-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -102,93 +101,112 @@ export default {
diff --git a/client/src/components/LanguageSwitcher.vue b/client/src/components/LanguageSwitcher.vue
index dde97df1..fbd81821 100644
--- a/client/src/components/LanguageSwitcher.vue
+++ b/client/src/components/LanguageSwitcher.vue
@@ -96,36 +96,40 @@ const selectLanguage = (locale) => {
.language-button {
display: flex;
align-items: center;
- gap: 0.5rem;
- padding: 0.5rem 0.875rem;
- background: white;
- border: 1px solid #e2e8f0;
- border-radius: 8px;
+ gap: 0.375rem;
+ padding: 0.4375rem 0.625rem;
+ background: transparent;
+ border: 1px solid transparent;
+ border-radius: var(--radius-md);
cursor: pointer;
- transition: all 0.2s ease;
+ transition: all 0.15s ease;
font-family: inherit;
- font-size: 0.875rem;
- color: #334155;
+ font-size: 0.8125rem;
+ color: var(--color-text-secondary);
}
.language-button:hover {
- background: #f8fafc;
- border-color: #cbd5e1;
+ background: var(--color-surface-alt);
+ color: var(--color-text-primary);
}
.globe-icon {
- color: #64748b;
+ color: var(--color-text-muted);
flex-shrink: 0;
+ width: 16px;
+ height: 16px;
}
.language-label {
- font-weight: 500;
+ font-weight: 600;
}
.chevron {
- color: #64748b;
+ color: var(--color-text-faint);
transition: transform 0.2s ease;
flex-shrink: 0;
+ width: 12px;
+ height: 12px;
}
.chevron-open {
@@ -137,12 +141,13 @@ const selectLanguage = (locale) => {
top: calc(100% + 0.5rem);
right: 0;
min-width: 160px;
- background: white;
- border: 1px solid #e2e8f0;
- border-radius: 10px;
- box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
+ background: var(--color-surface);
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-lg);
+ box-shadow: var(--shadow-lg);
z-index: 1000;
overflow: hidden;
+ padding: 0.25rem;
}
.dropdown-item {
@@ -151,25 +156,28 @@ const selectLanguage = (locale) => {
align-items: center;
justify-content: space-between;
gap: 0.75rem;
- padding: 0.75rem 1rem;
+ padding: 0.5rem 0.75rem;
background: none;
border: none;
+ border-radius: var(--radius-sm);
text-align: left;
cursor: pointer;
transition: background 0.15s ease;
font-family: inherit;
- font-size: 0.875rem;
+ font-size: 0.8125rem;
font-weight: 500;
- color: #334155;
+ color: var(--color-text-secondary);
}
.dropdown-item:hover {
- background: #f8fafc;
+ background: var(--color-surface-alt);
+ color: var(--color-text-primary);
}
.dropdown-item.active {
- background: #eff6ff;
- color: #2563eb;
+ background: var(--color-primary-soft);
+ color: var(--color-primary-text);
+ font-weight: 600;
}
.language-name {
@@ -177,7 +185,7 @@ const selectLanguage = (locale) => {
}
.check-icon {
- color: #2563eb;
+ color: var(--color-primary);
flex-shrink: 0;
}
diff --git a/client/src/components/ProfileDetailsModal.vue b/client/src/components/ProfileDetailsModal.vue
index 4896a602..ef538aeb 100644
--- a/client/src/components/ProfileDetailsModal.vue
+++ b/client/src/components/ProfileDetailsModal.vue
@@ -112,9 +112,10 @@ const formatDate = (dateString) => {
}
.modal-container {
- background: white;
+ background: #1e293b;
+ border: 1px solid #334155;
border-radius: 12px;
- box-shadow: 0 20px 50px rgba(0, 0, 0, 0.15);
+ box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
max-width: 600px;
width: 100%;
max-height: 90vh;
@@ -128,13 +129,13 @@ const formatDate = (dateString) => {
align-items: center;
justify-content: space-between;
padding: 1.5rem;
- border-bottom: 1px solid #e2e8f0;
+ border-bottom: 1px solid #334155;
}
.modal-title {
font-size: 1.25rem;
font-weight: 700;
- color: #0f172a;
+ color: #f1f5f9;
letter-spacing: -0.025em;
}
@@ -152,8 +153,8 @@ const formatDate = (dateString) => {
}
.close-button:hover {
- background: #f1f5f9;
- color: #0f172a;
+ background: #334155;
+ color: #f1f5f9;
}
.modal-body {
@@ -174,7 +175,7 @@ const formatDate = (dateString) => {
align-items: center;
gap: 0.75rem;
padding-bottom: 1.5rem;
- border-bottom: 1px solid #e2e8f0;
+ border-bottom: 1px solid #334155;
}
.avatar-xl {
@@ -189,19 +190,19 @@ const formatDate = (dateString) => {
font-weight: 700;
font-size: 2rem;
letter-spacing: 0.025em;
- box-shadow: 0 4px 12px rgba(37, 99, 235, 0.2);
+ box-shadow: 0 4px 20px rgba(37, 99, 235, 0.4);
}
.profile-name {
font-size: 1.5rem;
font-weight: 700;
- color: #0f172a;
+ color: #f1f5f9;
margin: 0;
}
.profile-job-title {
font-size: 1rem;
- color: #64748b;
+ color: #94a3b8;
margin: 0;
}
@@ -227,13 +228,13 @@ const formatDate = (dateString) => {
.info-value {
font-size: 0.938rem;
- color: #0f172a;
+ color: #cbd5e1;
font-weight: 500;
}
.modal-footer {
padding: 1.5rem;
- border-top: 1px solid #e2e8f0;
+ border-top: 1px solid #334155;
display: flex;
justify-content: flex-end;
gap: 0.75rem;
@@ -241,20 +242,20 @@ const formatDate = (dateString) => {
.btn-secondary {
padding: 0.625rem 1.25rem;
- background: #f1f5f9;
- border: 1px solid #e2e8f0;
+ background: #334155;
+ border: 1px solid #475569;
border-radius: 8px;
font-weight: 500;
font-size: 0.875rem;
- color: #334155;
+ color: #cbd5e1;
cursor: pointer;
transition: all 0.15s ease;
font-family: inherit;
}
.btn-secondary:hover {
- background: #e2e8f0;
- border-color: #cbd5e1;
+ background: #475569;
+ border-color: #64748b;
}
/* Modal transition animations */
diff --git a/client/src/components/ProfileMenu.vue b/client/src/components/ProfileMenu.vue
index 5706d24c..bc98d91a 100644
--- a/client/src/components/ProfileMenu.vue
+++ b/client/src/components/ProfileMenu.vue
@@ -123,26 +123,26 @@ const handleLogout = () => {
.profile-button {
display: flex;
align-items: center;
- gap: 0.625rem;
- padding: 0.5rem 0.875rem;
- background: white;
- border: 1px solid #e2e8f0;
- border-radius: 8px;
+ gap: 0.5rem;
+ padding: 0.25rem 0.625rem 0.25rem 0.25rem;
+ background: transparent;
+ border: 1px solid transparent;
+ border-radius: var(--radius-full);
cursor: pointer;
- transition: all 0.2s ease;
+ transition: all 0.15s ease;
font-family: inherit;
}
.profile-button:hover {
- background: #f8fafc;
- border-color: #cbd5e1;
+ background: var(--color-surface-alt);
+ border-color: var(--color-border);
}
.avatar {
- width: 32px;
- height: 32px;
+ width: 30px;
+ height: 30px;
border-radius: 50%;
- background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%);
+ background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-accent) 100%);
color: white;
display: flex;
align-items: center;
@@ -150,16 +150,22 @@ const handleLogout = () => {
font-weight: 600;
font-size: 0.75rem;
letter-spacing: 0.025em;
+ flex-shrink: 0;
+ box-shadow: var(--shadow-xs);
}
.profile-name {
- font-size: 0.875rem;
- font-weight: 500;
- color: #0f172a;
+ font-size: 0.8125rem;
+ font-weight: 600;
+ color: var(--color-text-primary);
+ max-width: 140px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
}
.chevron {
- color: #64748b;
+ color: var(--color-text-faint);
transition: transform 0.2s ease;
}
@@ -172,35 +178,39 @@ const handleLogout = () => {
top: calc(100% + 0.5rem);
right: 0;
min-width: 280px;
- background: white;
- border: 1px solid #e2e8f0;
- border-radius: 10px;
- box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
+ background: var(--color-surface);
+ border: 1px solid var(--color-border);
+ border-radius: var(--radius-lg);
+ box-shadow: var(--shadow-lg);
z-index: 1000;
overflow: hidden;
+ padding: 0.375rem;
}
.dropdown-header {
- padding: 1rem;
+ padding: 0.875rem;
display: flex;
- gap: 0.875rem;
+ gap: 0.75rem;
align-items: center;
- background: #f8fafc;
+ background: var(--color-surface-sunken);
+ border-radius: var(--radius-md);
+ margin-bottom: 0.375rem;
}
.avatar-large {
- width: 48px;
- height: 48px;
+ width: 44px;
+ height: 44px;
border-radius: 50%;
- background: linear-gradient(135deg, #2563eb 0%, #1e40af 100%);
+ background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-accent) 100%);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
- font-size: 1rem;
+ font-size: 0.9375rem;
letter-spacing: 0.025em;
flex-shrink: 0;
+ box-shadow: var(--shadow-sm);
}
.user-info {
@@ -210,14 +220,14 @@ const handleLogout = () => {
.user-name {
font-weight: 600;
- color: #0f172a;
- font-size: 0.938rem;
- margin-bottom: 0.25rem;
+ color: var(--color-text-primary);
+ font-size: 0.875rem;
+ margin-bottom: 2px;
}
.user-email {
- font-size: 0.813rem;
- color: #64748b;
+ font-size: 0.75rem;
+ color: var(--color-text-muted);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@@ -225,57 +235,68 @@ const handleLogout = () => {
.dropdown-divider {
height: 1px;
- background: #e2e8f0;
- margin: 0.5rem 0;
+ background: var(--color-border);
+ margin: 0.375rem -0.375rem;
}
.dropdown-item {
width: 100%;
display: flex;
align-items: center;
- gap: 0.75rem;
- padding: 0.75rem 1rem;
+ gap: 0.625rem;
+ padding: 0.5rem 0.75rem;
background: none;
border: none;
+ border-radius: var(--radius-sm);
text-align: left;
cursor: pointer;
transition: background 0.15s ease;
font-family: inherit;
- font-size: 0.875rem;
+ font-size: 0.8125rem;
font-weight: 500;
- color: #334155;
+ color: var(--color-text-secondary);
}
.dropdown-item:hover {
- background: #f8fafc;
+ background: var(--color-surface-alt);
+ color: var(--color-text-primary);
}
.dropdown-item svg {
- color: #64748b;
+ color: var(--color-text-muted);
flex-shrink: 0;
}
.dropdown-item.logout {
- color: #dc2626;
+ color: var(--color-error-text);
}
.dropdown-item.logout svg {
- color: #dc2626;
+ color: var(--color-error);
}
.dropdown-item.logout:hover {
- background: #fef2f2;
+ background: var(--color-error-soft);
}
.task-badge {
margin-left: auto;
- background: #2563eb;
+ background: var(--color-primary);
color: white;
- font-size: 0.75rem;
- font-weight: 600;
- padding: 0.125rem 0.5rem;
- border-radius: 12px;
- min-width: 20px;
+ font-size: 0.6875rem;
+ font-weight: 700;
+ padding: 0.125rem 0.4375rem;
+ border-radius: var(--radius-full);
+ min-width: 18px;
text-align: center;
}
+
+@media (max-width: 640px) {
+ .profile-name {
+ display: none;
+ }
+ .chevron {
+ display: none;
+ }
+}
diff --git a/client/src/components/Sidebar.vue b/client/src/components/Sidebar.vue
new file mode 100644
index 00000000..9b638136
--- /dev/null
+++ b/client/src/components/Sidebar.vue
@@ -0,0 +1,340 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/client/src/components/SidebarItem.vue b/client/src/components/SidebarItem.vue
new file mode 100644
index 00000000..38bb7bce
--- /dev/null
+++ b/client/src/components/SidebarItem.vue
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
diff --git a/client/src/components/TopHeader.vue b/client/src/components/TopHeader.vue
new file mode 100644
index 00000000..9d59085e
--- /dev/null
+++ b/client/src/components/TopHeader.vue
@@ -0,0 +1,269 @@
+
+
+
+
+
+
+
diff --git a/client/src/locales/en.js b/client/src/locales/en.js
index 03a58fe6..0ce7d834 100644
--- a/client/src/locales/en.js
+++ b/client/src/locales/en.js
@@ -6,6 +6,7 @@ export default {
orders: 'Orders',
finance: 'Finance',
demandForecast: 'Demand Forecast',
+ analytics: 'Analytics',
companyName: 'Catalyst Components',
subtitle: 'Inventory Management System'
},
diff --git a/client/src/locales/ja.js b/client/src/locales/ja.js
index db33223a..bfa8aefd 100644
--- a/client/src/locales/ja.js
+++ b/client/src/locales/ja.js
@@ -6,6 +6,7 @@ export default {
orders: 'ๆณจๆ',
finance: '่ฒกๅ',
demandForecast: '้่ฆไบๆธฌ',
+ analytics: 'ใขใใชใใฃใฏใน',
companyName: '่งฆๅชใณใณใใผใใณใ',
subtitle: 'ๅจๅบซ็ฎก็ใทในใใ '
},
diff --git a/client/src/views/Dashboard.vue b/client/src/views/Dashboard.vue
index 437da9c2..4c0f7b9b 100644
--- a/client/src/views/Dashboard.vue
+++ b/client/src/views/Dashboard.vue
@@ -4,6 +4,8 @@
{{ t('dashboard.title') }}
@@ -304,12 +306,14 @@ import { useI18n } from '../composables/useI18n'
import { formatCurrency } from '../utils/currency'
import ProductDetailModal from '../components/ProductDetailModal.vue'
import BacklogDetailModal from '../components/BacklogDetailModal.vue'
+import FilterBar from '../components/FilterBar.vue'
export default {
name: 'Dashboard',
components: {
ProductDetailModal,
BacklogDetailModal,
+ FilterBar,
},
setup() {
const { t, currentCurrency, translateProductName, translateWarehouse } = useI18n()
diff --git a/client/src/views/Demand.vue b/client/src/views/Demand.vue
index 2cdf01a6..9c46abb6 100644
--- a/client/src/views/Demand.vue
+++ b/client/src/views/Demand.vue
@@ -5,6 +5,8 @@
{{ t('demand.description') }}
@@ -83,9 +85,11 @@ import { ref, onMounted, watch, computed } from 'vue'
import { api } from '../api'
import { useFilters } from '../composables/useFilters'
import { useI18n } from '../composables/useI18n'
+import FilterBar from '../components/FilterBar.vue'
export default {
name: 'Orders',
+ components: { FilterBar },
setup() {
const { t, currentCurrency, translateProductName, translateCustomerName } = useI18n()
diff --git a/client/src/views/Spending.vue b/client/src/views/Spending.vue
index 17af4d10..376ea5a5 100644
--- a/client/src/views/Spending.vue
+++ b/client/src/views/Spending.vue
@@ -5,6 +5,8 @@
{{ t('finance.description') }}
@@ -178,11 +180,13 @@ import { useFilters } from '../composables/useFilters'
import { useI18n } from '../composables/useI18n'
import { formatCurrency as formatCurrencyUtil } from '../utils/currency'
import CostDetailModal from '../components/CostDetailModal.vue'
+import FilterBar from '../components/FilterBar.vue'
export default {
name: 'Spending',
components: {
- CostDetailModal
+ CostDetailModal,
+ FilterBar
},
setup() {
const { t, currentCurrency } = useI18n()