diff --git a/app/assets/css/main.css b/app/assets/css/main.css index 4c488385..7e7f0b70 100644 --- a/app/assets/css/main.css +++ b/app/assets/css/main.css @@ -67,41 +67,43 @@ --sidebar-accent-foreground: 240 5.9% 10%; --sidebar-border: 220 13% 91%; --sidebar-ring: 217.2 91.2% 59.8%; - /* .dark { */ - /* --background: 210 25% 8%; */ - /* --foreground: 210 20% 95%; */ - /* --card: 210 25% 10%; */ - /* --card-foreground: 210 20% 95%; */ - /* --popover: 210 25% 10%; */ - /* --popover-foreground: 210 20% 95%; */ - /* --primary: 150 75% 45%; */ - /* --primary-foreground: 0 0% 100%; */ - /* --primary-hover: 150 75% 50%; */ - /* --secondary: 210 25% 15%; */ - /* --secondary-foreground: 210 20% 90%; */ - /* --muted: 210 25% 15%; */ - /* --muted-foreground: 210 15% 65%; */ - /* --accent: 210 100% 55%; */ - /* --accent-foreground: 0 0% 100%; */ - /* --destructive: 0 75% 60%; */ - /* --destructive-foreground: 0 0% 100%; */ - /* --border: 210 25% 20%; */ - /* --input: 210 25% 15%; */ - /* --ring: 150 75% 45%; */ - /* --success: 150 75% 50%; */ - /* --warning: 45 95% 65%; */ - /* --info: 210 100% 60%; */ - /* --gradient-primary: linear-gradient(135deg, hsl(150 75% 45%), hsl(150 75% 55%)); */ - /* --gradient-medical: linear-gradient(135deg, hsl(150 75% 45%), hsl(210 100% 55%)); */ - /* --gradient-subtle: linear-gradient(180deg, hsl(210 25% 8%), hsl(210 25% 12%)); */ - /* --sidebar-background: 240 5.9% 10%; */ - /* --sidebar-foreground: 240 4.8% 95.9%; */ - /* --sidebar-primary: 224.3 76.3% 48%; */ - /* --sidebar-primary-foreground: 0 0% 100%; */ - /* --sidebar-accent: 240 3.7% 15.9%; */ - /* --sidebar-accent-foreground: 240 4.8% 95.9%; */ - /* --sidebar-border: 240 3.7% 15.9%; */ - /* --sidebar-ring: 217.2 91.2% 59.8%; */ +} + +.dark { + --background: 210 25% 8%; + --foreground: 210 20% 95%; + --card: 210 25% 10%; + --card-foreground: 210 20% 95%; + --popover: 210 25% 10%; + --popover-foreground: 210 20% 95%; + --primary: 150 75% 45%; + --primary-foreground: 0 0% 100%; + --primary-hover: 150 75% 50%; + --secondary: 210 25% 15%; + --secondary-foreground: 210 20% 90%; + --muted: 210 25% 15%; + --muted-foreground: 210 15% 65%; + --accent: 210 100% 55%; + --accent-foreground: 0 0% 100%; + --destructive: 0 75% 60%; + --destructive-foreground: 0 0% 100%; + --border: 210 25% 20%; + --input: 210 25% 15%; + --ring: 150 75% 45%; + --success: 150 75% 50%; + --warning: 45 95% 65%; + --info: 210 100% 60%; + --gradient-primary: linear-gradient(135deg, hsl(150 75% 45%), hsl(150 75% 55%)); + --gradient-medical: linear-gradient(135deg, hsl(150 75% 45%), hsl(210 100% 55%)); + --gradient-subtle: linear-gradient(180deg, hsl(210 25% 8%), hsl(210 25% 12%)); + --sidebar-background: 240 5.9% 10%; + --sidebar-foreground: 240 4.8% 95.9%; + --sidebar-primary: 224.3 76.3% 48%; + --sidebar-primary-foreground: 0 0% 100%; + --sidebar-accent: 240 3.7% 15.9%; + --sidebar-accent-foreground: 240 4.8% 95.9%; + --sidebar-border: 240 3.7% 15.9%; + --sidebar-ring: 217.2 91.2% 59.8%; } /* Keyframes for Animations */ @@ -330,7 +332,8 @@ body { /* Form Error Styling */ .field-error-info { - @apply text-xs ml-1; + font-size: 0.75rem; + margin-left: 0.25rem; color: hsl(var(--destructive)); /* font-size: 0.875rem; */ margin-top: 0.25rem; @@ -338,3 +341,28 @@ body { } /* .rounded-md { border-radius: var */ + +/* Dashboard grid utility */ +.dashboard-grid { + display: grid; + gap: 1rem; +} + +@media (min-width: 768px) { + .dashboard-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (min-width: 1024px) { + .dashboard-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} + +@media (min-width: 1280px) { + .dashboard-grid { + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 1.25rem; + } +} \ No newline at end of file diff --git a/app/components/content/dashboard/index.vue b/app/components/content/dashboard/index.vue index 2195b428..71167dac 100644 --- a/app/components/content/dashboard/index.vue +++ b/app/components/content/dashboard/index.vue @@ -113,7 +113,7 @@ onMounted(() => {

Dashboard SIMRS

-
Status: Aktif
+
Status: Aktif
-
+
-
+
Recent Sales @@ -143,7 +143,7 @@ onMounted(() => {

{{ recentSales.name }}

-

+

{{ recentSales.email }}

@@ -156,19 +156,19 @@ onMounted(() => {
- +

Aksi Cepat

- + + v-for="item in linkItems" + :key="item.title" + class="my-2 h-32 border border-primary transition-colors duration-200 hover:bg-gray-200 hover:bg-primary" + > - +

{{ item.title }}

diff --git a/app/components/layout/Header.vue b/app/components/layout/Header.vue index 19c87540..612524ef 100644 --- a/app/components/layout/Header.vue +++ b/app/components/layout/Header.vue @@ -1,4 +1,6 @@ + + diff --git a/app/composables/useTheme.ts b/app/composables/useTheme.ts new file mode 100644 index 00000000..f028d4c6 --- /dev/null +++ b/app/composables/useTheme.ts @@ -0,0 +1,31 @@ +import { ref, watchEffect } from 'vue' + +const THEME_KEY = 'theme-mode' + +export function useTheme() { + const theme = ref<'light' | 'dark'>(getInitialTheme()) + + function getInitialTheme() { + if (typeof window === 'undefined') return 'light' + const persisted = localStorage.getItem(THEME_KEY) + if (persisted === 'dark' || persisted === 'light') return persisted + // fallback: system preference + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' + } + + function setTheme(newTheme: 'light' | 'dark') { + theme.value = newTheme + localStorage.setItem(THEME_KEY, newTheme) + document.documentElement.classList.toggle('dark', newTheme === 'dark') + } + + function toggleTheme() { + setTheme(theme.value === 'dark' ? 'light' : 'dark') + } + + watchEffect(() => { + setTheme(theme.value) + }) + + return { theme, toggleTheme } +} diff --git a/app/layouts/default.vue b/app/layouts/default.vue index 7f5959b7..1f62236f 100644 --- a/app/layouts/default.vue +++ b/app/layouts/default.vue @@ -45,6 +45,8 @@ const contentContent = computed(() => { margin-right: auto; border-radius: 0.375rem; padding-bottom: 5rem; + padding-left: 1rem; + padding-right: 1rem; } .cf-container > *, @@ -56,9 +58,9 @@ const contentContent = computed(() => { margin-right: auto; padding: 0.75rem; /* p-3 */ padding-bottom: 5rem; /* pb-20 */ - border-width: 1px; - background-color: white !important; + background-color: hsl(var(--background)); border-radius: 0.375rem; + border: 1px solid hsl(var(--border)); border-color: rgb(226 232 240); /* slate-200 */ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } @@ -78,18 +80,58 @@ const contentContent = computed(() => { .cf-frame-width { margin-left: auto; margin-right: auto; - background-color: white; - border: 1px solid rgb(226 232 240); + background-color: hsl(var(--background)); border-radius: 0.375rem; + border: 1px solid hsl(var(--border)); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + max-width: 100%; + padding: 1rem; } + .cf-frame { margin-left: auto; margin-right: auto; - padding: 0.75rem; - background-color: white; + padding: 1rem; + background-color: hsl(var(--background)); border-radius: 0.375rem; - border: 1px solid rgb(226 232 240); + border: 1px solid hsl(var(--border)); box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + max-width: 100%; +} + +@media (min-width: 640px) { + .cf-container, + .cf-container-lg, + .cf-container-md, + .cf-container-sm { + padding-left: 2rem; + padding-right: 2rem; + } + + .cf-frame { + padding: 2rem; + } + + .cf-frame-width { + padding: 2rem; + } +} + +@media (min-width: 1024px) { + .cf-container, + .cf-container-lg, + .cf-container-md, + .cf-container-sm { + padding-left: 3rem; + padding-right: 3rem; + } + + .cf-frame { + padding: 3rem; + } + + .cf-frame-width { + padding: 3rem; + } }