@tekkare/romulus 0.1.11 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/module.json +1 -1
- package/dist/module.mjs +5 -0
- package/dist/runtime/assets/styles/chrome.css +1 -0
- package/dist/runtime/assets/styles/components.css +1 -1
- package/dist/runtime/assets/styles/tokens.css +1 -1
- package/dist/runtime/components/AiChat.vue +254 -0
- package/dist/runtime/components/AppShell.vue +68 -0
- package/dist/runtime/components/HybridTable.vue +70 -0
- package/dist/runtime/components/LineChart.vue +7 -0
- package/dist/runtime/components/Modal.vue +79 -0
- package/dist/runtime/components/NavBar.vue +147 -0
- package/dist/runtime/components/SimpleBar.vue +85 -0
- package/dist/runtime/components/Table.vue +161 -0
- package/dist/runtime/components/ToolStrip.vue +73 -0
- package/dist/runtime/components/TopBar.vue +46 -0
- package/dist/runtime/composables/useTheme.js +2 -9
- package/dist/runtime/utils/chart.d.ts +77 -8
- package/dist/runtime/utils/chart.js +23 -3
- package/dist/runtime/utils/transitionGuard.d.ts +24 -0
- package/dist/runtime/utils/transitionGuard.js +14 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -21,6 +21,7 @@ const module = defineNuxtModule({
|
|
|
21
21
|
if (options.baseStyles)
|
|
22
22
|
nuxt.options.css.push(resolve(runtimeDir, "assets/styles/base.css"));
|
|
23
23
|
nuxt.options.css.push(resolve(runtimeDir, "assets/styles/components.css"));
|
|
24
|
+
nuxt.options.css.push(resolve(runtimeDir, "assets/styles/chrome.css"));
|
|
24
25
|
if (options.utilities)
|
|
25
26
|
nuxt.options.css.push(resolve(runtimeDir, "assets/styles/utilities.css"));
|
|
26
27
|
await addComponentsDir({
|
|
@@ -38,6 +39,10 @@ const module = defineNuxtModule({
|
|
|
38
39
|
{ rel: "stylesheet", href: fontsHref }
|
|
39
40
|
);
|
|
40
41
|
}
|
|
42
|
+
const phosphorHref = "https://unpkg.com/@phosphor-icons/web@2.1.1/src/regular/style.css";
|
|
43
|
+
if (!nuxt.options.app.head.link.some((l) => l.href === phosphorHref)) {
|
|
44
|
+
nuxt.options.app.head.link.push({ rel: "stylesheet", href: phosphorHref });
|
|
45
|
+
}
|
|
41
46
|
}
|
|
42
47
|
});
|
|
43
48
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
body.lcollapsed{padding-left:var(--sidebar-collapsed-w)}.nav-item .icn i,.rpanel-item .icn i{font-size:16px}.strip-icon i,.topbar-toggle i{font-size:18px}.chev i,.chev-r i{font-size:11px}.topbar-toggle{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:6px;color:var(--text-secondary);cursor:pointer;display:flex;font-size:16px;height:32px;justify-content:center;width:32px}.topbar-toggle:hover{background:var(--bg-hover);border-color:var(--color-violet-pale);color:var(--color-secondary)}.logo-mark{align-items:center;background:linear-gradient(135deg,var(--color-primary),var(--color-secondary));border-radius:6px;box-shadow:0 2px 6px rgba(107,63,255,.25);color:var(--color-text-inverse);display:flex;flex-shrink:0;font-size:14px;height:28px;justify-content:center;width:28px}.logo-mark,.logo-text{font-family:var(--font-serif);font-weight:700}.logo-text{font-size:16px;line-height:1}.logo-sub{color:var(--text-muted);font-size:10px;letter-spacing:.05em;margin-top:2px;text-transform:uppercase}.sidebar{background:var(--bg-surface);border-right:1px solid var(--border-default);bottom:0;display:flex;flex-direction:column;left:0;overflow-x:hidden;overflow-y:auto;position:fixed;top:0;transition:width .24s cubic-bezier(.2,0,0,1);width:var(--sidebar-w);z-index:70}.sidebar-top{border-bottom:1px solid var(--border-default);flex-shrink:0;height:var(--topbar-h);justify-content:space-between;padding:0 14px}.sidebar-top,.sidebar-top .logo-block{align-items:center;display:flex;gap:8px}.sidebar-top .logo-block{min-width:0}body.lcollapsed .sidebar-top{justify-content:center;padding:0}body.lcollapsed .sidebar-top .logo-block{display:none}body.lcollapsed .sidebar-top .logo-mark{display:flex}.sidebar-search{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:999px;display:flex;gap:10px;margin:10px 12px 4px;padding:7px 14px;transition:border-color .15s,background .15s}.sidebar-search:focus-within,.sidebar-search:hover{background:var(--bg-surface);border-color:var(--color-violet-pale)}.sidebar-search i{color:var(--text-muted);flex-shrink:0;font-size:14px}.sidebar-search input{background:transparent;border:none;color:var(--text-primary);flex:1;font-family:inherit;font-size:13px;min-width:0;outline:none}.sidebar-search input::-moz-placeholder{color:var(--text-muted)}.sidebar-search input::placeholder{color:var(--text-muted)}.sidebar-search kbd{background:var(--bg-surface);border:1px solid var(--border-default);border-radius:4px;color:var(--text-secondary);flex-shrink:0;font-family:inherit;font-size:10px;font-weight:600;padding:1px 5px}body.lcollapsed .sidebar-search{display:none}body.lcollapsed .sidebar{width:var(--sidebar-collapsed-w)}.nav-group{padding:4px 0}.nav-section-header{align-items:center;cursor:pointer;display:flex;justify-content:space-between;padding:14px 14px 6px;-webkit-user-select:none;-moz-user-select:none;user-select:none}.nav-section-header .label,.nav-section-header span{color:var(--text-muted);font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.nav-section-header .chev{color:var(--text-muted);font-size:10px;transition:transform .2s}.nav-section.collapsed .chev{transform:rotate(-90deg)}.nav-section.collapsed .nav-items{display:none}.nav-item{align-items:center;color:var(--text-secondary);cursor:pointer;display:flex;font-size:13px;font-weight:500;gap:10px;padding:7px 14px 7px 22px;transition:background .15s,color .15s;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.nav-item .icn{color:var(--text-muted);flex-shrink:0;text-align:center;width:16px}.nav-item .lbl{flex:1;overflow:hidden;text-overflow:ellipsis}.nav-item .chev-r{color:var(--text-muted);font-size:10px;transition:transform .2s}.nav-item.has-children.open .chev-r{transform:rotate(90deg)}.nav-item:hover{background:var(--bg-surface-3);color:var(--text-primary)}.nav-item:hover .icn{color:var(--text-secondary)}.nav-item.active{background:linear-gradient(90deg,var(--color-violet-pale) 0,var(--bg-hover) 100%);color:var(--color-primary);font-weight:700;position:relative}.nav-item.active:before{background:var(--color-secondary);border-radius:0 4px 4px 0;bottom:5px;content:"";left:0;position:absolute;top:5px;width:4px}.nav-item.active .icn{color:var(--color-secondary)}.nav-subitems{background:var(--bg-surface-2);border-bottom:1px solid var(--border-soft);border-top:1px solid var(--border-soft);display:none;padding:2px 0 4px}.nav-item.has-children.open+.nav-subitems{display:block}.nav-subitem{align-items:center;color:var(--text-secondary);cursor:pointer;display:flex;font-size:12px;gap:8px;padding:6px 14px 6px 44px}.nav-subitem:hover{background:var(--bg-surface-3);color:var(--text-primary)}.nav-subitem.active{background:linear-gradient(90deg,var(--color-violet-pale) 0,var(--bg-hover) 100%);color:var(--color-primary);font-weight:700;position:relative}.nav-subitem.active:before{background:var(--color-secondary);border-radius:0 4px 4px 0;bottom:4px;content:"";left:0;position:absolute;top:4px;width:4px}.sidebar-footer{border-top:1px solid var(--border-default);display:flex;flex-direction:column;gap:4px;margin-top:auto;padding:10px 8px}.sb-user{align-items:center;border-radius:8px;cursor:pointer;display:flex;gap:12px;padding:10px 12px;transition:background .15s;-webkit-user-select:none;-moz-user-select:none;user-select:none}.sb-user:hover{background:var(--bg-surface-3)}.sb-user-avatar{align-items:center;background:linear-gradient(135deg,var(--color-secondary),var(--color-accent-teal));border-radius:50%;box-shadow:0 2px 6px rgba(107,63,255,.22);color:var(--color-text-inverse);display:flex;flex-shrink:0;font-family:var(--font-serif);font-size:13px;font-weight:700;height:36px;justify-content:center;width:36px}.sb-user-info{flex:1;min-width:0}.sb-user-name{color:var(--text-primary);font-size:13px;font-weight:600;line-height:1.25}.sb-user-name,.sb-user-org{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sb-user-org{color:var(--text-muted);font-size:11px;line-height:1.2;margin-top:2px}.sb-user-chev{color:var(--text-muted);flex-shrink:0;font-size:13px}.sb-actions{display:flex;gap:4px}.sb-actions .sb-lang,.sb-actions a{align-items:center;border-radius:6px;color:var(--text-secondary);cursor:pointer;display:inline-flex;flex:1;font-family:inherit;font-size:12px;font-weight:600;gap:5px;justify-content:center;padding:8px 10px;text-decoration:none;transition:background .15s,color .15s}.sb-actions .sb-lang:hover,.sb-actions a:hover{background:var(--bg-surface-3);color:var(--text-primary)}.sb-actions a.primary{color:var(--color-primary)}.sb-actions a.primary:hover{background:var(--bg-hover);color:var(--color-secondary)}.sb-actions i{font-size:13px}body.lcollapsed .sidebar .chev-r,body.lcollapsed .sidebar .lbl,body.lcollapsed .sidebar .nav-section-header,body.lcollapsed .sidebar-footer{display:none}body.lcollapsed .sidebar .nav-item.has-children.open+.nav-subitems,body.lcollapsed .sidebar .nav-subitems{display:none!important}body.lcollapsed .sidebar .nav-item.has-children.open .chev-r{transform:none}body.lcollapsed .sidebar .nav-group{border-top:1px solid var(--border-soft);padding:4px 0}body.lcollapsed .sidebar .nav-group:first-of-type{border-top:none}.nav-subitems.flyout,body.lcollapsed .sidebar .nav-item.has-children.open+.nav-subitems.flyout,body.lcollapsed .sidebar .nav-subitems.flyout{animation:flyout-in .12s cubic-bezier(.2,0,0,1);background:var(--bg-surface);border:1px solid var(--border-default);border-left:none;border-radius:0 8px 8px 0;box-shadow:var(--shadow-lg);display:block!important;left:var(--sidebar-collapsed-w);min-width:220px;padding:8px 0;position:fixed;z-index:100}.nav-subitems.flyout:before{border-bottom:1px solid var(--border-soft);color:var(--text-muted);content:attr(data-parent-label);display:block;font-size:11px;font-weight:700;letter-spacing:.08em;margin-bottom:4px;padding:6px 16px 8px;text-transform:uppercase}.nav-subitems.flyout .nav-subitem{font-size:13px;padding:8px 16px}body.lcollapsed .sidebar .nav-item{position:relative}body.lcollapsed .sidebar .nav-item[data-tip]:hover:after{background:var(--text-primary);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.2);color:var(--color-text-inverse);content:attr(data-tip);font-size:12px;font-weight:500;left:var(--sidebar-collapsed-w);margin-left:6px;padding:5px 10px;pointer-events:none;position:fixed;top:var(--tip-top,0);white-space:nowrap;z-index:110}.rsidebar .strip-icon{position:relative}.rsidebar .strip-icon[data-tip]:hover:before{background:var(--text-primary);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.2);color:var(--color-text-inverse);content:attr(data-tip);font-size:12px;font-weight:500;margin-right:6px;padding:5px 10px;pointer-events:none;position:fixed;right:var(--rsidebar-collapsed-w);top:var(--tip-top,0);white-space:nowrap;z-index:110}body.ropen .rsidebar .strip-icon[data-tip]:hover:before{display:none}.rsidebar .strip-icon.has-flyout.show-flyout .rflyout{display:block}body.ropen .rsidebar .rflyout{display:none!important}body.lcollapsed .nav-item{justify-content:center;padding:10px 0}body.lcollapsed .nav-section-header{justify-content:center;padding:8px 0}.rsidebar{background:var(--bg-surface);border-left:1px solid var(--border-default);bottom:0;display:flex;flex-direction:column;overflow:hidden;position:fixed;right:0;top:0;width:var(--rsidebar-collapsed-w);z-index:70}.rstrip-top{align-items:center;border-bottom:1px solid var(--border-default);display:flex;flex-shrink:0;height:var(--topbar-h);justify-content:center}.rstrip-collapsed{align-items:stretch;gap:4px;padding:8px}.rstrip-collapsed,.strip-icon{display:flex;flex-direction:column}.strip-icon{align-items:center;border-radius:8px;color:var(--text-secondary);cursor:pointer;gap:5px;justify-content:center;padding:10px 4px;position:relative;transition:background .15s,color .15s}.strip-icon i{font-size:19px;transition:color .15s}.strip-icon .strip-label{color:inherit;font-size:10px;font-weight:600;letter-spacing:.01em;line-height:1;white-space:nowrap}.strip-icon:hover{background:var(--bg-surface-3);color:var(--text-primary)}.strip-icon.active,.strip-icon:hover i{color:var(--color-secondary)}.strip-icon.active{background:var(--bg-hover)}.strip-icon.active i{color:var(--color-secondary)}.strip-icon .dot{background:var(--color-notification);border-radius:50%;box-shadow:0 0 0 2px var(--color-text-inverse);height:8px;position:absolute;right:14px;top:6px;width:8px}.strip-icon.is-live .dot{background:var(--color-success);box-shadow:0 0 0 2px var(--bg-surface)}.strip-icon.is-live .dot:after{animation:stripLivePulse 1.8s ease-out infinite;background:var(--color-success);border-radius:50%;content:"";inset:-2px;position:absolute}.strip-icon.is-live .strip-label{background:var(--color-success);border-radius:var(--radius-pill);color:var(--color-text-inverse);display:inline-block;font-weight:var(--weight-bold);letter-spacing:.04em;line-height:1.2;margin-top:2px;padding:2px var(--space-6);text-transform:uppercase}@media (prefers-reduced-motion:reduce){.strip-icon.is-live .dot:after{animation:none}}.strip-badge{align-items:center;background:var(--color-primary);border-radius:999px;box-shadow:0 0 0 2px var(--color-text-inverse);color:var(--color-text-inverse);display:flex;font-size:9px;font-variant-numeric:tabular-nums;font-weight:700;height:16px;justify-content:center;line-height:1;min-width:18px;padding:0 5px;position:absolute;right:8px;top:4px}.strip-divider{background:var(--bg-surface-3);margin:6px auto;width:70%}body.ropen .rpanel-open{display:block}.ptabs.export-toptabs{align-items:stretch;border-bottom:1px solid var(--border-default);gap:0;height:auto;margin:0 0 var(--space-20);padding:0}.ptabs.export-toptabs .ptab{align-items:center;display:inline-flex;font-size:var(--font-14);font-weight:var(--weight-semibold);gap:var(--space-6);padding:var(--space-12) var(--space-16)}.ptabs.export-toptabs .ptab i{font-size:var(--font-16)}.ptabs.export-toptabs .lib-tab-count{background:var(--bg-surface-3);border-radius:var(--radius-pill);color:var(--text-muted);font-size:var(--font-11);font-variant-numeric:tabular-nums;font-weight:var(--weight-bold);min-width:18px;padding:0 var(--space-6);text-align:center}.ptabs.export-toptabs .ptab.active .lib-tab-count{background:var(--bg-hover);color:var(--color-secondary)}.ptabs.views-toptabs{align-items:stretch;border-bottom:1px solid var(--border-default);gap:0;height:auto;margin:0 0 var(--space-16);padding:0}.ptabs.views-toptabs .ptab{align-items:center;display:inline-flex;font-size:var(--font-14);font-weight:var(--weight-semibold);gap:var(--space-6);padding:var(--space-12) var(--space-16)}.ptabs.views-toptabs .ptab i{font-size:var(--font-16)}.ptabs.views-toptabs .lib-tab-count{background:var(--bg-surface-3);border-radius:var(--radius-pill);color:var(--text-muted);font-size:var(--font-11);font-variant-numeric:tabular-nums;font-weight:var(--weight-bold);min-width:18px;padding:0 var(--space-6);text-align:center}.ptabs.views-toptabs .ptab.active .lib-tab-count{background:var(--bg-hover);color:var(--color-secondary)}.ptabs.alerts-toptabs{gap:var(--space-4);margin:0 0 var(--space-16);padding:0}.ptabs.alerts-toptabs .ptab{font-size:var(--font-13);padding:var(--space-8) var(--space-12)}.ptabs.alerts-toptabs .ptab i{font-size:var(--font-16)}.topbar{background:var(--bg-surface);border-bottom:1px solid var(--border-default);padding-top:28px;position:sticky;top:var(--topbar-merged-h);transition:padding-top .2s ease;z-index:31}.topbar.compact{padding-top:10px}.topbar.compact .pane-title{font-size:19px;margin-bottom:8px}.ptabs{align-items:flex-end;display:flex;gap:4px;height:var(--tabs-h);padding:0 32px}.ptab{border-bottom:3px solid transparent;color:var(--text-secondary);cursor:pointer;font-size:14px;font-weight:500;padding:0 20px 12px;position:relative;transition:color .15s;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ptab:hover{color:var(--text-primary)}.ptab.active{background:linear-gradient(180deg,transparent 30%,rgba(var(--brand-rgb),.06) 100%);border-bottom-color:var(--color-primary);border-radius:6px 6px 0 0;color:var(--color-primary);font-weight:700}.strip-icon--hub{display:none}.strip-divider{background:var(--border-default);height:1px;margin:var(--space-8) auto var(--space-4);width:60%}.topbar>*{margin-left:auto;margin-right:auto;max-width:var(--content-max-w);width:100%}body.lcollapsed .hint{left:calc(var(--sidebar-collapsed-w) + 16px)}body.ropen .hint{right:calc(var(--rsidebar-w) + 16px)}.mobile-hamburger{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:999px;box-shadow:0 2px 8px rgba(0,0,0,.08);cursor:pointer;display:none;height:40px;justify-content:center;left:10px;position:fixed;top:10px;width:40px;z-index:260}.mobile-hamburger i{color:var(--text-primary);font-size:18px}.mobile-backdrop{background:rgba(0,0,0,.4);display:none;inset:0;position:fixed;z-index:240}body.lopen .mobile-backdrop{display:block}@media (max-width:767px){.mobile-hamburger{display:inline-flex}body.lopen .mobile-hamburger{display:none}.sidebar{box-shadow:4px 0 16px rgba(0,0,0,.15);transform:translateX(-100%);transition:transform .24s cubic-bezier(.2,0,0,1);width:280px;z-index:250}body.lopen .sidebar{transform:translateX(0)}body.lcollapsed .sidebar{width:280px}#rDrawer,.rsidebar{display:none!important}.ptabs{flex-wrap:nowrap;overflow-x:auto;padding:0 14px;scrollbar-width:thin}.ptabs::-webkit-scrollbar{height:4px}.ptab{flex-shrink:0;white-space:nowrap}}body.rm-shell{background:var(--bg-app);color:var(--text-primary);font-family:var(--font-sans);margin:0;padding-left:var(--sidebar-w);padding-right:var(--rsidebar-collapsed-w);padding-top:var(--topbar-merged-h);transition:padding .24s cubic-bezier(.2,0,0,1)}body.rm-shell.lcollapsed{padding-left:var(--sidebar-collapsed-w)}body.rm-switching.rm-shell,body.theme-switching.rm-shell{transition:none!important}@media (max-width:767px){body.rm-shell,body.rm-shell.lcollapsed{padding-left:0;padding-right:0}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.grid-2{grid-template-columns:repeat(2,1fr)}.grid-2,.grid-3{display:grid;gap:20px}.grid-3{grid-template-columns:repeat(3,1fr)}.grid-4{display:grid;gap:16px;grid-template-columns:repeat(4,1fr)}.grid-2-1{display:grid;gap:20px;grid-template-columns:2fr 1fr}.pane-title{color:var(--text-primary);font-family:var(--font-serif);font-size:32px;font-weight:700;letter-spacing:-.02em;line-height:1.1;margin:0 0 16px}.pane-sub{color:var(--text-muted);font-size:13px;line-height:1.55;margin:0 0 24px;max-width:78ch}.chart-section{margin-inline:auto;max-width:var(--content-max-w,1440px);padding:0 0 40px;width:100%}.section-label{align-items:center;color:var(--text-secondary);display:flex;font-size:11px;font-weight:700;gap:8px;letter-spacing:.12em;margin:40px 0 18px;text-transform:uppercase}body.text-large .pane-title{font-size:38px}body.text-xl .pane-title{font-size:46px}body.text-large .section-label{font-size:13px}body.text-xl .section-label{font-size:14px}.chart-card{background:var(--bg-surface);border:1px solid var(--border-default);border-radius:10px;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;transition:box-shadow .18s,border-color .18s}.chart-card:hover{border-color:var(--color-violet-pale);box-shadow:0 6px 16px rgba(107,63,255,.1),0 1px 3px rgba(30,41,59,.04)}.chart-card-head{padding:22px 64px 14px 24px;position:relative}.chart-card-title{color:var(--text-primary);font-size:15px;font-weight:700;letter-spacing:-.01em;line-height:1.3;margin:0 0 5px}.chart-card-context{color:var(--text-muted);font-size:12px;line-height:1.55;margin:0}.chart-card-actions{position:absolute;right:12px;top:12px}.cc-export{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:6px;color:var(--text-secondary);cursor:pointer;display:flex;font-size:14px;height:28px;justify-content:center;transition:background .15s,color .15s,border-color .15s;width:28px}.cc-export:hover{color:var(--color-secondary)}.cc-export:hover,.chart-card-actions.open .cc-export{background:var(--bg-hover);border-color:var(--color-violet-pale)}.chart-card-actions.open .cc-export{color:var(--color-primary)}.cc-menu{animation:cc-menu-in .12s cubic-bezier(.2,0,0,1);background:var(--bg-surface);border:1px solid var(--border-default);border-radius:8px;box-shadow:var(--shadow-lg);display:none;min-width:200px;padding:6px 0;position:absolute;right:0;top:34px;z-index:var(--z-modal)}.chart-card-actions.open .cc-menu{display:block}.cc-menu-section{color:var(--text-muted);font-size:10px;font-weight:700;letter-spacing:.08em;padding:8px 14px 4px;text-transform:uppercase}.cc-menu-item{align-items:center;background:none;border:0;color:var(--text-secondary);cursor:pointer;display:flex;font-family:var(--font-sans);font-size:13px;gap:10px;padding:7px 14px;text-align:left;width:100%}.cc-menu-item i{color:var(--text-muted);font-size:14px}.cc-menu-item:hover{background:var(--bg-surface-3);color:var(--text-primary)}.cc-menu-item:hover i{color:var(--text-secondary)}.cc-menu-divider{background:var(--bg-surface-3);height:1px;margin:4px 0}@keyframes cc-menu-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.chart-card-body{flex:1;padding:4px 12px 8px}.chart-card-foot{align-items:center;background:var(--bg-surface-2);border-radius:0 0 10px 10px;border-top:1px solid var(--border-soft);color:var(--text-muted);display:flex;flex-wrap:wrap;font-size:11px;gap:10px;padding:12px 24px}.chart-card-foot .src{align-items:center;display:flex;gap:4px}.chart-card-foot .src b{color:var(--text-secondary);font-weight:600}.chart-card-foot .dot{background:var(--border-default);border-radius:50%;height:3px;width:3px}.chart-card-foot .updated{color:var(--text-secondary);font-weight:500}.kpi-card{background:var(--bg-surface);border:1px solid var(--border-default);border-radius:8px;box-shadow:0 2px 8px rgba(30,41,59,.06);padding:16px 18px}.kpi-label{color:var(--text-muted);font-size:11px;font-weight:600;letter-spacing:.1em;margin:0 0 6px;text-transform:uppercase}.kpi-value{color:var(--color-primary);font-family:var(--font-serif);font-size:28px;font-weight:700;line-height:1;margin:0}.kpi-value.healthcare{color:var(--color-healthcare)}.kpi-value.discovery{color:var(--color-discovery)}.kpi-value.pharma{color:var(--color-pharma)}.kpi-value.databank{color:var(--color-databank)}.kpi-trend{align-items:center;display:inline-flex;font-size:12px;font-weight:600;gap:4px;margin-top:6px}.kpi-trend i{font-size:11px}.kpi-trend--up{color:var(--color-success)}.kpi-trend--down{color:var(--color-danger)}.kpi-foot,.kpi-trend--flat{color:var(--text-muted)}.kpi-foot{font-size:11px;margin-top:4px}.badge{border-radius:4px;display:inline-block;font-size:10px;font-weight:600;padding:2px 8px}.badge-active{background:var(--color-success-bg);color:var(--color-success)}.badge-pending{background:var(--color-warning-bg);color:var(--color-warning)}.badge-error{background:var(--color-danger-bg);color:var(--color-danger)}.badge-info{background:var(--bg-hover);color:var(--color-primary)}.badge-grey{background:var(--bg-surface-3);color:var(--text-secondary)}table.tk{border-collapse:collapse;font-size:13px;width:100%}.sr-only,table.tk>caption.sr-only{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0,0,0,0);border:0;white-space:nowrap}table.tk caption{caption-side:top;color:var(--text-primary);font-size:var(--font-13);font-weight:var(--weight-bold);padding:0 0 var(--space-8);text-align:left}table.tk th{background:var(--bg-surface-2);border-bottom:1px solid var(--border-default);color:var(--text-secondary);font-size:11px;font-weight:700;letter-spacing:.08em;padding:12px 14px;text-align:left;text-transform:uppercase}table.tk tbody th[scope=row]{background:transparent;font-size:var(--font-13);font-weight:var(--weight-bold);letter-spacing:0;text-transform:none}table.tk tbody th[scope=row],table.tk td{border-bottom:1px solid var(--border-soft);color:var(--text-primary)}table.tk td{padding:12px 14px}table.tk tbody tr:nth-child(2n) td,table.tk tbody tr:nth-child(2n) th[scope=row]{background:var(--bg-surface-2)}table.tk tbody tr:hover td,table.tk tbody tr:hover th[scope=row]{background:var(--bg-hover)}table.tk th[aria-sort]{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}table.tk th[aria-sort]:hover{color:var(--text-primary)}.tk-wrap{overflow-x:auto}.tk-num{font-variant-numeric:tabular-nums;text-align:right}.nav-group{display:flex;flex-direction:column}.nav-group-header{align-items:center;background:none;border:0;color:var(--text-muted);cursor:pointer;display:flex;font-family:var(--font-sans);font-size:11px;font-weight:700;gap:8px;letter-spacing:.08em;padding:8px 12px;text-align:left;text-transform:uppercase;transition:color var(--duration-fast) var(--ease-out);width:100%}.nav-group-header:hover{color:var(--text-secondary)}.nav-group-header .caret{display:inline-flex;margin-left:auto;transition:transform var(--duration-fast) var(--ease-out)}.nav-group[data-open=true]>.nav-group-header{color:var(--color-primary)}.nav-group[data-open=true]>.nav-group-header .caret{transform:rotate(180deg)}.nav-group-items{display:flex;flex-direction:column;gap:2px;padding:2px 0 8px}.cc-export:focus-visible,.cc-menu-item:focus-visible,.chart-card :focus-visible,.nav-group-header:focus-visible,table.tk th[aria-sort]:focus-visible{box-shadow:var(--shadow-focus);outline:2px solid var(--color-secondary);outline-offset:2px}.cc-menu-item,.nav-group-header{min-height:40px}body.text-large .kpi-label{font-size:13px}body.text-large .kpi-value{font-size:34px}body.text-large .kpi-trend{font-size:14px}body.text-large .kpi-foot{font-size:13px}body.text-large .chart-card-title{font-size:17px}body.text-large .chart-card-context{font-size:14px}body.text-large .chart-card-foot{font-size:12px}body.text-large .badge{font-size:12px;padding:3px 9px}body.text-large table.tk{font-size:15px}body.text-large table.tk th{font-size:13px}body.text-xl .kpi-label{font-size:14px}body.text-xl .kpi-value{font-size:40px}body.text-xl .kpi-trend{font-size:16px}body.text-xl .kpi-foot{font-size:14px}body.text-xl .chart-card-title{font-size:20px}body.text-xl .chart-card-context{font-size:16px}body.text-xl .chart-card-foot{font-size:14px}body.text-xl .badge{font-size:14px;padding:3px 10px}body.text-xl table.tk{font-size:16px}body.text-xl table.tk th{font-size:14px}body.high-contrast .cc-export,body.high-contrast .cc-menu,body.high-contrast .chart-card,body.high-contrast .kpi-card{border-width:2px}body.high-contrast .chart-card:hover{border-color:var(--border-default)}body.theme-switching,body.theme-switching *,body.theme-switching :after,body.theme-switching :before{transition:none!important}body.high-contrast *{box-shadow:none!important}
|
|
1
|
+
.grid-2{grid-template-columns:repeat(2,1fr)}.grid-2,.grid-3{display:grid;gap:20px}.grid-3{grid-template-columns:repeat(3,1fr)}.grid-4{display:grid;gap:16px;grid-template-columns:repeat(4,1fr)}.grid-2-1{display:grid;gap:20px;grid-template-columns:2fr 1fr}.pane-title{color:var(--text-primary);font-family:var(--font-serif);font-size:32px;font-weight:700;letter-spacing:-.02em;line-height:1.1;margin:0 0 16px}.pane-sub{color:var(--text-muted);font-size:13px;line-height:1.55;margin:0 0 24px;max-width:78ch}.chart-section{margin-inline:auto;max-width:var(--content-max-w,1440px);padding:0 0 40px;width:100%}.section-label{align-items:center;color:var(--text-secondary);display:flex;font-size:11px;font-weight:700;gap:8px;letter-spacing:.12em;margin:40px 0 18px;text-transform:uppercase}body.text-large .pane-title{font-size:38px}body.text-xl .pane-title{font-size:46px}body.text-large .section-label{font-size:13px}body.text-xl .section-label{font-size:14px}.chart-card{background:var(--bg-surface);border:1px solid var(--border-default);border-radius:10px;box-shadow:var(--shadow-sm);display:flex;flex-direction:column;transition:box-shadow .18s,border-color .18s}.chart-card:hover{border-color:var(--color-violet-pale);box-shadow:0 6px 16px rgba(107,63,255,.1),0 1px 3px rgba(30,41,59,.04)}.chart-card-head{padding:22px 64px 14px 24px;position:relative}.chart-card-title{color:var(--text-primary);font-size:15px;font-weight:700;letter-spacing:-.01em;line-height:1.3;margin:0 0 5px}.chart-card-context{color:var(--text-muted);font-size:12px;line-height:1.55;margin:0}.chart-card-actions{position:absolute;right:12px;top:12px}.cc-export{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:6px;color:var(--text-secondary);cursor:pointer;display:flex;font-size:14px;height:28px;justify-content:center;transition:background .15s,color .15s,border-color .15s;width:28px}.cc-export:hover{color:var(--color-secondary)}.cc-export:hover,.chart-card-actions.open .cc-export{background:var(--bg-hover);border-color:var(--color-violet-pale)}.chart-card-actions.open .cc-export{color:var(--color-primary)}.cc-menu{animation:cc-menu-in .12s cubic-bezier(.2,0,0,1);background:var(--bg-surface);border:1px solid var(--border-default);border-radius:8px;box-shadow:var(--shadow-lg);display:none;min-width:200px;padding:6px 0;position:absolute;right:0;top:34px;z-index:var(--z-modal)}.chart-card-actions.open .cc-menu{display:block}.cc-menu-section{color:var(--text-muted);font-size:10px;font-weight:700;letter-spacing:.08em;padding:8px 14px 4px;text-transform:uppercase}.cc-menu-item{align-items:center;background:none;border:0;color:var(--text-secondary);cursor:pointer;display:flex;font-family:var(--font-sans);font-size:13px;gap:10px;padding:7px 14px;text-align:left;width:100%}.cc-menu-item i{color:var(--text-muted);font-size:14px}.cc-menu-item:hover{background:var(--bg-surface-3);color:var(--text-primary)}.cc-menu-item:hover i{color:var(--text-secondary)}.cc-menu-divider{background:var(--bg-surface-3);height:1px;margin:4px 0}@keyframes cc-menu-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.chart-card-body{flex:1;padding:4px 12px 8px}.chart-card-foot{align-items:center;background:var(--bg-surface-2);border-radius:0 0 10px 10px;border-top:1px solid var(--border-soft);color:var(--text-muted);display:flex;flex-wrap:wrap;font-size:11px;gap:10px;padding:12px 24px}.chart-card-foot .src{align-items:center;display:flex;gap:4px}.chart-card-foot .src b{color:var(--text-secondary);font-weight:600}.chart-card-foot .dot{background:var(--border-default);border-radius:50%;height:3px;width:3px}.chart-card-foot .updated{color:var(--text-secondary);font-weight:500}.kpi-card{background:var(--bg-surface);border:1px solid var(--border-default);border-radius:8px;box-shadow:0 2px 8px rgba(30,41,59,.06);padding:16px 18px}.kpi-label{color:var(--text-muted);font-size:11px;font-weight:600;letter-spacing:.1em;margin:0 0 6px;text-transform:uppercase}.kpi-value{color:var(--color-primary);font-family:var(--font-serif);font-size:28px;font-weight:700;line-height:1;margin:0}.kpi-value.healthcare{color:var(--color-healthcare)}.kpi-value.discovery{color:var(--color-discovery)}.kpi-value.pharma{color:var(--color-pharma)}.kpi-value.databank{color:var(--color-databank)}.kpi-trend{align-items:center;display:inline-flex;font-size:12px;font-weight:600;gap:4px;margin-top:6px}.kpi-trend i{font-size:11px}.kpi-trend--up{color:var(--color-success)}.kpi-trend--down{color:var(--color-danger)}.kpi-foot,.kpi-trend--flat{color:var(--text-muted)}.kpi-foot{font-size:11px;margin-top:4px}.badge{border-radius:4px;display:inline-block;font-size:10px;font-weight:600;padding:2px 8px}.badge-active{background:var(--color-success-bg);color:var(--color-success)}.badge-pending{background:var(--color-warning-bg);color:var(--color-warning)}.badge-error{background:var(--color-danger-bg);color:var(--color-danger)}.badge-info{background:var(--bg-hover);color:var(--color-primary)}.badge-grey{background:var(--bg-surface-3);color:var(--text-secondary)}table.tk{border-collapse:collapse;font-size:13px;width:100%}.sr-only,table.tk>caption.sr-only{height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px;clip:rect(0,0,0,0);border:0;white-space:nowrap}table.tk caption{caption-side:top;color:var(--text-primary);font-size:var(--font-13);font-weight:var(--weight-bold);padding:0 0 var(--space-8);text-align:left}table.tk th{background:var(--bg-surface-2);border-bottom:1px solid var(--border-default);color:var(--text-secondary);font-size:11px;font-weight:700;letter-spacing:.08em;padding:12px 14px;text-align:left;text-transform:uppercase}table.tk tbody th[scope=row]{background:transparent;font-size:var(--font-13);font-weight:var(--weight-bold);letter-spacing:0;text-transform:none}table.tk tbody th[scope=row],table.tk td{border-bottom:1px solid var(--border-soft);color:var(--text-primary)}table.tk td{padding:12px 14px}table.tk tbody tr:nth-child(2n) td,table.tk tbody tr:nth-child(2n) th[scope=row]{background:var(--bg-surface-2)}table.tk tbody tr:hover td,table.tk tbody tr:hover th[scope=row]{background:var(--bg-hover)}table.tk th[aria-sort]{cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}table.tk th[aria-sort]:hover{color:var(--text-primary)}.tk-wrap{overflow-x:auto}.tk-num{font-variant-numeric:tabular-nums;text-align:right}.nav-group{display:flex;flex-direction:column}.nav-group-header{align-items:center;background:none;border:0;color:var(--text-muted);cursor:pointer;display:flex;font-family:var(--font-sans);font-size:11px;font-weight:700;gap:8px;letter-spacing:.08em;padding:8px 12px;text-align:left;text-transform:uppercase;transition:color var(--duration-fast) var(--ease-out);width:100%}.nav-group-header:hover{color:var(--text-secondary)}.nav-group-header .caret{display:inline-flex;margin-left:auto;transition:transform var(--duration-fast) var(--ease-out)}.nav-group[data-open=true]>.nav-group-header{color:var(--color-primary)}.nav-group[data-open=true]>.nav-group-header .caret{transform:rotate(180deg)}.nav-group-items{display:flex;flex-direction:column;gap:2px;padding:2px 0 8px}.cc-export:focus-visible,.cc-menu-item:focus-visible,.chart-card :focus-visible,.nav-group-header:focus-visible,table.tk th[aria-sort]:focus-visible{box-shadow:var(--shadow-focus);outline:2px solid var(--color-secondary);outline-offset:2px}.cc-menu-item,.nav-group-header{min-height:40px}body.text-large .kpi-label{font-size:13px}body.text-large .kpi-value{font-size:34px}body.text-large .kpi-trend{font-size:14px}body.text-large .kpi-foot{font-size:13px}body.text-large .chart-card-title{font-size:17px}body.text-large .chart-card-context{font-size:14px}body.text-large .chart-card-foot{font-size:12px}body.text-large .badge{font-size:12px;padding:3px 9px}body.text-large table.tk{font-size:15px}body.text-large table.tk th{font-size:13px}body.text-xl .kpi-label{font-size:14px}body.text-xl .kpi-value{font-size:40px}body.text-xl .kpi-trend{font-size:16px}body.text-xl .kpi-foot{font-size:14px}body.text-xl .chart-card-title{font-size:20px}body.text-xl .chart-card-context{font-size:16px}body.text-xl .chart-card-foot{font-size:14px}body.text-xl .badge{font-size:14px;padding:3px 10px}body.text-xl table.tk{font-size:16px}body.text-xl table.tk th{font-size:14px}body.high-contrast .cc-export,body.high-contrast .cc-menu,body.high-contrast .chart-card,body.high-contrast .kpi-card{border-width:2px}body.high-contrast .chart-card:hover{border-color:var(--border-default)}body.rm-switching,body.rm-switching *,body.rm-switching :after,body.rm-switching :before,body.theme-switching,body.theme-switching *,body.theme-switching :after,body.theme-switching :before{transition:none!important}body.high-contrast *{box-shadow:none!important}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--sidebar-w:220px;--sidebar-collapsed-w:56px;--rsidebar-w:280px;--rsidebar-collapsed-w:76px;--topbar-h:56px;--tabs-h:46px;--analysis-header-h:124px;--sourcebar-h:38px;--filterbar-h:56px;--color-primary:#2100ad;--color-primary-hover:#1a0088;--color-secondary:#6b3fff;--color-accent-soft:#b485ff;--color-violet-pale:#d6ccff;--color-healthcare:#4164ee;--color-discovery:#07816f;--color-pharma:#f7520e;--color-databank:#e04380;--color-healthcare-active:#3451d4;--color-discovery-active:#066b5c;--color-pharma-active:#d9470c;--color-databank-active:#c73a6f;--color-pharma-soft:#ff7942;--healthcare-rgb:65,100,238;--discovery-rgb:7,129,111;--pharma-rgb:247,82,14;--databank-rgb:224,67,128;--surface-rgb:255,255,255;--shadow-rgb:30,41,59;--color-accent-teal:#00d4a8;--color-notification:#e59;--color-text-inverse:#fff;--color-success:#16a34a;--color-success-bg:#dcfce7;--color-warning:#d97706;--color-warning-bg:#fef3c7;--color-danger:#dc2626;--color-danger-bg:#fee2e2;--color-info:#4164ee;--color-info-bg:#dbeafe;--bg-app:#eef1f5;--bg-surface:#fff;--bg-surface-2:#fbfbfd;--bg-surface-3:#f5f5f9;--bg-hover:#eef1fe;--border-default:#dbdef0;--border-soft:#f0f1f7;--text-primary:#1e293b;--text-secondary:#525670;--text-muted:#878ca6;--brand-rgb:33,0,173;--chart-cat-1:#2100ad;--chart-cat-2:#00a38e;--chart-cat-3:#e67e22;--chart-cat-4:#d63384;--chart-cat-5:#4164ee;--chart-cat-6:#16a34a;--space-2:2px;--space-4:4px;--space-6:6px;--space-8:8px;--space-12:12px;--space-16:16px;--space-20:20px;--space-24:24px;--space-32:32px;--space-40:40px;--space-48:48px;--radius-sm:4px;--radius-md:6px;--radius-lg:8px;--radius-xl:10px;--radius-2xl:12px;--radius-pill:999px;--font-10:10px;--font-11:11px;--font-12:12px;--font-13:13px;--font-14:14px;--font-16:16px;--font-18:18px;--font-22:22px;--font-24:24px;--font-32:32px;--weight-normal:400;--weight-medium:500;--weight-semibold:600;--weight-bold:700;--font-serif:"Caudex",Georgia,serif;--font-sans:"Figtree",system-ui,sans-serif;--font-mono:"SF Mono",Menlo,monospace;--shadow-xs:0 1px 2px rgba(30,41,59,.04);--shadow-sm:0 2px 6px rgba(30,41,59,.06),0 1px 2px rgba(30,41,59,.03);--shadow-md:0 4px 12px rgba(30,41,59,.06),0 1px 3px rgba(30,41,59,.04);--shadow-lg:0 8px 24px rgba(30,41,59,.12);--shadow-focus:0 0 0 3px rgba(107,63,255,.14);--duration-instant:100ms;--duration-fast:150ms;--duration-base:240ms;--duration-slow:400ms;--duration-slowest:600ms;--ease-out:cubic-bezier(.2,0,0,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--ease-spring:cubic-bezier(.5,1.6,.4,1);--z-base:1;--z-sticky:20;--z-header:30;--z-drawer:40;--z-modal:50;--z-toast:60;--z-help:70}body.night{--color-primary:#9b7cff;--color-secondary:#b485ff;--color-accent-soft:#d6ccff;--color-healthcare:#7aa0ff;--color-discovery:#2ecc71;--color-pharma:#ff8c00;--color-databank:#f472b6;--color-healthcare-active:#4164ee;--color-discovery-active:#07816f;--color-pharma-active:#f7520e;--color-databank-active:#e04380;--healthcare-rgb:122,160,255;--discovery-rgb:46,204,113;--pharma-rgb:255,140,0;--databank-rgb:244,114,182;--surface-rgb:26,26,36;--shadow-rgb:0,0,0;--bg-app:#0e0e14;--bg-surface:#1a1a24;--bg-surface-2:#232330;--bg-surface-3:#2a2a38;--bg-hover:#2d2a42;--border-default:#45455c;--border-soft:#32323f;--text-primary:#f5f6fa;--text-secondary:#cfd3e5;--text-muted:#8a90a8;--brand-rgb:155,124,255;--color-success:#6fe8c5;--color-success-bg:rgba(0,212,168,.18);--color-warning:#fbbf24;--color-warning-bg:rgba(245,158,11,.18);--color-danger:#fca5a5;--color-danger-bg:rgba(239,68,68,.18);--color-info:#7aa0ff;--color-info-bg:rgba(65,100,238,.18);--chart-cat-1:#9b7cff;--chart-cat-2:#6fe8c5;--chart-cat-3:#fbbf24;--chart-cat-4:#f472b6;--chart-cat-5:#7b9ef5;--chart-cat-6:#bef264;background:var(--bg-app);color:var(--text-primary)}body.high-contrast:not(.night){--text-primary:#000;--text-secondary:#1a1a24;--text-muted:#2f2f40;--border-default:#000;--border-soft:#525670;--bg-app:#fff;--bg-surface:#fff;--bg-surface-2:#fff;--bg-surface-3:#f0f1f7;--bg-hover:#ffe56b;--color-primary:#1100a0;--color-primary-hover:#0a0070;--color-secondary:#5028d8;--color-success:#006b2c;--color-warning:#8c4500;--color-danger:#a60000;--color-info:#0040c8}body.night.high-contrast{--text-primary:#fff;--text-secondary:#f5f6fa;--text-muted:#cfd3e5;--border-default:#fff;--border-soft:#b8bcd0;--bg-app:#000;--bg-surface:#000;--bg-surface-2:#000;--bg-surface-3:#000;--bg-hover:#ffe56b;--color-primary:#d6ccff;--color-primary-hover:#fff;--color-secondary:#e5daff;--color-accent-soft:#fff;--color-success:#6fe8c5;--color-warning:#fbbf24;--color-danger:#fca5a5;--color-info:#7aa0ff;--brand-rgb:214,204,255}body.reduce-motion *,body.reduce-motion :after,body.reduce-motion :before{animation:none!important;scroll-behavior:auto!important;transition:none!important}:root{--r-color-primary-50:#f0f4ff;--r-color-primary-100:#dce5fd;--r-color-primary-200:#b9cbfb;--r-color-primary-300:#96b0f9;--r-color-primary-400:#7395f5;--r-color-primary-500:#5a7ef2;--r-color-primary-600:var(--color-healthcare);--r-color-primary-700:#3451d4;--r-color-primary-800:#283fb0;--r-color-primary-900:#1c2d8a;--r-color-gray-50:#f9fafb;--r-color-gray-100:#f3f4f6;--r-color-gray-200:#e5e7eb;--r-color-gray-300:#d1d5db;--r-color-gray-400:#9ca3af;--r-color-gray-500:#6b7280;--r-color-gray-600:#4b5563;--r-color-gray-700:#374151;--r-color-gray-800:#1f2937;--r-color-gray-900:#111827;--r-color-gray-950:#030712;--r-color-success-500:var(--color-success);--r-color-success-600:#16a34a;--r-color-warning-500:#f59e0b;--r-color-warning-600:var(--color-warning);--r-color-danger-500:#ef4444;--r-color-danger-600:var(--color-danger);--r-color-white:#fff;--r-color-black:#000;--r-font-family:var(--font-sans);--r-font-mono:var(--font-mono);--r-text-xs:0.75rem;--r-text-sm:0.875rem;--r-text-base:1rem;--r-text-lg:1.125rem;--r-text-xl:1.25rem;--r-text-2xl:1.5rem;--r-text-3xl:1.875rem;--r-text-4xl:2.25rem;--r-font-weight-normal:var(--weight-normal);--r-font-weight-medium:var(--weight-medium);--r-font-weight-semibold:var(--weight-semibold);--r-font-weight-bold:var(--weight-bold);--r-leading-tight:1.25;--r-leading-normal:1.5;--r-leading-relaxed:1.75;--r-space-0:0;--r-space-1:var(--space-4);--r-space-2:var(--space-8);--r-space-3:var(--space-12);--r-space-4:var(--space-16);--r-space-5:var(--space-20);--r-space-6:var(--space-24);--r-space-8:var(--space-32);--r-space-10:var(--space-40);--r-space-12:var(--space-48);--r-radius-none:0;--r-radius-sm:var(--radius-sm);--r-radius-md:var(--radius-md);--r-radius-lg:var(--radius-lg);--r-radius-xl:0.75rem;--r-radius-2xl:1rem;--r-radius-full:var(--radius-pill);--r-shadow-xs:0 1px 2px 0 rgba(0,0,0,.05);--r-shadow-sm:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--r-shadow-md:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--r-shadow-lg:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--r-shadow-xl:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--r-transition-fast:var(--duration-fast) var(--ease-in-out);--r-transition-base:200ms var(--ease-in-out);--r-transition-slow:var(--duration-slow) var(--ease-in-out)}
|
|
1
|
+
:root{--sidebar-w:220px;--sidebar-collapsed-w:56px;--rsidebar-w:280px;--rsidebar-collapsed-w:76px;--topbar-h:56px;--topbar-merged-h:0px;--tabs-h:46px;--analysis-header-h:124px;--sourcebar-h:38px;--filterbar-h:56px;--color-primary:#2100ad;--color-primary-hover:#1a0088;--color-secondary:#6b3fff;--color-accent-soft:#b485ff;--color-violet-pale:#d6ccff;--color-healthcare:#4164ee;--color-discovery:#07816f;--color-pharma:#f7520e;--color-databank:#e04380;--color-healthcare-active:#3451d4;--color-discovery-active:#066b5c;--color-pharma-active:#d9470c;--color-databank-active:#c73a6f;--color-pharma-soft:#ff7942;--healthcare-rgb:65,100,238;--discovery-rgb:7,129,111;--pharma-rgb:247,82,14;--databank-rgb:224,67,128;--surface-rgb:255,255,255;--shadow-rgb:30,41,59;--color-accent-teal:#00d4a8;--color-notification:#e59;--color-text-inverse:#fff;--color-success:#16a34a;--color-success-bg:#dcfce7;--color-warning:#d97706;--color-warning-bg:#fef3c7;--color-danger:#dc2626;--color-danger-bg:#fee2e2;--color-info:#4164ee;--color-info-bg:#dbeafe;--bg-app:#eef1f5;--bg-surface:#fff;--bg-surface-2:#fbfbfd;--bg-surface-3:#f5f5f9;--bg-hover:#eef1fe;--border-default:#dbdef0;--border-soft:#f0f1f7;--text-primary:#1e293b;--text-secondary:#525670;--text-muted:#878ca6;--brand-rgb:33,0,173;--chart-cat-1:#2100ad;--chart-cat-2:#00a38e;--chart-cat-3:#e67e22;--chart-cat-4:#d63384;--chart-cat-5:#4164ee;--chart-cat-6:#16a34a;--space-2:2px;--space-4:4px;--space-6:6px;--space-8:8px;--space-12:12px;--space-16:16px;--space-20:20px;--space-24:24px;--space-32:32px;--space-40:40px;--space-48:48px;--radius-sm:4px;--radius-md:6px;--radius-lg:8px;--radius-xl:10px;--radius-2xl:12px;--radius-pill:999px;--font-10:10px;--font-11:11px;--font-12:12px;--font-13:13px;--font-14:14px;--font-16:16px;--font-18:18px;--font-22:22px;--font-24:24px;--font-32:32px;--weight-normal:400;--weight-medium:500;--weight-semibold:600;--weight-bold:700;--font-serif:"Caudex",Georgia,serif;--font-sans:"Figtree",system-ui,sans-serif;--font-mono:"SF Mono",Menlo,monospace;--shadow-xs:0 1px 2px rgba(30,41,59,.04);--shadow-sm:0 2px 6px rgba(30,41,59,.06),0 1px 2px rgba(30,41,59,.03);--shadow-md:0 4px 12px rgba(30,41,59,.06),0 1px 3px rgba(30,41,59,.04);--shadow-lg:0 8px 24px rgba(30,41,59,.12);--shadow-focus:0 0 0 3px rgba(107,63,255,.14);--duration-instant:100ms;--duration-fast:150ms;--duration-base:240ms;--duration-slow:400ms;--duration-slowest:600ms;--ease-out:cubic-bezier(.2,0,0,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--ease-spring:cubic-bezier(.5,1.6,.4,1);--z-base:1;--z-sticky:20;--z-header:30;--z-drawer:40;--z-modal:50;--z-toast:60;--z-help:70}body.night{--color-primary:#9b7cff;--color-secondary:#b485ff;--color-accent-soft:#d6ccff;--color-healthcare:#7aa0ff;--color-discovery:#2ecc71;--color-pharma:#ff8c00;--color-databank:#f472b6;--color-healthcare-active:#4164ee;--color-discovery-active:#07816f;--color-pharma-active:#f7520e;--color-databank-active:#e04380;--healthcare-rgb:122,160,255;--discovery-rgb:46,204,113;--pharma-rgb:255,140,0;--databank-rgb:244,114,182;--surface-rgb:26,26,36;--shadow-rgb:0,0,0;--bg-app:#0e0e14;--bg-surface:#1a1a24;--bg-surface-2:#232330;--bg-surface-3:#2a2a38;--bg-hover:#2d2a42;--border-default:#45455c;--border-soft:#32323f;--text-primary:#f5f6fa;--text-secondary:#cfd3e5;--text-muted:#8a90a8;--brand-rgb:155,124,255;--color-success:#6fe8c5;--color-success-bg:rgba(0,212,168,.18);--color-warning:#fbbf24;--color-warning-bg:rgba(245,158,11,.18);--color-danger:#fca5a5;--color-danger-bg:rgba(239,68,68,.18);--color-info:#7aa0ff;--color-info-bg:rgba(65,100,238,.18);--chart-cat-1:#9b7cff;--chart-cat-2:#6fe8c5;--chart-cat-3:#fbbf24;--chart-cat-4:#f472b6;--chart-cat-5:#7b9ef5;--chart-cat-6:#bef264;background:var(--bg-app);color:var(--text-primary)}body.high-contrast:not(.night){--text-primary:#000;--text-secondary:#1a1a24;--text-muted:#2f2f40;--border-default:#000;--border-soft:#525670;--bg-app:#fff;--bg-surface:#fff;--bg-surface-2:#fff;--bg-surface-3:#f0f1f7;--bg-hover:#ffe56b;--color-primary:#1100a0;--color-primary-hover:#0a0070;--color-secondary:#5028d8;--color-success:#006b2c;--color-warning:#8c4500;--color-danger:#a60000;--color-info:#0040c8}body.night.high-contrast{--text-primary:#fff;--text-secondary:#f5f6fa;--text-muted:#cfd3e5;--border-default:#fff;--border-soft:#b8bcd0;--bg-app:#000;--bg-surface:#000;--bg-surface-2:#000;--bg-surface-3:#000;--bg-hover:#ffe56b;--color-primary:#d6ccff;--color-primary-hover:#fff;--color-secondary:#e5daff;--color-accent-soft:#fff;--color-success:#6fe8c5;--color-warning:#fbbf24;--color-danger:#fca5a5;--color-info:#7aa0ff;--brand-rgb:214,204,255}body.reduce-motion *,body.reduce-motion :after,body.reduce-motion :before{animation:none!important;scroll-behavior:auto!important;transition:none!important}:root{--r-color-primary-50:#f0f4ff;--r-color-primary-100:#dce5fd;--r-color-primary-200:#b9cbfb;--r-color-primary-300:#96b0f9;--r-color-primary-400:#7395f5;--r-color-primary-500:#5a7ef2;--r-color-primary-600:var(--color-healthcare);--r-color-primary-700:#3451d4;--r-color-primary-800:#283fb0;--r-color-primary-900:#1c2d8a;--r-color-gray-50:#f9fafb;--r-color-gray-100:#f3f4f6;--r-color-gray-200:#e5e7eb;--r-color-gray-300:#d1d5db;--r-color-gray-400:#9ca3af;--r-color-gray-500:#6b7280;--r-color-gray-600:#4b5563;--r-color-gray-700:#374151;--r-color-gray-800:#1f2937;--r-color-gray-900:#111827;--r-color-gray-950:#030712;--r-color-success-500:var(--color-success);--r-color-success-600:#16a34a;--r-color-warning-500:#f59e0b;--r-color-warning-600:var(--color-warning);--r-color-danger-500:#ef4444;--r-color-danger-600:var(--color-danger);--r-color-white:#fff;--r-color-black:#000;--r-font-family:var(--font-sans);--r-font-mono:var(--font-mono);--r-text-xs:0.75rem;--r-text-sm:0.875rem;--r-text-base:1rem;--r-text-lg:1.125rem;--r-text-xl:1.25rem;--r-text-2xl:1.5rem;--r-text-3xl:1.875rem;--r-text-4xl:2.25rem;--r-font-weight-normal:var(--weight-normal);--r-font-weight-medium:var(--weight-medium);--r-font-weight-semibold:var(--weight-semibold);--r-font-weight-bold:var(--weight-bold);--r-leading-tight:1.25;--r-leading-normal:1.5;--r-leading-relaxed:1.75;--r-space-0:0;--r-space-1:var(--space-4);--r-space-2:var(--space-8);--r-space-3:var(--space-12);--r-space-4:var(--space-16);--r-space-5:var(--space-20);--r-space-6:var(--space-24);--r-space-8:var(--space-32);--r-space-10:var(--space-40);--r-space-12:var(--space-48);--r-radius-none:0;--r-radius-sm:var(--radius-sm);--r-radius-md:var(--radius-md);--r-radius-lg:var(--radius-lg);--r-radius-xl:0.75rem;--r-radius-2xl:1rem;--r-radius-full:var(--radius-pill);--r-shadow-xs:0 1px 2px 0 rgba(0,0,0,.05);--r-shadow-sm:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--r-shadow-md:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--r-shadow-lg:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--r-shadow-xl:0 20px 25px -5px rgba(0,0,0,.1),0 8px 10px -6px rgba(0,0,0,.1);--r-transition-fast:var(--duration-fast) var(--ease-in-out);--r-transition-base:200ms var(--ease-in-out);--r-transition-slow:var(--duration-slow) var(--ease-in-out)}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
export interface AiChatMessage {
|
|
3
|
+
id: string
|
|
4
|
+
role: 'user' | 'assistant'
|
|
5
|
+
content: string
|
|
6
|
+
timestamp?: Date
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface AiChatSuggestion {
|
|
10
|
+
icon?: string
|
|
11
|
+
label: string
|
|
12
|
+
message: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface RmAiChatProps {
|
|
16
|
+
/** Whether the chat drawer is open */
|
|
17
|
+
modelValue: boolean
|
|
18
|
+
/** Chat title displayed in the header */
|
|
19
|
+
title?: string
|
|
20
|
+
/** Emoji or text icon for the header */
|
|
21
|
+
icon?: string
|
|
22
|
+
/** Input placeholder text */
|
|
23
|
+
placeholder?: string
|
|
24
|
+
/** Suggestion buttons displayed on empty state */
|
|
25
|
+
suggestions?: AiChatSuggestion[]
|
|
26
|
+
/** Chat messages */
|
|
27
|
+
messages?: AiChatMessage[]
|
|
28
|
+
/** Whether the assistant is currently responding */
|
|
29
|
+
loading?: boolean
|
|
30
|
+
/** Loading indicator text */
|
|
31
|
+
loadingText?: string
|
|
32
|
+
/** Welcome message displayed when no messages */
|
|
33
|
+
welcomeMessage?: string
|
|
34
|
+
/** Drawer size */
|
|
35
|
+
drawerSize?: 'sm' | 'md' | 'lg' | 'xl'
|
|
36
|
+
/** Show the floating trigger button */
|
|
37
|
+
showTrigger?: boolean
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const props = withDefaults(defineProps<RmAiChatProps>(), {
|
|
41
|
+
title: 'AI Assistant',
|
|
42
|
+
icon: '',
|
|
43
|
+
placeholder: 'Type a message...',
|
|
44
|
+
suggestions: () => [],
|
|
45
|
+
messages: () => [],
|
|
46
|
+
loading: false,
|
|
47
|
+
loadingText: 'Thinking...',
|
|
48
|
+
welcomeMessage: 'Hello! How can I help you today?',
|
|
49
|
+
drawerSize: 'md',
|
|
50
|
+
showTrigger: true,
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
const emit = defineEmits<{
|
|
54
|
+
'update:modelValue': [value: boolean]
|
|
55
|
+
'send': [message: string]
|
|
56
|
+
'clear': []
|
|
57
|
+
}>()
|
|
58
|
+
|
|
59
|
+
const inputValue = ref('')
|
|
60
|
+
const messagesContainer = ref<HTMLElement | null>(null)
|
|
61
|
+
|
|
62
|
+
function open() {
|
|
63
|
+
emit('update:modelValue', true)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function close() {
|
|
67
|
+
emit('update:modelValue', false)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function toggle() {
|
|
71
|
+
emit('update:modelValue', !props.modelValue)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function handleSubmit() {
|
|
75
|
+
if (!inputValue.value.trim() || props.loading) return
|
|
76
|
+
const message = inputValue.value
|
|
77
|
+
inputValue.value = ''
|
|
78
|
+
emit('send', message)
|
|
79
|
+
scrollToBottom()
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function handleSuggestion(suggestion: AiChatSuggestion) {
|
|
83
|
+
emit('send', suggestion.message)
|
|
84
|
+
scrollToBottom()
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function handleClear() {
|
|
88
|
+
emit('clear')
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function scrollToBottom() {
|
|
92
|
+
nextTick(() => {
|
|
93
|
+
if (messagesContainer.value) {
|
|
94
|
+
messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Scroll to bottom when drawer opens or new messages arrive
|
|
100
|
+
watch(() => props.modelValue, (open) => {
|
|
101
|
+
if (open) scrollToBottom()
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
watch(() => props.messages.length, () => {
|
|
105
|
+
scrollToBottom()
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
// Simple markdown renderer
|
|
109
|
+
function renderMarkdown(text: string): string {
|
|
110
|
+
if (!text) return ''
|
|
111
|
+
return text
|
|
112
|
+
.replace(/&/g, '&')
|
|
113
|
+
.replace(/</g, '<')
|
|
114
|
+
.replace(/>/g, '>')
|
|
115
|
+
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
|
116
|
+
.replace(/\*(.+?)\*/g, '<em>$1</em>')
|
|
117
|
+
.replace(/^(\d+)\.\s+(.+)$/gm, '<li class="rm-ai-chat-numbered">$2</li>')
|
|
118
|
+
.replace(/^[-*]\s+(.+)$/gm, '<li class="rm-ai-chat-bullet">$1</li>')
|
|
119
|
+
.replace(/((?:<li class="rm-ai-chat-numbered">.*?<\/li>)+)/g, '<ol>$1</ol>')
|
|
120
|
+
.replace(/((?:<li class="rm-ai-chat-bullet">.*?<\/li>)+)/g, '<ul>$1</ul>')
|
|
121
|
+
.replace(/\n/g, '<br>')
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Close on Escape
|
|
125
|
+
onMounted(() => {
|
|
126
|
+
const handleEscape = (e: KeyboardEvent) => {
|
|
127
|
+
if (e.key === 'Escape' && props.modelValue) {
|
|
128
|
+
close()
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
document.addEventListener('keydown', handleEscape)
|
|
132
|
+
onUnmounted(() => {
|
|
133
|
+
document.removeEventListener('keydown', handleEscape)
|
|
134
|
+
})
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
defineExpose({ open, close, toggle, scrollToBottom })
|
|
138
|
+
</script>
|
|
139
|
+
|
|
140
|
+
<template>
|
|
141
|
+
<!-- Floating trigger button -->
|
|
142
|
+
<button
|
|
143
|
+
v-if="showTrigger"
|
|
144
|
+
class="rm-ai-chat-trigger"
|
|
145
|
+
:class="{ 'rm-ai-chat-trigger--open': modelValue }"
|
|
146
|
+
@click="toggle"
|
|
147
|
+
>
|
|
148
|
+
<slot name="trigger">
|
|
149
|
+
<RmIcon name="Robot" :size="24" weight="duotone" />
|
|
150
|
+
</slot>
|
|
151
|
+
</button>
|
|
152
|
+
|
|
153
|
+
<!-- Chat Drawer -->
|
|
154
|
+
<RmDrawer
|
|
155
|
+
:model-value="modelValue"
|
|
156
|
+
:size="drawerSize"
|
|
157
|
+
side="right"
|
|
158
|
+
@update:model-value="emit('update:modelValue', $event)"
|
|
159
|
+
>
|
|
160
|
+
<template #header>
|
|
161
|
+
<div class="rm-ai-chat-header">
|
|
162
|
+
<span v-if="icon" class="rm-ai-chat-header__icon">{{ icon }}</span>
|
|
163
|
+
<RmIcon v-else name="Robot" :size="22" weight="duotone" class="rm-ai-chat-header__robot" />
|
|
164
|
+
<h3 class="rm-ai-chat-header__title">{{ title }}</h3>
|
|
165
|
+
</div>
|
|
166
|
+
<button class="rm-ai-chat-header__clear" @click="handleClear" title="Clear chat">
|
|
167
|
+
<RmIcon name="Trash" :size="16" />
|
|
168
|
+
</button>
|
|
169
|
+
</template>
|
|
170
|
+
|
|
171
|
+
<div class="rm-ai-chat-body">
|
|
172
|
+
<div ref="messagesContainer" class="rm-ai-chat-messages">
|
|
173
|
+
<!-- Welcome state -->
|
|
174
|
+
<div v-if="messages.length === 0" class="rm-ai-chat-welcome">
|
|
175
|
+
<div class="rm-ai-chat-message rm-ai-chat-message--assistant rm-ai-chat-message--welcome">
|
|
176
|
+
<div class="rm-ai-chat-avatar rm-ai-chat-avatar--assistant">
|
|
177
|
+
<RmIcon name="Robot" :size="18" weight="duotone" />
|
|
178
|
+
</div>
|
|
179
|
+
<div class="rm-ai-chat-bubble rm-ai-chat-bubble--assistant rm-ai-chat-bubble--welcome">
|
|
180
|
+
<slot name="welcome">
|
|
181
|
+
{{ welcomeMessage }}
|
|
182
|
+
</slot>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
|
|
186
|
+
<div v-if="suggestions.length" class="rm-ai-chat-suggestions">
|
|
187
|
+
<p class="rm-ai-chat-suggestions__hint">Try asking:</p>
|
|
188
|
+
<button
|
|
189
|
+
v-for="(suggestion, i) in suggestions"
|
|
190
|
+
:key="i"
|
|
191
|
+
class="rm-ai-chat-suggestion"
|
|
192
|
+
@click="handleSuggestion(suggestion)"
|
|
193
|
+
>
|
|
194
|
+
<span v-if="suggestion.icon" class="rm-ai-chat-suggestion__icon">{{ suggestion.icon }}</span>
|
|
195
|
+
{{ suggestion.label }}
|
|
196
|
+
</button>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
<!-- Messages -->
|
|
201
|
+
<div
|
|
202
|
+
v-for="message in messages"
|
|
203
|
+
:key="message.id"
|
|
204
|
+
class="rm-ai-chat-message"
|
|
205
|
+
:class="`rm-ai-chat-message--${message.role}`"
|
|
206
|
+
>
|
|
207
|
+
<div class="rm-ai-chat-avatar" :class="`rm-ai-chat-avatar--${message.role}`">
|
|
208
|
+
<RmIcon v-if="message.role === 'assistant'" name="Robot" :size="18" weight="duotone" />
|
|
209
|
+
<RmIcon v-else name="User" :size="18" />
|
|
210
|
+
</div>
|
|
211
|
+
<div class="rm-ai-chat-bubble" :class="`rm-ai-chat-bubble--${message.role}`">
|
|
212
|
+
<div v-html="renderMarkdown(message.content)" />
|
|
213
|
+
<slot name="message-footer" :message="message" />
|
|
214
|
+
</div>
|
|
215
|
+
</div>
|
|
216
|
+
|
|
217
|
+
<!-- Loading indicator -->
|
|
218
|
+
<div v-if="loading" class="rm-ai-chat-message rm-ai-chat-message--assistant">
|
|
219
|
+
<div class="rm-ai-chat-avatar rm-ai-chat-avatar--assistant">
|
|
220
|
+
<RmIcon name="Robot" :size="18" weight="duotone" />
|
|
221
|
+
</div>
|
|
222
|
+
<div class="rm-ai-chat-bubble rm-ai-chat-bubble--assistant">
|
|
223
|
+
<div class="rm-ai-chat-loading">
|
|
224
|
+
<span class="rm-ai-chat-loading__pulse" />
|
|
225
|
+
<RmIcon name="CircleNotch" :size="16" class="rm-ai-chat-loading__icon" />
|
|
226
|
+
<span class="rm-ai-chat-loading__text">{{ loadingText }}</span>
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
|
|
233
|
+
<template #footer>
|
|
234
|
+
<form class="rm-ai-chat-input" @submit.prevent="handleSubmit">
|
|
235
|
+
<div class="rm-ai-chat-input__wrapper">
|
|
236
|
+
<input
|
|
237
|
+
v-model="inputValue"
|
|
238
|
+
type="text"
|
|
239
|
+
:placeholder="placeholder"
|
|
240
|
+
:disabled="loading"
|
|
241
|
+
@keydown.enter.prevent="handleSubmit"
|
|
242
|
+
/>
|
|
243
|
+
<button type="submit" :disabled="loading || !inputValue.trim()" class="rm-ai-chat-input__send">
|
|
244
|
+
<RmIcon name="PaperPlaneRight" :size="18" weight="fill" />
|
|
245
|
+
</button>
|
|
246
|
+
</div>
|
|
247
|
+
</form>
|
|
248
|
+
</template>
|
|
249
|
+
</RmDrawer>
|
|
250
|
+
</template>
|
|
251
|
+
|
|
252
|
+
<style scoped>
|
|
253
|
+
.rm-ai-chat-trigger{align-items:center;background:linear-gradient(135deg,var(--r-color-primary-500) 0,var(--r-color-primary-600) 100%);border:none;border-radius:var(--r-radius-full);bottom:24px;box-shadow:var(--r-shadow-lg);color:var(--r-color-white);cursor:pointer;display:flex;height:52px;justify-content:center;position:fixed;right:24px;transition:all var(--r-transition-base);width:52px;z-index:89}.rm-ai-chat-trigger:hover{box-shadow:var(--r-shadow-xl);transform:scale(1.08)}.rm-ai-chat-trigger--open{opacity:.7;transform:scale(.9)}.rm-ai-chat-header{align-items:center;display:flex;gap:10px}.rm-ai-chat-header__icon{font-size:22px}.rm-ai-chat-header__robot{color:var(--r-color-primary-500)}.rm-ai-chat-header__title{color:var(--r-color-gray-900);font-size:var(--r-text-lg);font-weight:var(--r-font-weight-semibold);margin:0}.rm-ai-chat-header__clear{align-items:center;background:none;border:none;border-radius:var(--r-radius-md);color:var(--r-color-gray-400);cursor:pointer;display:flex;height:32px;justify-content:center;margin-right:8px;transition:all var(--r-transition-fast);width:32px}.rm-ai-chat-header__clear:hover{background-color:var(--r-color-gray-100);color:var(--r-color-gray-600)}.rm-ai-chat-body{display:flex;flex-direction:column;height:100%;margin:-24px}.rm-ai-chat-messages{background-color:var(--r-color-gray-50);display:flex;flex:1;flex-direction:column;gap:16px;overflow-y:auto;padding:20px}.rm-ai-chat-welcome{display:flex;flex-direction:column;gap:20px}.rm-ai-chat-bubble--welcome{background:linear-gradient(135deg,#f0f9ff,#e0f2fe)!important;border:1px solid #bae6fd}.rm-ai-chat-suggestions{align-items:center;display:flex;flex-direction:column;gap:8px}.rm-ai-chat-suggestions__hint{color:var(--r-color-gray-400);font-size:var(--r-text-xs);font-weight:var(--r-font-weight-medium);margin:0}.rm-ai-chat-suggestion{align-items:center;background:var(--r-color-white);border:1px solid var(--r-color-gray-200);border-radius:var(--r-radius-lg);color:var(--r-color-gray-600);cursor:pointer;display:flex;font-size:var(--r-text-sm);gap:8px;padding:10px 14px;text-align:left;transition:all var(--r-transition-fast);width:100%}.rm-ai-chat-suggestion:hover{background:var(--r-color-gray-50);border-color:var(--r-color-primary-400);color:var(--r-color-primary-600);transform:translateX(4px)}.rm-ai-chat-suggestion__icon{flex-shrink:0}.rm-ai-chat-message{animation:rm-ai-chat-fade-in .2s ease;display:flex;gap:10px}.rm-ai-chat-message--user{flex-direction:row-reverse}@keyframes rm-ai-chat-fade-in{0%{opacity:0;transform:translateY(6px)}to{opacity:1;transform:translateY(0)}}.rm-ai-chat-avatar{align-items:center;border-radius:var(--r-radius-full);display:flex;flex-shrink:0;height:32px;justify-content:center;width:32px}.rm-ai-chat-avatar--assistant{background:var(--r-color-primary-50);color:var(--r-color-primary-500)}.rm-ai-chat-avatar--user{background:linear-gradient(135deg,var(--r-color-primary-500) 0,var(--r-color-primary-600) 100%);color:var(--r-color-white)}.rm-ai-chat-bubble{border-radius:16px;font-size:var(--r-text-sm);line-height:var(--r-leading-relaxed);max-width:80%;padding:10px 14px}.rm-ai-chat-bubble--user{background:linear-gradient(135deg,var(--r-color-primary-500) 0,var(--r-color-primary-600) 100%);border-bottom-right-radius:4px;color:var(--r-color-white)}.rm-ai-chat-bubble--assistant{background:var(--r-color-white);border-bottom-left-radius:4px;box-shadow:0 1px 3px rgba(0,0,0,.06);color:var(--r-color-gray-700)}.rm-ai-chat-bubble :deep(ol),.rm-ai-chat-bubble :deep(ul){margin:6px 0;padding-left:20px}.rm-ai-chat-bubble :deep(li){margin:3px 0}.rm-ai-chat-bubble :deep(ol){list-style-type:decimal}.rm-ai-chat-bubble :deep(ul){list-style-type:disc}.rm-ai-chat-bubble :deep(strong){font-weight:var(--r-font-weight-semibold)}.rm-ai-chat-loading{align-items:center;display:flex;gap:8px;padding:2px 0}.rm-ai-chat-loading__pulse{animation:rm-ai-chat-pulse 2.5s ease-in-out infinite;background:rgba(99,102,241,.08);border-radius:var(--r-radius-full);height:28px;position:absolute;width:28px}.rm-ai-chat-loading__icon{animation:rm-ai-chat-spin 1.2s linear infinite;color:var(--r-color-primary-500);z-index:1}.rm-ai-chat-loading__text{color:var(--r-color-gray-500);font-size:var(--r-text-sm);font-weight:var(--r-font-weight-medium)}@keyframes rm-ai-chat-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes rm-ai-chat-pulse{0%,to{opacity:.4;transform:scale(.8)}50%{opacity:0;transform:scale(1.3)}}.rm-ai-chat-input{margin:0}.rm-ai-chat-input__wrapper{align-items:center;background:var(--r-color-gray-100);border-radius:var(--r-radius-lg);display:flex;gap:8px;padding:4px 4px 4px 16px}.rm-ai-chat-input__wrapper input{background:none;border:none;color:var(--r-color-gray-800);flex:1;font-family:inherit;font-size:var(--r-text-sm);outline:none;padding:10px 0}.rm-ai-chat-input__wrapper input::-moz-placeholder{color:var(--r-color-gray-400)}.rm-ai-chat-input__wrapper input::placeholder{color:var(--r-color-gray-400)}.rm-ai-chat-input__send{align-items:center;background:linear-gradient(135deg,var(--r-color-primary-500) 0,var(--r-color-primary-600) 100%);border:none;border-radius:var(--r-radius-md);color:var(--r-color-white);cursor:pointer;display:flex;flex-shrink:0;height:38px;justify-content:center;transition:all var(--r-transition-fast);width:38px}.rm-ai-chat-input__send:hover:not(:disabled){transform:scale(1.05)}.rm-ai-chat-input__send:disabled{cursor:not-allowed;opacity:.5}
|
|
254
|
+
</style>
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
RmAppShell - le chrome d'application du design system : barre laterale fixe
|
|
3
|
+
a gauche, strip d'actions fixe a droite, contenu decale entre les deux.
|
|
4
|
+
|
|
5
|
+
Structure et classes reprises de `app-shell.html`. La regle n°0 du skill est
|
|
6
|
+
de ne jamais reconstruire ce chrome de memoire : ce composant ne fait que
|
|
7
|
+
poser le markup attendu et gerer l'etat de repli.
|
|
8
|
+
|
|
9
|
+
Le decalage vit sur `body.rm-shell`, pose au montage et retire au demontage.
|
|
10
|
+
Sans ce retrait, une app multi-layout garderait le decalage sur ses autres
|
|
11
|
+
ecrans apres avoir quitte celui-ci.
|
|
12
|
+
-->
|
|
13
|
+
<script setup lang="ts">
|
|
14
|
+
import { onBeforeUnmount, onMounted, ref } from 'vue'
|
|
15
|
+
import { rmWithoutTransitions } from '../utils/transitionGuard'
|
|
16
|
+
|
|
17
|
+
const props = withDefaults(defineProps<{
|
|
18
|
+
/** Barre laterale repliee au chargement. */
|
|
19
|
+
navCollapsed?: boolean
|
|
20
|
+
}>(), { navCollapsed: false })
|
|
21
|
+
|
|
22
|
+
const collapsed = ref(props.navCollapsed)
|
|
23
|
+
const stripOpen = ref(false)
|
|
24
|
+
|
|
25
|
+
function sync() {
|
|
26
|
+
if (typeof document === 'undefined') return
|
|
27
|
+
const { body } = document
|
|
28
|
+
body.classList.add('rm-shell')
|
|
29
|
+
body.classList.toggle('lcollapsed', collapsed.value)
|
|
30
|
+
body.classList.toggle('ropen', stripOpen.value)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
onMounted(sync)
|
|
34
|
+
|
|
35
|
+
onBeforeUnmount(() => {
|
|
36
|
+
if (typeof document === 'undefined') return
|
|
37
|
+
document.body.classList.remove('rm-shell', 'lcollapsed', 'ropen')
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
// Sans la garde, replier la barre laterale ne fait rien : sa largeur vient
|
|
41
|
+
// d'un `var()` et la propriete est sous transition (cf. utils/transitionGuard).
|
|
42
|
+
function toggleNav() {
|
|
43
|
+
rmWithoutTransitions(() => {
|
|
44
|
+
collapsed.value = !collapsed.value
|
|
45
|
+
sync()
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
function setStrip(open: boolean) {
|
|
49
|
+
rmWithoutTransitions(() => {
|
|
50
|
+
stripOpen.value = open
|
|
51
|
+
sync()
|
|
52
|
+
})
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
defineExpose({ collapsed, stripOpen, toggleNav, setStrip })
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<template>
|
|
59
|
+
<div class="rm-app-shell">
|
|
60
|
+
<slot name="nav" :collapsed="collapsed" :toggle="toggleNav" />
|
|
61
|
+
<slot name="strip" :open="stripOpen" :set-open="setStrip" />
|
|
62
|
+
<slot />
|
|
63
|
+
</div>
|
|
64
|
+
</template>
|
|
65
|
+
|
|
66
|
+
<style scoped>
|
|
67
|
+
.rm-app-shell{display:contents}
|
|
68
|
+
</style>
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* HybridTable — a table with inline horizontal bars behind values.
|
|
4
|
+
* Each row shows a label, a value, and a bar proportional to the max value.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface HybridTableRow {
|
|
8
|
+
label: string
|
|
9
|
+
value: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const props = withDefaults(defineProps<{
|
|
13
|
+
rows: HybridTableRow[]
|
|
14
|
+
title?: string
|
|
15
|
+
color?: string
|
|
16
|
+
maxVisible?: number
|
|
17
|
+
valueFormatter?: (val: number) => string
|
|
18
|
+
}>(), {
|
|
19
|
+
title: undefined,
|
|
20
|
+
color: '#4164EE',
|
|
21
|
+
maxVisible: 10,
|
|
22
|
+
valueFormatter: (val: number) => val.toLocaleString(),
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
const showAll = ref(false)
|
|
26
|
+
|
|
27
|
+
const maxValue = computed(() => Math.max(...props.rows.map(r => r.value), 1))
|
|
28
|
+
|
|
29
|
+
const visibleRows = computed(() => {
|
|
30
|
+
if (showAll.value) return props.rows
|
|
31
|
+
return props.rows.slice(0, props.maxVisible)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const hasMore = computed(() => props.rows.length > props.maxVisible)
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<template>
|
|
38
|
+
<div class="hybrid-table">
|
|
39
|
+
<h3 v-if="title" class="hybrid-table__title">{{ title }}</h3>
|
|
40
|
+
|
|
41
|
+
<div class="hybrid-table__list">
|
|
42
|
+
<div
|
|
43
|
+
v-for="(row, idx) in visibleRows"
|
|
44
|
+
:key="idx"
|
|
45
|
+
class="hybrid-table__row"
|
|
46
|
+
>
|
|
47
|
+
<span class="hybrid-table__label">{{ row.label }}</span>
|
|
48
|
+
<div class="hybrid-table__bar-wrapper">
|
|
49
|
+
<div
|
|
50
|
+
class="hybrid-table__bar"
|
|
51
|
+
:style="{ width: `${(row.value / maxValue) * 100}%`, backgroundColor: color }"
|
|
52
|
+
/>
|
|
53
|
+
</div>
|
|
54
|
+
<span class="hybrid-table__value">{{ valueFormatter(row.value) }}</span>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<button
|
|
59
|
+
v-if="hasMore"
|
|
60
|
+
class="hybrid-table__toggle"
|
|
61
|
+
@click="showAll = !showAll"
|
|
62
|
+
>
|
|
63
|
+
{{ showAll ? 'Show less' : `Show all (${rows.length})` }}
|
|
64
|
+
</button>
|
|
65
|
+
</div>
|
|
66
|
+
</template>
|
|
67
|
+
|
|
68
|
+
<style scoped>
|
|
69
|
+
.hybrid-table{font-family:var(--r-font-family)}.hybrid-table__title{color:var(--r-color-gray-700);font-size:14px;font-weight:600;margin:0 0 12px}.hybrid-table__list{display:flex;flex-direction:column;gap:6px}.hybrid-table__row{align-items:center;display:flex;gap:12px;padding:6px 0}.hybrid-table__label{color:var(--r-color-gray-700);flex-shrink:0;font-size:13px;min-width:140px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.hybrid-table__bar-wrapper{background:var(--r-color-gray-50);border-radius:4px;flex:1;height:20px;overflow:hidden}.hybrid-table__bar{border-radius:4px;height:100%;min-width:2px;transition:width .4s ease}.hybrid-table__value{color:var(--r-color-gray-900);flex-shrink:0;font-size:13px;font-weight:600;min-width:50px;text-align:right}.hybrid-table__toggle{background:none;border:none;color:#4164ee;cursor:pointer;font-family:var(--r-font-family);font-size:13px;margin-top:8px;padding:0;text-decoration:underline}.hybrid-table__toggle:hover{color:#3451d4}
|
|
70
|
+
</style>
|
|
@@ -15,12 +15,18 @@ const props = withDefaults(defineProps<{
|
|
|
15
15
|
/** Marche d'escalier : prix, taux de remboursement, decisions datees. */
|
|
16
16
|
step?: boolean
|
|
17
17
|
smooth?: boolean
|
|
18
|
+
/**
|
|
19
|
+
* Libelles des axes gauche et droit. A fournir des qu'une serie porte
|
|
20
|
+
* `axis: 1` : deux unites sur un graphe sans libelle d'axe se lisent mal.
|
|
21
|
+
*/
|
|
22
|
+
axisLabels?: [string, string]
|
|
18
23
|
height?: keyof typeof RM_CHART_HEIGHTS | number
|
|
19
24
|
description?: string
|
|
20
25
|
}>(), {
|
|
21
26
|
area: false,
|
|
22
27
|
step: false,
|
|
23
28
|
smooth: true,
|
|
29
|
+
axisLabels: undefined,
|
|
24
30
|
height: 'standard',
|
|
25
31
|
description: undefined,
|
|
26
32
|
})
|
|
@@ -33,6 +39,7 @@ const option = computed(() =>
|
|
|
33
39
|
step: props.step,
|
|
34
40
|
smooth: props.smooth,
|
|
35
41
|
decal: decal.value,
|
|
42
|
+
axisLabels: props.axisLabels,
|
|
36
43
|
}),
|
|
37
44
|
)
|
|
38
45
|
</script>
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { PhX } from '@phosphor-icons/vue'
|
|
3
|
+
|
|
4
|
+
export interface RmModalProps {
|
|
5
|
+
/** Whether the modal is open */
|
|
6
|
+
modelValue: boolean
|
|
7
|
+
/** Size: sm, md, lg, xl */
|
|
8
|
+
size?: 'sm' | 'md' | 'lg' | 'xl'
|
|
9
|
+
/** Mode: fixed (size is fixed) or free (adapts to content) */
|
|
10
|
+
mode?: 'fixed' | 'free'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const props = withDefaults(defineProps<RmModalProps>(), {
|
|
14
|
+
size: 'md',
|
|
15
|
+
mode: 'fixed',
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
const emit = defineEmits<{
|
|
19
|
+
'update:modelValue': [value: boolean]
|
|
20
|
+
}>()
|
|
21
|
+
|
|
22
|
+
function close() {
|
|
23
|
+
emit('update:modelValue', false)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const sizeMap: Record<string, { width: string; height: string }> = {
|
|
27
|
+
sm: { width: '480px', height: '360px' },
|
|
28
|
+
md: { width: '640px', height: '500px' },
|
|
29
|
+
lg: { width: '800px', height: '640px' },
|
|
30
|
+
xl: { width: '960px', height: '780px' },
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const modalStyle = computed(() => {
|
|
34
|
+
const s = sizeMap[props.size] ?? sizeMap.md
|
|
35
|
+
if (props.mode === 'fixed') {
|
|
36
|
+
return { width: s.width, height: s.height }
|
|
37
|
+
}
|
|
38
|
+
return { width: s.width, maxHeight: '85vh' }
|
|
39
|
+
})
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<template>
|
|
43
|
+
<Teleport to="body">
|
|
44
|
+
<Transition name="rm-modal">
|
|
45
|
+
<div
|
|
46
|
+
v-if="modelValue"
|
|
47
|
+
class="rm-modal-overlay"
|
|
48
|
+
@click.self="close"
|
|
49
|
+
>
|
|
50
|
+
<div class="rm-modal" :style="modalStyle">
|
|
51
|
+
<div class="rm-modal__header">
|
|
52
|
+
<div class="rm-modal__header-content">
|
|
53
|
+
<slot name="header" />
|
|
54
|
+
</div>
|
|
55
|
+
<button class="rm-modal__close" @click="close">
|
|
56
|
+
<PhX :size="20" />
|
|
57
|
+
</button>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div v-if="$slots.tabs" class="rm-modal__tabs">
|
|
61
|
+
<slot name="tabs" />
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div class="rm-modal__body">
|
|
65
|
+
<slot />
|
|
66
|
+
</div>
|
|
67
|
+
|
|
68
|
+
<div v-if="$slots.footer" class="rm-modal__footer">
|
|
69
|
+
<slot name="footer" />
|
|
70
|
+
</div>
|
|
71
|
+
</div>
|
|
72
|
+
</div>
|
|
73
|
+
</Transition>
|
|
74
|
+
</Teleport>
|
|
75
|
+
</template>
|
|
76
|
+
|
|
77
|
+
<style scoped>
|
|
78
|
+
.rm-modal-overlay{align-items:center;backdrop-filter:blur(2px);background:rgba(0,0,0,.4);display:flex;inset:0;justify-content:center;position:fixed;z-index:100}.rm-modal{background:#fff;border-radius:12px;box-shadow:0 20px 60px rgba(0,0,0,.15);display:flex;flex-direction:column;max-height:90vh;max-width:95vw}.rm-modal__header{align-items:flex-start;display:flex;gap:16px;justify-content:space-between;padding:20px 24px 0}.rm-modal__header-content{flex:1;min-width:0}.rm-modal__close{align-items:center;background:none;border:none;border-radius:var(--r-radius-md);color:var(--r-color-gray-400);cursor:pointer;display:flex;flex-shrink:0;height:32px;justify-content:center;transition:all var(--r-transition-fast);width:32px}.rm-modal__close:hover{background:var(--r-color-gray-50);color:var(--r-color-gray-700)}.rm-modal__tabs{padding:0}.rm-modal__body{flex:1;overflow-y:auto;padding:24px}.rm-modal__footer{border-top:1px solid var(--r-color-gray-200);padding:16px 24px}.rm-modal-enter-active,.rm-modal-leave-active{transition:opacity .2s ease}.rm-modal-enter-active .rm-modal,.rm-modal-leave-active .rm-modal{transition:transform .2s ease}.rm-modal-enter-from,.rm-modal-leave-to{opacity:0}.rm-modal-enter-from .rm-modal,.rm-modal-leave-to .rm-modal{transform:scale(.95)}
|
|
79
|
+
</style>
|