UI Phenikaa
This commit is contained in:
17
web-server/package-lock.json
generated
17
web-server/package-lock.json
generated
@@ -8,6 +8,8 @@
|
||||
"name": "robot-installer-web-server",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@fluentui/svg-icons": "^1.1.333",
|
||||
"@fontsource-variable/montserrat": "^5.3.0",
|
||||
"dotenv": "^17.4.2",
|
||||
"ejs": "^3.1.10",
|
||||
"express": "^4.19.2",
|
||||
@@ -276,6 +278,21 @@
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@fluentui/svg-icons": {
|
||||
"version": "1.1.333",
|
||||
"resolved": "https://registry.npmjs.org/@fluentui/svg-icons/-/svg-icons-1.1.333.tgz",
|
||||
"integrity": "sha512-uSFMDQq25/sVgHvD9KhP+c1rZrHWqIA0OZkofu9Ii3Q5b72DqLgqOreABHbPD67U5XfsFc4iPlZzWEl1849Obg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@fontsource-variable/montserrat": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@fontsource-variable/montserrat/-/montserrat-5.3.0.tgz",
|
||||
"integrity": "sha512-7PaZoxaxrWLAyrhO46v65An9LhUhfkTExWLhfbywYZCnZEgg/W1rEHnlNmZKjNZ3nJTVYyicqxlJt10z/26yTA==",
|
||||
"license": "OFL-1.1",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ayuhito"
|
||||
}
|
||||
},
|
||||
"node_modules/@js-joda/core": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@js-joda/core/-/core-5.7.0.tgz",
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
"dev": "node server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluentui/svg-icons": "^1.1.333",
|
||||
"@fontsource-variable/montserrat": "^5.3.0",
|
||||
"dotenv": "^17.4.2",
|
||||
"ejs": "^3.1.10",
|
||||
"express": "^4.19.2",
|
||||
|
||||
@@ -1,28 +1,92 @@
|
||||
:root {
|
||||
--primary: #3755c3;
|
||||
--primary-dim: #2848b7;
|
||||
--primary-container: #dde1ff;
|
||||
--on-primary: #f8f7ff;
|
||||
--background: #f7f9fb;
|
||||
--surface-lowest: #ffffff;
|
||||
--surface-low: #f0f4f7;
|
||||
--surface: #e8eff3;
|
||||
--surface-high: #e1e9ee;
|
||||
--on-surface: #2a3439;
|
||||
--on-surface-variant: #566166;
|
||||
--outline: #717c82;
|
||||
--outline-variant: #a9b4b9;
|
||||
--danger: #b42318;
|
||||
--danger-bg: #fee4e2;
|
||||
--success: #067647;
|
||||
--success-bg: #dcfae6;
|
||||
--warning: #b54708;
|
||||
--warning-bg: #fef0c7;
|
||||
--info: #175cd3;
|
||||
--info-bg: #d1e9ff;
|
||||
--radius: 8px;
|
||||
--shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
|
||||
--shadow-lg: 0 24px 60px rgba(15, 23, 42, 0.18);
|
||||
color-scheme: light;
|
||||
|
||||
/* Phenikaa-X universal tokens — design-language.md v0.4.4 */
|
||||
--blue-50: #eaedf5;
|
||||
--blue-100: #c5cce0;
|
||||
--blue-200: #8c9ac4;
|
||||
--blue-300: #6e7ca8;
|
||||
--blue-500: #223771;
|
||||
--blue-700: #1a2a57;
|
||||
--blue-900: #1e2243;
|
||||
--orange-100: #fcd9c4;
|
||||
--orange-300: #f58220;
|
||||
--orange-500: #f26522;
|
||||
--orange-700: #c44e14;
|
||||
--neutral-0: #ffffff;
|
||||
--neutral-50: #f7f8fb;
|
||||
--neutral-100: #eeedf6;
|
||||
--neutral-200: #dddfea;
|
||||
--neutral-300: #c5c8d8;
|
||||
--neutral-400: #9fa3b8;
|
||||
--neutral-450: #8c90a8;
|
||||
--neutral-500: #757a91;
|
||||
--neutral-600: #565b70;
|
||||
--neutral-700: #3c4054;
|
||||
--neutral-800: #272a3a;
|
||||
--neutral-900: #161824;
|
||||
|
||||
--surface-base: var(--neutral-0);
|
||||
--surface-raised: var(--neutral-50);
|
||||
--surface-brand-tint: var(--neutral-100);
|
||||
--text-primary: var(--neutral-900);
|
||||
--text-secondary: var(--neutral-600);
|
||||
--text-tertiary: var(--neutral-500);
|
||||
--border-subtle: var(--neutral-300);
|
||||
--border-strong: var(--neutral-450);
|
||||
--brand-primary: var(--blue-500);
|
||||
--brand-primary-strong: var(--blue-700);
|
||||
--brand-accent: var(--orange-500);
|
||||
--brand-accent-strong: var(--orange-700);
|
||||
|
||||
--semantic-success: #2e7d32;
|
||||
--semantic-success-bg: #e8f5e9;
|
||||
--semantic-warning: #9a5b00;
|
||||
--semantic-warning-icon: #cb6119;
|
||||
--semantic-warning-bg: #fff4db;
|
||||
--semantic-error: #c62828;
|
||||
--semantic-error-bg: #ffebee;
|
||||
--semantic-info: #1565c0;
|
||||
--semantic-info-bg: #e7f1fc;
|
||||
|
||||
--space-xxs: 4px;
|
||||
--space-xs: 8px;
|
||||
--space-sm: 12px;
|
||||
--space-md: 16px;
|
||||
--space-lg: 24px;
|
||||
--space-xl: 32px;
|
||||
--space-2xl: 48px;
|
||||
--radius-sm: 2px;
|
||||
--radius-md: 4px;
|
||||
--radius-lg: 8px;
|
||||
--elevation-1: 0 1px 3px rgba(22, 24, 36, 0.12);
|
||||
--elevation-2: 0 4px 12px rgba(22, 24, 36, 0.18);
|
||||
|
||||
/* Compatibility aliases used by the existing components. */
|
||||
--primary: var(--brand-primary);
|
||||
--primary-dim: var(--brand-primary-strong);
|
||||
--primary-container: var(--blue-50);
|
||||
--on-primary: var(--neutral-0);
|
||||
--background: var(--surface-raised);
|
||||
--surface-lowest: var(--surface-base);
|
||||
--surface-low: var(--surface-raised);
|
||||
--surface: var(--surface-brand-tint);
|
||||
--surface-high: var(--neutral-200);
|
||||
--on-surface: var(--text-primary);
|
||||
--on-surface-variant: var(--text-secondary);
|
||||
--outline: var(--border-strong);
|
||||
--outline-variant: var(--border-subtle);
|
||||
--danger: var(--semantic-error);
|
||||
--danger-bg: var(--semantic-error-bg);
|
||||
--success: var(--semantic-success);
|
||||
--success-bg: var(--semantic-success-bg);
|
||||
--warning: var(--semantic-warning);
|
||||
--warning-bg: var(--semantic-warning-bg);
|
||||
--info: var(--semantic-info);
|
||||
--info-bg: var(--semantic-info-bg);
|
||||
--radius: var(--radius-md);
|
||||
--shadow-sm: var(--elevation-1);
|
||||
--shadow-lg: var(--elevation-2);
|
||||
}
|
||||
|
||||
* {
|
||||
@@ -39,8 +103,9 @@ body {
|
||||
margin: 0;
|
||||
background: var(--background);
|
||||
color: var(--on-surface);
|
||||
font-family: "Inter", Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
font-family: "Montserrat Variable", Montserrat, "Segoe UI", sans-serif;
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -48,7 +113,7 @@ h1,
|
||||
h2,
|
||||
h3,
|
||||
.brand-copy strong {
|
||||
font-family: "Manrope", Arial, sans-serif;
|
||||
font-family: "Montserrat Variable", Montserrat, "Segoe UI", sans-serif;
|
||||
}
|
||||
|
||||
h1,
|
||||
@@ -79,17 +144,13 @@ button:disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.material-symbols-outlined {
|
||||
direction: ltr;
|
||||
.fluent-icon {
|
||||
background: currentColor;
|
||||
display: inline-flex;
|
||||
font-family: "Material Symbols Outlined";
|
||||
font-size: 1.25rem;
|
||||
font-style: normal;
|
||||
font-variation-settings: "FILL" 0, "wght" 400, "GRAD" 0, "opsz" 20;
|
||||
letter-spacing: 0;
|
||||
line-height: 1;
|
||||
text-transform: none;
|
||||
white-space: nowrap;
|
||||
flex: 0 0 auto;
|
||||
height: 1.25rem;
|
||||
mask: var(--fluent-icon-url) center / contain no-repeat;
|
||||
width: 1.25rem;
|
||||
}
|
||||
|
||||
.app-shell {
|
||||
@@ -304,7 +365,7 @@ button:disabled {
|
||||
|
||||
.notification-panel-header strong {
|
||||
color: #111827;
|
||||
font-family: "Manrope", Arial, sans-serif;
|
||||
font-family: "Montserrat Variable", Montserrat, "Segoe UI", sans-serif;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
@@ -394,8 +455,10 @@ button:disabled {
|
||||
width: 34px;
|
||||
}
|
||||
|
||||
.notification-item-icon .material-symbols-outlined {
|
||||
font-size: 19px;
|
||||
.notification-item-icon .material-symbols-outlined,
|
||||
.notification-item-icon .fluent-icon {
|
||||
height: 19px;
|
||||
width: 19px;
|
||||
}
|
||||
|
||||
.notification-item.tone-success .notification-item-icon {
|
||||
@@ -468,9 +531,11 @@ button:disabled {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.notification-empty .material-symbols-outlined {
|
||||
.notification-empty .material-symbols-outlined,
|
||||
.notification-empty .fluent-icon {
|
||||
color: #94a3b8;
|
||||
font-size: 32px;
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
}
|
||||
|
||||
.notification-empty strong {
|
||||
@@ -705,7 +770,7 @@ button:disabled {
|
||||
|
||||
.metric-card strong {
|
||||
color: #111827;
|
||||
font-family: "Manrope", Arial, sans-serif;
|
||||
font-family: "Montserrat Variable", Montserrat, "Segoe UI", sans-serif;
|
||||
font-size: 28px;
|
||||
font-weight: 800;
|
||||
}
|
||||
@@ -1208,9 +1273,11 @@ tbody tr:hover td.action-col {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.file-dropzone-content > .material-symbols-outlined {
|
||||
.file-dropzone-content > .material-symbols-outlined,
|
||||
.file-dropzone-content > .fluent-icon {
|
||||
color: var(--primary);
|
||||
font-size: 34px;
|
||||
height: 34px;
|
||||
width: 34px;
|
||||
}
|
||||
|
||||
.file-dropzone-content strong {
|
||||
@@ -1237,7 +1304,8 @@ tbody tr:hover td.action-col {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.file-preview > .material-symbols-outlined {
|
||||
.file-preview > .material-symbols-outlined,
|
||||
.file-preview > .fluent-icon {
|
||||
align-items: center;
|
||||
background: var(--primary-container);
|
||||
border-radius: var(--radius);
|
||||
@@ -1798,3 +1866,323 @@ tbody tr:hover td.action-col {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Phenikaa-X application theme
|
||||
Keeps the existing EJS/JavaScript contract while applying Layer-1 tokens.
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
::selection {
|
||||
background: var(--orange-100);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
:focus-visible {
|
||||
outline: 2px solid var(--blue-500);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
background: var(--blue-900);
|
||||
border-color: var(--neutral-700);
|
||||
}
|
||||
|
||||
.brand-block {
|
||||
border-bottom: 1px solid rgba(197, 204, 224, 0.18);
|
||||
min-height: 72px;
|
||||
padding: var(--space-md);
|
||||
}
|
||||
|
||||
.brand-mark {
|
||||
background: var(--brand-accent);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: none;
|
||||
color: var(--neutral-0);
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.brand-copy strong {
|
||||
color: var(--neutral-0);
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.brand-copy span,
|
||||
.sidebar .nav-label,
|
||||
.sidebar-copyright {
|
||||
color: var(--blue-100);
|
||||
}
|
||||
|
||||
.brand-copy span,
|
||||
.nav-label {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.06em;
|
||||
}
|
||||
|
||||
.nav-section {
|
||||
gap: var(--space-xxs);
|
||||
padding: var(--space-sm);
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
border-left-width: 4px;
|
||||
border-radius: 0 var(--radius-md) var(--radius-md) 0;
|
||||
color: var(--blue-100);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
gap: var(--space-sm);
|
||||
min-height: 44px;
|
||||
}
|
||||
|
||||
.nav-item:hover {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
color: var(--neutral-0);
|
||||
}
|
||||
|
||||
.nav-item.active {
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
border-left-color: var(--brand-accent);
|
||||
color: var(--neutral-0);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.topbar {
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
border-color: var(--border-subtle);
|
||||
min-height: 64px;
|
||||
}
|
||||
|
||||
.page {
|
||||
padding: var(--space-lg);
|
||||
}
|
||||
|
||||
.page-header h1,
|
||||
.auth-heading h1 {
|
||||
color: var(--text-primary);
|
||||
font-size: 25px;
|
||||
font-weight: 700;
|
||||
letter-spacing: -0.025em;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.panel,
|
||||
.table-panel,
|
||||
.metric-card,
|
||||
.modal-content,
|
||||
.notification-panel,
|
||||
.empty-state,
|
||||
.auth-panel {
|
||||
background: var(--surface-base);
|
||||
border-color: var(--border-subtle);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--elevation-1);
|
||||
}
|
||||
|
||||
.modal-content,
|
||||
.notification-panel,
|
||||
.auth-panel {
|
||||
box-shadow: var(--elevation-2);
|
||||
}
|
||||
|
||||
.panel-header,
|
||||
.modal-header,
|
||||
.modal-actions,
|
||||
.page-filters,
|
||||
thead,
|
||||
td {
|
||||
border-color: var(--border-subtle);
|
||||
}
|
||||
|
||||
.btn,
|
||||
.icon-button,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
.btn {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--brand-primary);
|
||||
color: var(--neutral-0);
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: var(--brand-primary-strong);
|
||||
}
|
||||
|
||||
.btn-warning {
|
||||
background: var(--brand-accent);
|
||||
color: var(--neutral-900);
|
||||
}
|
||||
|
||||
.btn-warning:hover {
|
||||
background: var(--brand-accent-strong);
|
||||
color: var(--neutral-0);
|
||||
}
|
||||
|
||||
.btn-secondary,
|
||||
.icon-button {
|
||||
background: var(--surface-base);
|
||||
border-color: var(--border-subtle);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.btn-secondary:hover,
|
||||
.icon-button:hover,
|
||||
.icon-button.subtle:hover {
|
||||
background: var(--blue-50);
|
||||
border-color: var(--blue-200);
|
||||
color: var(--brand-primary);
|
||||
}
|
||||
|
||||
.form-field input,
|
||||
.form-field select,
|
||||
.form-field textarea,
|
||||
.filter-field input,
|
||||
.filter-field select,
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
background: var(--surface-base);
|
||||
border-color: var(--border-strong);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.form-field input:focus,
|
||||
.form-field select:focus,
|
||||
.form-field textarea:focus,
|
||||
.filter-field input:focus,
|
||||
.filter-field select:focus,
|
||||
input:focus,
|
||||
select:focus,
|
||||
textarea:focus {
|
||||
border-color: var(--brand-primary);
|
||||
box-shadow: 0 0 0 3px rgba(34, 55, 113, 0.16);
|
||||
}
|
||||
|
||||
thead {
|
||||
background: var(--surface-brand-tint);
|
||||
}
|
||||
|
||||
th {
|
||||
color: var(--blue-700);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.045em;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
tbody tr:hover {
|
||||
background: var(--blue-50);
|
||||
}
|
||||
|
||||
.badge {
|
||||
border-radius: var(--radius-sm);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.badge-success {
|
||||
background: var(--semantic-success-bg);
|
||||
color: var(--semantic-success);
|
||||
}
|
||||
|
||||
.badge-danger {
|
||||
background: var(--semantic-error-bg);
|
||||
color: var(--semantic-error);
|
||||
}
|
||||
|
||||
.badge-warning {
|
||||
background: var(--semantic-warning-bg);
|
||||
color: var(--semantic-warning);
|
||||
}
|
||||
|
||||
.badge-info,
|
||||
.badge-primary {
|
||||
background: var(--semantic-info-bg);
|
||||
color: var(--semantic-info);
|
||||
}
|
||||
|
||||
.empty-state > .fluent-icon {
|
||||
color: var(--brand-primary);
|
||||
height: 42px;
|
||||
width: 42px;
|
||||
}
|
||||
|
||||
.error-state > .fluent-icon {
|
||||
color: var(--semantic-error);
|
||||
}
|
||||
|
||||
.auth-shell {
|
||||
background:
|
||||
linear-gradient(135deg, rgba(30, 34, 67, 0.98), rgba(34, 55, 113, 0.93) 42%, rgba(247, 248, 251, 0.98) 42.1%),
|
||||
var(--surface-raised);
|
||||
}
|
||||
|
||||
.auth-panel {
|
||||
border-top: 4px solid var(--brand-accent);
|
||||
gap: var(--space-lg);
|
||||
padding: var(--space-lg);
|
||||
}
|
||||
|
||||
.auth-brand .brand-copy strong {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.auth-brand .brand-copy span {
|
||||
color: var(--text-tertiary);
|
||||
}
|
||||
|
||||
.auth-confirm-icon {
|
||||
background: var(--blue-50);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--brand-primary);
|
||||
}
|
||||
|
||||
.auth-confirm-icon .fluent-icon {
|
||||
height: 28px;
|
||||
width: 28px;
|
||||
}
|
||||
|
||||
.toast {
|
||||
background: var(--blue-900);
|
||||
border-radius: var(--radius-md);
|
||||
box-shadow: var(--elevation-2);
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.sidebar {
|
||||
box-shadow: var(--elevation-2);
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 560px) {
|
||||
.page {
|
||||
padding: var(--space-md);
|
||||
}
|
||||
|
||||
.auth-page {
|
||||
padding: var(--space-md);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
scroll-behavior: auto !important;
|
||||
transition-duration: 0.01ms !important;
|
||||
animation-duration: 0.01ms !important;
|
||||
animation-iteration-count: 1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,64 @@
|
||||
const body = document.body;
|
||||
const menuButton = document.getElementById('mobileMenuBtn');
|
||||
const sidebarBackdrop = document.getElementById('sidebarBackdrop');
|
||||
const FLUENT_ICON_FILES = Object.freeze({
|
||||
add: 'add_20_regular.svg',
|
||||
add_box: 'box_24_regular.svg',
|
||||
apps: 'apps_24_regular.svg',
|
||||
archive: 'archive_24_regular.svg',
|
||||
attach_file: 'attach_20_regular.svg',
|
||||
campaign: 'megaphone_20_regular.svg',
|
||||
check_circle: 'checkmark_circle_20_filled.svg',
|
||||
close: 'dismiss_20_regular.svg',
|
||||
dashboard: 'grid_24_regular.svg',
|
||||
database_off: 'database_warning_20_regular.svg',
|
||||
delete: 'delete_20_regular.svg',
|
||||
deployed_code: 'cube_24_regular.svg',
|
||||
download: 'arrow_download_20_regular.svg',
|
||||
draft: 'document_24_regular.svg',
|
||||
edit: 'edit_20_regular.svg',
|
||||
error: 'error_circle_20_filled.svg',
|
||||
forward_to_inbox: 'mail_arrow_forward_20_regular.svg',
|
||||
group: 'people_24_regular.svg',
|
||||
inventory_2: 'box_24_regular.svg',
|
||||
link_off: 'link_dismiss_20_regular.svg',
|
||||
login: 'arrow_enter_20_regular.svg',
|
||||
logout: 'sign_out_20_regular.svg',
|
||||
mark_email_unread: 'mail_unread_24_regular.svg',
|
||||
memory: 'memory_16_regular.svg',
|
||||
menu: 'navigation_20_regular.svg',
|
||||
notifications: 'alert_20_regular.svg',
|
||||
notifications_none: 'alert_off_20_regular.svg',
|
||||
person_add: 'person_add_20_regular.svg',
|
||||
precision_manufacturing: 'bot_24_filled.svg',
|
||||
save: 'save_20_regular.svg',
|
||||
search_off: 'search_24_regular.svg',
|
||||
send: 'send_20_regular.svg',
|
||||
stars: 'star_20_filled.svg',
|
||||
swap_horiz: 'arrow_swap_20_regular.svg',
|
||||
sync: 'arrow_sync_20_regular.svg',
|
||||
upgrade: 'arrow_up_20_regular.svg',
|
||||
upload: 'arrow_upload_20_regular.svg',
|
||||
upload_file: 'document_arrow_up_24_regular.svg',
|
||||
visibility: 'eye_20_regular.svg',
|
||||
warning: 'warning_20_filled.svg'
|
||||
});
|
||||
|
||||
function applyFluentIcon(element, iconName) {
|
||||
if (!element) return;
|
||||
const fileName = FLUENT_ICON_FILES[iconName] || 'question_20_regular.svg';
|
||||
element.classList.remove('material-symbols-outlined');
|
||||
element.classList.add('fluent-icon');
|
||||
element.style.setProperty('--fluent-icon-url', `url("/vendor/fluent-icons/${fileName}")`);
|
||||
element.setAttribute('aria-hidden', 'true');
|
||||
element.textContent = '';
|
||||
}
|
||||
|
||||
function hydrateFluentIcons(root) {
|
||||
root.querySelectorAll('.material-symbols-outlined').forEach((element) => {
|
||||
applyFluentIcon(element, element.textContent.trim());
|
||||
});
|
||||
}
|
||||
|
||||
function initNotiflix() {
|
||||
if (!window.Notiflix) return;
|
||||
@@ -11,8 +69,8 @@
|
||||
position: 'right-top',
|
||||
distance: '16px',
|
||||
timeout: 2600,
|
||||
borderRadius: '8px',
|
||||
fontFamily: 'Inter, sans-serif',
|
||||
borderRadius: '4px',
|
||||
fontFamily: 'Montserrat Variable, Montserrat, sans-serif',
|
||||
fontSize: '13px',
|
||||
messageMaxLength: 180,
|
||||
clickToClose: true,
|
||||
@@ -21,35 +79,35 @@
|
||||
useIcon: true,
|
||||
zindex: 5000,
|
||||
success: {
|
||||
background: '#067647',
|
||||
background: '#2e7d32',
|
||||
textColor: '#ffffff'
|
||||
},
|
||||
failure: {
|
||||
background: '#b42318',
|
||||
background: '#c62828',
|
||||
textColor: '#ffffff'
|
||||
},
|
||||
warning: {
|
||||
background: '#b54708',
|
||||
background: '#9a5b00',
|
||||
textColor: '#ffffff'
|
||||
},
|
||||
info: {
|
||||
background: '#3755c3',
|
||||
background: '#223771',
|
||||
textColor: '#ffffff'
|
||||
}
|
||||
});
|
||||
|
||||
window.Notiflix.Confirm.init({
|
||||
width: '360px',
|
||||
borderRadius: '8px',
|
||||
fontFamily: 'Inter, sans-serif',
|
||||
titleColor: '#111827',
|
||||
borderRadius: '4px',
|
||||
fontFamily: 'Montserrat Variable, Montserrat, sans-serif',
|
||||
titleColor: '#161824',
|
||||
titleFontSize: '16px',
|
||||
messageColor: '#475569',
|
||||
messageColor: '#565b70',
|
||||
messageFontSize: '13px',
|
||||
okButtonBackground: '#3755c3',
|
||||
okButtonBackground: '#223771',
|
||||
okButtonColor: '#ffffff',
|
||||
cancelButtonBackground: '#e2e8f0',
|
||||
cancelButtonColor: '#334155',
|
||||
cancelButtonBackground: '#eeedf6',
|
||||
cancelButtonColor: '#3c4054',
|
||||
backOverlayColor: 'rgba(15, 23, 42, 0.42)',
|
||||
zindex: 5001,
|
||||
cssAnimationStyle: 'zoom'
|
||||
@@ -701,9 +759,7 @@
|
||||
const icon = document.createElement('span');
|
||||
icon.className = 'notification-item-icon';
|
||||
const iconGlyph = document.createElement('span');
|
||||
iconGlyph.className = 'material-symbols-outlined';
|
||||
iconGlyph.setAttribute('aria-hidden', 'true');
|
||||
iconGlyph.textContent = getNotificationIcon(notification);
|
||||
applyFluentIcon(iconGlyph, getNotificationIcon(notification));
|
||||
icon.appendChild(iconGlyph);
|
||||
|
||||
const copy = document.createElement('span');
|
||||
@@ -926,6 +982,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
hydrateFluentIcons(document);
|
||||
initNotiflix();
|
||||
initFileDropzones();
|
||||
initRegistrationUniqueChecks();
|
||||
|
||||
@@ -127,6 +127,8 @@ app.use(express.urlencoded({ extended: true }));
|
||||
app.use(express.json({ limit: '32kb' }));
|
||||
app.use(express.static(path.join(__dirname, 'public')));
|
||||
app.use('/vendor/notiflix', express.static(path.join(__dirname, 'node_modules/notiflix/dist')));
|
||||
app.use('/vendor/montserrat', express.static(path.join(__dirname, 'node_modules/@fontsource-variable/montserrat')));
|
||||
app.use('/vendor/fluent-icons', express.static(path.join(__dirname, 'node_modules/@fluentui/svg-icons/icons')));
|
||||
app.use(applyPublicApiCors);
|
||||
app.get('/packages/agent/latest.deb', asyncRoute(async (req, res) => {
|
||||
const arch = normalizeAgentArch(req.query.arch);
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><%= title %> | Robot Installer</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/vendor/montserrat/index.css">
|
||||
<link rel="stylesheet" href="/vendor/notiflix/notiflix-<%= notiflixVersion %>.min.css">
|
||||
<link rel="stylesheet" href="/css/styles.css">
|
||||
</head>
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><%= title %> | Robot Installer</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/vendor/montserrat/index.css">
|
||||
<link rel="stylesheet" href="/vendor/notiflix/notiflix-<%= notiflixVersion %>.min.css">
|
||||
<link rel="stylesheet" href="/css/styles.css">
|
||||
</head>
|
||||
|
||||
@@ -4,10 +4,7 @@
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><%= title %> | Robot Installer</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="/vendor/montserrat/index.css">
|
||||
<link rel="stylesheet" href="/vendor/notiflix/notiflix-<%= notiflixVersion %>.min.css">
|
||||
<link rel="stylesheet" href="/css/styles.css">
|
||||
</head>
|
||||
|
||||
Reference in New Issue
Block a user