Created
August 10, 2025 03:15
-
-
Save naranyala/4c97858b6eb736eae0f99631af85860f to your computer and use it in GitHub Desktop.
the only one dashboard layout you need, of course mobile-friendly
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Minimal Dashboard</title> | |
<link rel="stylesheet" href="https://unpkg.com/open-props" /> | |
<link rel="stylesheet" href="https://unpkg.com/open-props/normalize.min.css" /> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<style> | |
[v-cloak] { | |
display: none; | |
} | |
body { | |
font-family: var(--font-sans); | |
background: var(--gray-1); | |
color: var(--gray-9); | |
} | |
.dashboard { | |
display: grid; | |
grid-template-columns: 240px 1fr 280px; | |
min-height: 100vh; | |
gap: 0; | |
} | |
.sidebar, | |
.right-sidebar { | |
background: white; | |
padding: var(--size-4); | |
border-right: 1px solid var(--gray-3); | |
overflow-y: auto; | |
} | |
.right-sidebar { | |
border-right: none; | |
border-left: 1px solid var(--gray-3); | |
} | |
.sidebar h2, | |
.right-sidebar h2 { | |
font-size: var(--font-size-3); | |
margin-bottom: var(--size-4); | |
color: var(--gray-9); | |
font-weight: var(--font-weight-6); | |
} | |
.menu-list { | |
list-style: none; | |
padding: 0; | |
margin: 0; | |
} | |
.menu-item { | |
margin-bottom: var(--size-2); | |
} | |
.menu-link { | |
display: flex; | |
align-items: center; | |
gap: var(--size-3); | |
padding: var(--size-3); | |
text-decoration: none; | |
color: var(--gray-7); | |
border-radius: var(--radius-2); | |
transition: all 0.2s ease; | |
cursor: pointer; | |
} | |
.menu-link:hover { | |
background: var(--gray-2); | |
color: var(--gray-9); | |
} | |
.menu-link.active { | |
background: var(--indigo-9); | |
color: white; | |
} | |
.main-content { | |
padding: var(--size-5); | |
background: var(--gray-1); | |
} | |
.main-content h1 { | |
font-size: var(--font-size-5); | |
margin-bottom: var(--size-4); | |
font-weight: var(--font-weight-6); | |
} | |
.card { | |
background: white; | |
border-radius: var(--radius-3); | |
padding: var(--size-4); | |
box-shadow: var(--shadow-2); | |
margin-bottom: var(--size-4); | |
} | |
.stats-grid { | |
display: grid; | |
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); | |
gap: var(--size-4); | |
margin-bottom: var(--size-4); | |
} | |
.stat-card { | |
display: flex; | |
align-items: center; | |
gap: var(--size-4); | |
} | |
.stat-icon { | |
font-size: var(--font-size-6); | |
color: var(--indigo-9); | |
} | |
.stat-value { | |
font-size: var(--font-size-5); | |
font-weight: var(--font-weight-7); | |
line-height: 1; | |
} | |
.stat-label { | |
color: var(--gray-6); | |
font-size: var(--font-size-1); | |
} | |
.activity-item, | |
.notification-item { | |
padding: var(--size-3) 0; | |
border-bottom: 1px solid var(--gray-2); | |
display: flex; | |
gap: var(--size-3); | |
} | |
.activity-icon, | |
.notification-icon { | |
color: var(--indigo-9); | |
min-width: 20px; | |
} | |
.activity-time { | |
font-size: var(--font-size-0); | |
color: var(--gray-6); | |
margin-top: var(--size-1); | |
} | |
/* Mobile Header */ | |
.mobile-header { | |
display: none; | |
position: fixed; | |
top: 0; | |
left: 0; | |
right: 0; | |
height: 60px; | |
background: white; | |
border-bottom: 1px solid var(--gray-3); | |
z-index: 200; | |
padding: 0 var(--size-4); | |
align-items: center; | |
justify-content: space-between; | |
} | |
.mobile-header .brand { | |
font-weight: var(--font-weight-6); | |
font-size: var(--font-size-3); | |
} | |
.mobile-header .actions { | |
display: flex; | |
gap: var(--size-2); | |
} | |
.btn { | |
background: var(--gray-2); | |
border: none; | |
padding: var(--size-2); | |
border-radius: var(--radius-2); | |
cursor: pointer; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
width: 40px; | |
height: 40px; | |
} | |
.btn:hover { | |
background: var(--gray-3); | |
} | |
/* Mobile Backdrop */ | |
.mobile-backdrop { | |
position: fixed; | |
top: 0; | |
left: 0; | |
right: 0; | |
bottom: 0; | |
background: rgba(0, 0, 0, 0.5); | |
z-index: 150; | |
display: none; | |
} | |
.mobile-backdrop.active { | |
display: block; | |
} | |
@media (max-width: 1024px) { | |
.mobile-header { | |
display: flex; | |
} | |
.dashboard { | |
grid-template-columns: 1fr; | |
} | |
.sidebar, | |
.right-sidebar { | |
position: fixed; | |
top: 0; | |
height: 100vh; | |
z-index: 180; | |
transform: translateX(-100%); | |
transition: transform 0.3s ease; | |
width: 280px; | |
} | |
.right-sidebar { | |
right: 0; | |
left: auto; | |
transform: translateX(100%); | |
} | |
.sidebar.active { | |
transform: translateX(0); | |
} | |
.right-sidebar.active { | |
transform: translateX(0); | |
} | |
.main-content { | |
padding-top: calc(60px + var(--size-4)); | |
} | |
} | |
</style> | |
</head> | |
<body> | |
<div id="app" v-cloak> | |
<!-- Mobile Header --> | |
<header class="mobile-header"> | |
<div class="brand">Dashboard</div> | |
<div class="actions"> | |
<button @click="toggleLeftSidebar" class="btn"> | |
<i class="fas fa-bars"></i> | |
</button> | |
<button @click="toggleRightSidebar" class="btn"> | |
<i class="fas fa-bell"></i> | |
</button> | |
</div> | |
</header> | |
<!-- Mobile Backdrop --> | |
<div class="mobile-backdrop" :class="{ active: showMobileBackdrop }" @click="closeMobileSidebars"></div> | |
<div class="dashboard"> | |
<!-- Left Sidebar --> | |
<aside class="sidebar" :class="{ active: leftSidebarActive }"> | |
<h2>Dashboard</h2> | |
<nav> | |
<ul class="menu-list"> | |
<li class="menu-item"> | |
<a class="menu-link" :class="{active: activeTab === 'dashboard'}" @click="setActiveTab('dashboard')"> | |
<i class="fas fa-tachometer-alt"></i> | |
<span>Dashboard</span> | |
</a> | |
</li> | |
<li class="menu-item"> | |
<a class="menu-link" :class="{active: activeTab === 'analytics'}" @click="setActiveTab('analytics')"> | |
<i class="fas fa-chart-line"></i> | |
<span>Analytics</span> | |
</a> | |
</li> | |
<li class="menu-item"> | |
<a class="menu-link" :class="{active: activeTab === 'users'}" @click="setActiveTab('users')"> | |
<i class="fas fa-users"></i> | |
<span>Users</span> | |
</a> | |
</li> | |
<li class="menu-item"> | |
<a class="menu-link" :class="{active: activeTab === 'orders'}" @click="setActiveTab('orders')"> | |
<i class="fas fa-shopping-cart"></i> | |
<span>Orders</span> | |
</a> | |
</li> | |
</ul> | |
</nav> | |
</aside> | |
<!-- Main Content --> | |
<main class="main-content"> | |
<h1>{{getTabLabel(activeTab)}}</h1> | |
<!-- Dashboard Content --> | |
<div v-if="activeTab === 'dashboard'"> | |
<div class="stats-grid"> | |
<div class="card stat-card"> | |
<div class="stat-icon"><i class="fas fa-users"></i></div> | |
<div> | |
<div class="stat-value">{{stats.users}}</div> | |
<div class="stat-label">Total Users</div> | |
</div> | |
</div> | |
<div class="card stat-card"> | |
<div class="stat-icon"><i class="fas fa-shopping-cart"></i></div> | |
<div> | |
<div class="stat-value">{{stats.orders}}</div> | |
<div class="stat-label">New Orders</div> | |
</div> | |
</div> | |
<div class="card stat-card"> | |
<div class="stat-icon"><i class="fas fa-boxes"></i></div> | |
<div> | |
<div class="stat-value">{{stats.products}}</div> | |
<div class="stat-label">Products</div> | |
</div> | |
</div> | |
</div> | |
<div class="card"> | |
<h3>Recent Activity</h3> | |
<div v-for="activity in recentActivities" :key="activity.id" class="activity-item"> | |
<div class="activity-icon"> | |
<i :class="activity.icon"></i> | |
</div> | |
<div> | |
<div><strong>{{activity.user}}</strong> {{activity.action}}</div> | |
<div class="activity-time">{{activity.time}}</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Other Tabs --> | |
<div v-else> | |
<div class="card"> | |
<p>{{getTabLabel(activeTab)}} content goes here</p> | |
</div> | |
</div> | |
</main> | |
<!-- Right Sidebar --> | |
<aside class="right-sidebar" :class="{ active: rightSidebarActive }"> | |
<h2>Notifications</h2> | |
<div v-for="notification in notifications" :key="notification.id" class="notification-item"> | |
<div class="notification-icon"> | |
<i :class="notification.icon"></i> | |
</div> | |
<div> | |
<div>{{notification.message}}</div> | |
<div class="activity-time">{{notification.time}}</div> | |
</div> | |
</div> | |
<div v-if="notifications.length === 0" style="text-align: center; padding: var(--size-4);"> | |
<p style="color: var(--gray-6);">No new notifications</p> | |
</div> | |
</aside> | |
</div> | |
</div> | |
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script> | |
<script> | |
const {createApp, ref, computed} = Vue; | |
createApp({ | |
setup() { | |
const activeTab = ref('dashboard'); | |
const leftSidebarActive = ref(false); | |
const rightSidebarActive = ref(false); | |
const stats = ref({ | |
users: 1245, | |
orders: 48, | |
products: 326 | |
}); | |
const recentActivities = ref([ | |
{ | |
id: 1, | |
user: 'Jane Smith', | |
action: 'placed a new order (#1234)', | |
time: '10 minutes ago', | |
icon: 'fas fa-shopping-cart' | |
}, | |
{ | |
id: 2, | |
user: 'Mike Johnson', | |
action: 'updated product details', | |
time: '25 minutes ago', | |
icon: 'fas fa-box' | |
}, | |
{ | |
id: 3, | |
user: 'Sarah Williams', | |
action: 'registered as a new user', | |
time: '1 hour ago', | |
icon: 'fas fa-user-plus' | |
} | |
]); | |
const notifications = ref([ | |
{ | |
id: 1, | |
message: 'New user registered', | |
time: '15 minutes ago', | |
icon: 'fas fa-user-plus' | |
}, | |
{ | |
id: 2, | |
message: 'Order #1234 completed', | |
time: '1 hour ago', | |
icon: 'fas fa-check-circle' | |
}, | |
{ | |
id: 3, | |
message: 'System maintenance scheduled', | |
time: '3 hours ago', | |
icon: 'fas fa-tools' | |
} | |
]); | |
const getTabLabel = (tab) => { | |
const labels = { | |
dashboard: 'Dashboard Overview', | |
analytics: 'Analytics', | |
users: 'User Management', | |
orders: 'Order Management' | |
}; | |
return labels[tab] || tab.charAt(0).toUpperCase() + tab.slice(1); | |
}; | |
const showMobileBackdrop = computed(() => { | |
return leftSidebarActive.value || rightSidebarActive.value; | |
}); | |
const toggleLeftSidebar = () => { | |
leftSidebarActive.value = !leftSidebarActive.value; | |
if (leftSidebarActive.value) { | |
rightSidebarActive.value = false; | |
} | |
}; | |
const toggleRightSidebar = () => { | |
rightSidebarActive.value = !rightSidebarActive.value; | |
if (rightSidebarActive.value) { | |
leftSidebarActive.value = false; | |
} | |
}; | |
const closeMobileSidebars = () => { | |
leftSidebarActive.value = false; | |
rightSidebarActive.value = false; | |
}; | |
const setActiveTab = (tab) => { | |
activeTab.value = tab; | |
closeMobileSidebars(); | |
}; | |
return { | |
activeTab, | |
leftSidebarActive, | |
rightSidebarActive, | |
showMobileBackdrop, | |
stats, | |
recentActivities, | |
notifications, | |
getTabLabel, | |
toggleLeftSidebar, | |
toggleRightSidebar, | |
closeMobileSidebars, | |
setActiveTab | |
}; | |
} | |
}).mount('#app'); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment