@tekkare/romulus 0.1.238 → 0.1.240
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/runtime/assets/styles/components.css +1 -1
- package/dist/runtime/components/ChartCard.vue +16 -1
- package/dist/runtime/components/TagRow.vue +16 -5
- package/dist/runtime/composables/useRmCardActions.js +2 -2
- package/dist/runtime/composables/useRmExport.js +82 -8
- package/dist/runtime/utils/cardData.d.ts +7 -1
- package/dist/runtime/utils/cardData.js +9 -0
- package/dist/runtime/utils/export.d.ts +16 -0
- package/dist/runtime/utils/export.js +22 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
.grid-2{grid-template-columns:repeat(2,1fr)}.grid-2,.grid-3{display:grid;gap:var(--space-20)}.grid-3{grid-template-columns:repeat(3,1fr)}.grid-4{display:grid;gap:var(--space-16);grid-template-columns:repeat(4,1fr)}.grid-2-1{display:grid;gap:var(--space-20);grid-template-columns:2fr 1fr}.pane-title{color:var(--text-primary);font-family:var(--font-serif);font-size:var(--font-32);font-weight:700;letter-spacing:-.02em;line-height:1.1;margin:0 0 16px}.pane-sub{color:var(--text-muted);font-size:var(--font-13);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 var(--space-40);width:100%}.section-label{align-items:center;color:var(--text-secondary);display:flex;font-size:var(--font-11);font-weight:700;gap:var(--space-8);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:var(--font-13)}body.text-xl .section-label{font-size:var(--font-14)}.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 var(--space-24) 14px;padding-right:64px;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:var(--font-12);line-height:1.55;margin:0}.rm-card-actions{position:relative}.chart-card-head>.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:var(--font-14);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,.rm-card-actions.open .cc-export{background:var(--bg-hover);border-color:var(--color-violet-pale)}.rm-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:var(--space-6) 0;position:absolute;right:0;top:34px;z-index:500}.rm-card-actions.open .cc-menu{display:block}.cc-menu-section{color:var(--text-muted);font-size:var(--font-10);font-weight:700;letter-spacing:.08em;padding:var(--space-8) 14px var(--space-4);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:var(--font-13);gap:var(--space-10);padding:7px 14px;text-align:left;width:100%}.cc-menu-item i{color:var(--text-muted);font-size:var(--font-14)}.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}.cc-menu-note{border-top:1px solid var(--bg-surface-3);color:var(--text-secondary);font-size:var(--font-12);margin:4px 0 0;padding:var(--space-8) 14px var(--space-4)}.cc-menu-item[disabled]{cursor:default;opacity:.55}.cc-menu-item[disabled]:hover{background:none;color:var(--text-secondary)}.chart-card:fullscreen,.rm-card-zoom,.rm-rcard:fullscreen,.rm-table-card:fullscreen{background:var(--bg-surface);border-radius:0;box-sizing:border-box;height:100vh;overflow:auto;padding:var(--space-16);width:100vw}.rm-card-zoom{border:0;inset:0;margin:0;position:fixed;z-index:500}body.rm-card-zoom-open{overflow:hidden}.chart-card.rm-card-zoom .chart-card-body,.chart-card:fullscreen .chart-card-body{display:flex;flex-direction:column}.chart-card.rm-card-zoom .rm-chart,.chart-card:fullscreen .rm-chart{flex:1 1 auto}.chart-card.rm-card-zoom .echart,.chart-card:fullscreen .echart{height:72vh!important}@keyframes cc-menu-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.chart-card-body{flex:1;padding:var(--space-4) var(--space-12) var(--space-8)}.chart-card-body>.rm-empty{box-sizing:border-box;gap:var(--space-6);justify-content:center;max-width:none;min-height:240px;padding:36px var(--space-24)}.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:var(--font-11);gap:var(--space-10);padding:var(--space-12) var(--space-24)}.chart-card-foot .src{align-items:center;display:flex;gap:var(--space-4)}.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:var(--space-16) 18px}.kpi-label{color:var(--text-muted);font-size:var(--font-11);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:var(--font-12);font-weight:600;gap:var(--space-4);margin-top:6px}.kpi-trend i{font-size:var(--font-11)}.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:var(--font-11);margin-top:4px}.kpi-extra{margin-top:12px}.badge{border-radius:4px;display:inline-block;font-size:var(--font-10);font-weight:600;padding:var(--space-2) var(--space-8)}.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:var(--font-13);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:var(--font-11);font-weight:700;letter-spacing:.08em;padding:var(--space-12) 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:var(--space-12) 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{min-width:0;overflow-x:auto}.tk-num{font-variant-numeric:tabular-nums;text-align:right}.tk-skeleton{height:14px;width:80%}.tk-empty{color:var(--text-muted);text-align:center}.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:var(--font-11);font-weight:700;gap:var(--space-8);letter-spacing:.08em;padding:var(--space-8) var(--space-12);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:var(--space-2);padding:var(--space-2) 0 var(--space-8)}.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:var(--font-13)}body.text-large .kpi-value{font-size:34px}body.text-large .kpi-trend{font-size:var(--font-14)}body.text-large .kpi-foot{font-size:var(--font-13)}body.text-large .chart-card-title{font-size:17px}body.text-large .chart-card-context{font-size:var(--font-14)}body.text-large .chart-card-foot{font-size:var(--font-12)}body.text-large .rm-table-card__context{font-size:var(--font-14)}body.text-large .badge,body.text-large .rm-table-card__foot{font-size:var(--font-12)}body.text-large .badge{padding:3px 9px}body.text-large table.tk{font-size:15px}body.text-large table.tk th{font-size:var(--font-13)}body.text-xl .kpi-label{font-size:var(--font-14)}body.text-xl .kpi-value{font-size:40px}body.text-xl .kpi-trend{font-size:var(--font-16)}body.text-xl .kpi-foot{font-size:var(--font-14)}body.text-xl .chart-card-title{font-size:20px}body.text-xl .chart-card-context{font-size:var(--font-16)}body.text-xl .chart-card-foot{font-size:var(--font-14)}body.text-xl .rm-table-card__context{font-size:var(--font-16)}body.text-xl .badge,body.text-xl .rm-table-card__foot{font-size:var(--font-14)}body.text-xl .badge{padding:3px var(--space-10)}body.text-xl table.tk{font-size:var(--font-16)}body.text-xl table.tk th{font-size:var(--font-14)}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}.rm-skeleton{animation:rm-skeleton-shimmer 1.5s ease-in-out infinite;background:linear-gradient(90deg,var(--bg-hover) 0,var(--bg-surface-2) 50%,var(--bg-hover) 100%);background-size:200% 100%;border-radius:var(--radius-md)}@keyframes rm-skeleton-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}@media (prefers-reduced-motion:reduce){.rm-skeleton{animation:none;background:var(--bg-hover)}}.rm-state-loading{display:flex;flex-direction:column;gap:var(--space-10);justify-content:center;min-height:240px;padding:var(--space-8) var(--space-4)}.rm-spinner{animation:rm-spinner-turn .8s linear infinite;border:3px solid var(--border-default);border-radius:50%;border-top-color:var(--color-secondary);height:32px;width:32px}@keyframes rm-spinner-turn{to{transform:rotate(1turn)}}@media (prefers-reduced-motion:reduce){.rm-spinner{animation-duration:3s}}.rm-state{color:var(--text-secondary);flex-direction:column;font-family:var(--font-sans);gap:var(--space-6);min-height:240px;padding:36px var(--space-24);text-align:center}.rm-state,.rm-state__icon{align-items:center;display:flex;justify-content:center}.rm-state__icon{background:var(--bg-surface-3);border-radius:50%;color:var(--text-muted);height:56px;margin-bottom:6px;width:56px}.rm-state__title{color:var(--text-primary);font-size:var(--font-14);font-weight:var(--weight-semibold);margin:0}.rm-state__text{color:var(--text-muted);font-size:var(--font-12);line-height:1.5;margin:0;max-width:280px}.rm-state__action{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:var(--radius-md);color:var(--text-secondary);cursor:pointer;display:inline-flex;font-family:inherit;font-size:var(--font-12);font-weight:var(--weight-semibold);gap:var(--space-6);margin-top:10px;padding:var(--space-6) 14px}.rm-state__action:hover{background:var(--bg-surface-3);color:var(--text-primary)}.rm-state--error .rm-state__icon{background:var(--color-danger-bg);color:var(--color-danger)}.rm-state--error .rm-state__action{border-color:var(--color-danger);color:var(--color-danger)}.rm-state--error .rm-state__action:hover{background:var(--color-danger-bg)}*{scrollbar-color:var(--border-default) transparent;scrollbar-width:thin}::-webkit-scrollbar{height:10px;width:10px}::-webkit-scrollbar-corner,::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background-clip:padding-box;background-color:var(--border-default);border:3px solid transparent;border-radius:var(--radius-pill)}::-webkit-scrollbar-thumb:hover{background-color:var(--text-muted)}
|
|
1
|
+
.grid-2{grid-template-columns:repeat(2,1fr)}.grid-2,.grid-3{display:grid;gap:var(--space-20)}.grid-3{grid-template-columns:repeat(3,1fr)}.grid-4{display:grid;gap:var(--space-16);grid-template-columns:repeat(4,1fr)}.grid-2-1{display:grid;gap:var(--space-20);grid-template-columns:2fr 1fr}.pane-title{color:var(--text-primary);font-family:var(--font-serif);font-size:var(--font-32);font-weight:700;letter-spacing:-.02em;line-height:1.1;margin:0 0 16px}.pane-sub{color:var(--text-muted);font-size:var(--font-13);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 var(--space-40);width:100%}.section-label{align-items:center;color:var(--text-secondary);display:flex;font-size:var(--font-11);font-weight:700;gap:var(--space-8);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:var(--font-13)}body.text-xl .section-label{font-size:var(--font-14)}.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 var(--space-24) 14px;padding-right:64px;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:var(--font-12);line-height:1.55;margin:0}.chart-card-tags{margin-top:var(--space-4)}.rm-card-actions{position:relative}.chart-card-head>.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:var(--font-14);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,.rm-card-actions.open .cc-export{background:var(--bg-hover);border-color:var(--color-violet-pale)}.rm-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:var(--space-6) 0;position:absolute;right:0;top:34px;z-index:500}.rm-card-actions.open .cc-menu{display:block}.cc-menu-section{color:var(--text-muted);font-size:var(--font-10);font-weight:700;letter-spacing:.08em;padding:var(--space-8) 14px var(--space-4);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:var(--font-13);gap:var(--space-10);padding:7px 14px;text-align:left;width:100%}.cc-menu-item i{color:var(--text-muted);font-size:var(--font-14)}.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}.cc-menu-note{border-top:1px solid var(--bg-surface-3);color:var(--text-secondary);font-size:var(--font-12);margin:4px 0 0;padding:var(--space-8) 14px var(--space-4)}.cc-menu-item[disabled]{cursor:default;opacity:.55}.cc-menu-item[disabled]:hover{background:none;color:var(--text-secondary)}.chart-card:fullscreen,.rm-card-zoom,.rm-rcard:fullscreen,.rm-table-card:fullscreen{background:var(--bg-surface);border-radius:0;box-sizing:border-box;height:100vh;overflow:auto;padding:var(--space-16);width:100vw}.rm-card-zoom{border:0;inset:0;margin:0;position:fixed;z-index:500}body.rm-card-zoom-open{overflow:hidden}.chart-card.rm-card-zoom .chart-card-body,.chart-card:fullscreen .chart-card-body{display:flex;flex-direction:column}.chart-card.rm-card-zoom .rm-chart,.chart-card:fullscreen .rm-chart{flex:1 1 auto}.chart-card.rm-card-zoom .echart,.chart-card:fullscreen .echart{height:72vh!important}@keyframes cc-menu-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.chart-card-body{flex:1;padding:var(--space-4) var(--space-12) var(--space-8)}.chart-card-body>.rm-empty{box-sizing:border-box;gap:var(--space-6);justify-content:center;max-width:none;min-height:240px;padding:36px var(--space-24)}.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:var(--font-11);gap:var(--space-10);padding:var(--space-12) var(--space-24)}.chart-card-foot .src{align-items:center;display:flex;gap:var(--space-4)}.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:var(--space-16) 18px}.kpi-label{color:var(--text-muted);font-size:var(--font-11);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:var(--font-12);font-weight:600;gap:var(--space-4);margin-top:6px}.kpi-trend i{font-size:var(--font-11)}.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:var(--font-11);margin-top:4px}.kpi-extra{margin-top:12px}.badge{border-radius:4px;display:inline-block;font-size:var(--font-10);font-weight:600;padding:var(--space-2) var(--space-8)}.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:var(--font-13);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:var(--font-11);font-weight:700;letter-spacing:.08em;padding:var(--space-12) 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:var(--space-12) 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{min-width:0;overflow-x:auto}.tk-num{font-variant-numeric:tabular-nums;text-align:right}.tk-skeleton{height:14px;width:80%}.tk-empty{color:var(--text-muted);text-align:center}.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:var(--font-11);font-weight:700;gap:var(--space-8);letter-spacing:.08em;padding:var(--space-8) var(--space-12);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:var(--space-2);padding:var(--space-2) 0 var(--space-8)}.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:var(--font-13)}body.text-large .kpi-value{font-size:34px}body.text-large .kpi-trend{font-size:var(--font-14)}body.text-large .kpi-foot{font-size:var(--font-13)}body.text-large .chart-card-title{font-size:17px}body.text-large .chart-card-context{font-size:var(--font-14)}body.text-large .chart-card-foot{font-size:var(--font-12)}body.text-large .rm-table-card__context{font-size:var(--font-14)}body.text-large .badge,body.text-large .rm-table-card__foot{font-size:var(--font-12)}body.text-large .badge{padding:3px 9px}body.text-large table.tk{font-size:15px}body.text-large table.tk th{font-size:var(--font-13)}body.text-xl .kpi-label{font-size:var(--font-14)}body.text-xl .kpi-value{font-size:40px}body.text-xl .kpi-trend{font-size:var(--font-16)}body.text-xl .kpi-foot{font-size:var(--font-14)}body.text-xl .chart-card-title{font-size:20px}body.text-xl .chart-card-context{font-size:var(--font-16)}body.text-xl .chart-card-foot{font-size:var(--font-14)}body.text-xl .rm-table-card__context{font-size:var(--font-16)}body.text-xl .badge,body.text-xl .rm-table-card__foot{font-size:var(--font-14)}body.text-xl .badge{padding:3px var(--space-10)}body.text-xl table.tk{font-size:var(--font-16)}body.text-xl table.tk th{font-size:var(--font-14)}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}.rm-skeleton{animation:rm-skeleton-shimmer 1.5s ease-in-out infinite;background:linear-gradient(90deg,var(--bg-hover) 0,var(--bg-surface-2) 50%,var(--bg-hover) 100%);background-size:200% 100%;border-radius:var(--radius-md)}@keyframes rm-skeleton-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}@media (prefers-reduced-motion:reduce){.rm-skeleton{animation:none;background:var(--bg-hover)}}.rm-state-loading{display:flex;flex-direction:column;gap:var(--space-10);justify-content:center;min-height:240px;padding:var(--space-8) var(--space-4)}.rm-spinner{animation:rm-spinner-turn .8s linear infinite;border:3px solid var(--border-default);border-radius:50%;border-top-color:var(--color-secondary);height:32px;width:32px}@keyframes rm-spinner-turn{to{transform:rotate(1turn)}}@media (prefers-reduced-motion:reduce){.rm-spinner{animation-duration:3s}}.rm-state{color:var(--text-secondary);flex-direction:column;font-family:var(--font-sans);gap:var(--space-6);min-height:240px;padding:36px var(--space-24);text-align:center}.rm-state,.rm-state__icon{align-items:center;display:flex;justify-content:center}.rm-state__icon{background:var(--bg-surface-3);border-radius:50%;color:var(--text-muted);height:56px;margin-bottom:6px;width:56px}.rm-state__title{color:var(--text-primary);font-size:var(--font-14);font-weight:var(--weight-semibold);margin:0}.rm-state__text{color:var(--text-muted);font-size:var(--font-12);line-height:1.5;margin:0;max-width:280px}.rm-state__action{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:var(--radius-md);color:var(--text-secondary);cursor:pointer;display:inline-flex;font-family:inherit;font-size:var(--font-12);font-weight:var(--weight-semibold);gap:var(--space-6);margin-top:10px;padding:var(--space-6) 14px}.rm-state__action:hover{background:var(--bg-surface-3);color:var(--text-primary)}.rm-state--error .rm-state__icon{background:var(--color-danger-bg);color:var(--color-danger)}.rm-state--error .rm-state__action{border-color:var(--color-danger);color:var(--color-danger)}.rm-state--error .rm-state__action:hover{background:var(--color-danger-bg)}*{scrollbar-color:var(--border-default) transparent;scrollbar-width:thin}::-webkit-scrollbar{height:10px;width:10px}::-webkit-scrollbar-corner,::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background-clip:padding-box;background-color:var(--border-default);border:3px solid transparent;border-radius:var(--radius-pill)}::-webkit-scrollbar-thumb:hover{background-color:var(--text-muted)}
|
|
@@ -13,12 +13,19 @@
|
|
|
13
13
|
import { computed } from 'vue'
|
|
14
14
|
import type { RmExportPayload } from '../utils/export'
|
|
15
15
|
import { rmDate } from '../utils/format'
|
|
16
|
+
import type { RmTagRowItem } from './TagRow.vue'
|
|
16
17
|
|
|
17
18
|
const props = withDefaults(defineProps<{
|
|
18
19
|
/** Titre de la carte. */
|
|
19
20
|
title: string
|
|
20
21
|
/** Sous-titre : perimetre, methode, aide a la lecture. */
|
|
21
22
|
context?: string
|
|
23
|
+
/**
|
|
24
|
+
* Perimetre lu, en etiquettes (element, mesure, periode, geographie) : une
|
|
25
|
+
* rangee qui se parcourt d'un coup d'oeil, la ou la phrase du sous-titre
|
|
26
|
+
* se lisait jusqu'au bout. Pose sous le sous-titre quand les deux sont la.
|
|
27
|
+
*/
|
|
28
|
+
tags?: RmTagRowItem[]
|
|
22
29
|
/** Organisme public : "HAS", "OCDE", "ANSM (Repertoire des specialites)". Jamais un outil interne. */
|
|
23
30
|
source: string
|
|
24
31
|
/** Date de notre verification. Un Date est formate en long ; une chaine deja formatee passe telle quelle. */
|
|
@@ -59,6 +66,7 @@ const props = withDefaults(defineProps<{
|
|
|
59
66
|
emptyActionLabel?: string
|
|
60
67
|
}>(), {
|
|
61
68
|
context: undefined,
|
|
69
|
+
tags: undefined,
|
|
62
70
|
lang: 'fr',
|
|
63
71
|
extra: undefined,
|
|
64
72
|
actions: true,
|
|
@@ -117,6 +125,12 @@ const t = computed(() => WORDS[props.lang])
|
|
|
117
125
|
*/
|
|
118
126
|
const ISO_DATE = /^\d{4}-\d{2}-\d{2}/
|
|
119
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Nom des exports : le titre et sa phrase de contexte. Les etiquettes n'y
|
|
130
|
+
* entrent pas, les exports les redessinent sous le titre (cf. `rmCardTags`).
|
|
131
|
+
*/
|
|
132
|
+
const exportName = computed(() => (props.context ? `${props.title} (${props.context})` : props.title))
|
|
133
|
+
|
|
120
134
|
const verifiedText = computed(() => {
|
|
121
135
|
if (typeof props.verified === 'string' && !ISO_DATE.test(props.verified)) return props.verified
|
|
122
136
|
const parsed = new Date(props.verified)
|
|
@@ -133,6 +147,7 @@ const verifiedText = computed(() => {
|
|
|
133
147
|
<div class="chart-card-head">
|
|
134
148
|
<p class="chart-card-title">{{ title }}</p>
|
|
135
149
|
<p v-if="context" class="chart-card-context">{{ context }}</p>
|
|
150
|
+
<RmTagRow v-if="tags?.length" class="chart-card-tags" :tags="tags" />
|
|
136
151
|
|
|
137
152
|
<!-- Les six actions vivent dans RmCardActions : elles doivent etre les
|
|
138
153
|
memes sur une carte de resultat que sur une carte de graphique. Les
|
|
@@ -142,7 +157,7 @@ const verifiedText = computed(() => {
|
|
|
142
157
|
class="chart-card-actions"
|
|
143
158
|
:lang="lang"
|
|
144
159
|
:link="link"
|
|
145
|
-
:name="
|
|
160
|
+
:name="exportName"
|
|
146
161
|
:sources="[{ name: source, date: verifiedText }]"
|
|
147
162
|
:payload="payload"
|
|
148
163
|
@export-png="emit('exportPng')"
|
|
@@ -15,8 +15,16 @@
|
|
|
15
15
|
import { computed, nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|
16
16
|
import type { RmTagVariant } from './Tag.vue'
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* Une etiquette : un texte seul prend la couleur de la rangee ; l'objet porte
|
|
20
|
+
* la sienne, quand chaque etiquette dit une chose differente (element,
|
|
21
|
+
* mesure, periode...) et que la couleur aide a les distinguer.
|
|
22
|
+
*/
|
|
23
|
+
export type RmTagRowItem = string | { label: string; variant?: RmTagVariant }
|
|
24
|
+
|
|
18
25
|
const props = withDefaults(defineProps<{
|
|
19
|
-
tags:
|
|
26
|
+
tags: RmTagRowItem[]
|
|
27
|
+
/** Couleur des etiquettes qui n'en portent pas. */
|
|
20
28
|
variant?: RmTagVariant
|
|
21
29
|
/** Cote ou sort la bulle du compteur. */
|
|
22
30
|
tooltipDir?: 'top' | 'right' | 'bottom' | 'left'
|
|
@@ -28,8 +36,11 @@ const props = withDefaults(defineProps<{
|
|
|
28
36
|
const rowRef = ref<HTMLElement>()
|
|
29
37
|
const visibleCount = ref(props.tags.length)
|
|
30
38
|
|
|
31
|
-
const
|
|
32
|
-
|
|
39
|
+
const items = computed(() =>
|
|
40
|
+
props.tags.map(tag => (typeof tag === 'string' ? { label: tag, variant: props.variant } : { label: tag.label, variant: tag.variant ?? props.variant })),
|
|
41
|
+
)
|
|
42
|
+
const shown = computed(() => items.value.slice(0, visibleCount.value))
|
|
43
|
+
const hidden = computed(() => items.value.slice(visibleCount.value).map(tag => tag.label))
|
|
33
44
|
|
|
34
45
|
/**
|
|
35
46
|
* Compte les etiquettes restees sur la premiere ligne. La rangee est mesuree
|
|
@@ -69,9 +80,9 @@ watch(() => props.tags, measure, { deep: true })
|
|
|
69
80
|
</script>
|
|
70
81
|
|
|
71
82
|
<template>
|
|
72
|
-
<div class="rm-tag-row">
|
|
83
|
+
<div class="rm-tag-row" :data-rm-tags="JSON.stringify(items)">
|
|
73
84
|
<div ref="rowRef" class="rm-tag-row__items">
|
|
74
|
-
<RmTag v-for="tag in shown" :key="tag" data-rm-tag :variant="variant">{{ tag }}</RmTag>
|
|
85
|
+
<RmTag v-for="tag in shown" :key="tag.label" data-rm-tag :variant="tag.variant">{{ tag.label }}</RmTag>
|
|
75
86
|
</div>
|
|
76
87
|
<RmTooltip v-if="hidden.length > 0" :text="hidden.join('\n')" :dir="tooltipDir" full>
|
|
77
88
|
<span class="rm-tag-row__more">+{{ hidden.length }}</span>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { rmCardCharts, rmCardSheets, rmCardTitle } from "../utils/cardData.js";
|
|
1
|
+
import { rmCardCharts, rmCardSheets, rmCardTags, rmCardTitle } from "../utils/cardData.js";
|
|
2
2
|
import { useRmExport } from "./useRmExport.js";
|
|
3
3
|
import { rmExportDefaults } from "./useRmExportDefaults.js";
|
|
4
4
|
const FILE_NAME_MAX = 60;
|
|
@@ -51,7 +51,7 @@ export function useRmCardActions() {
|
|
|
51
51
|
return run(configOf(format, fileNameOf(title)), {
|
|
52
52
|
...defaults,
|
|
53
53
|
title,
|
|
54
|
-
charts: rmCardCharts(card).map((el) => ({ title, el })),
|
|
54
|
+
charts: rmCardCharts(card).map((el) => ({ title, el, tags: rmCardTags(card) })),
|
|
55
55
|
// Le lien de la carte, sinon celui du cadre : le permalien de la page
|
|
56
56
|
// porte la vue et les filtres, la ou l'URL courante ne dit rien de ce
|
|
57
57
|
// qui est affiche.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { RM_EXPORT_EXTENSIONS } from "../utils/export.js";
|
|
1
|
+
import { RM_EXPORT_EXTENSIONS, rmExportTagColor } from "../utils/export.js";
|
|
2
2
|
const BRAND_TITLE = "OIP Healthcare";
|
|
3
3
|
const BRAND_LINE = "By Tekkare \u{1F49C}";
|
|
4
4
|
const COVER_SHEET = "Tekkare";
|
|
@@ -92,7 +92,28 @@ function titleGap(title) {
|
|
|
92
92
|
return title ? 22 : 0;
|
|
93
93
|
}
|
|
94
94
|
function drawableCharts(payload) {
|
|
95
|
-
return (payload.charts ?? []).map((chart) => ({ title: chart.title, svg: svgOf(chart.el) })).filter((chart) => !!chart.svg);
|
|
95
|
+
return (payload.charts ?? []).map((chart) => ({ title: chart.title, tags: chart.tags, svg: svgOf(chart.el) })).filter((chart) => !!chart.svg);
|
|
96
|
+
}
|
|
97
|
+
const TAG_FONT = "500 12px Figtree, Helvetica, sans-serif";
|
|
98
|
+
const TAG_HEIGHT = 22;
|
|
99
|
+
const TAG_SPACE = 6;
|
|
100
|
+
function layoutTags(tags, width) {
|
|
101
|
+
if (!tags?.length) return { placed: [], height: 0 };
|
|
102
|
+
const measure = document.createElement("canvas").getContext("2d");
|
|
103
|
+
measure.font = TAG_FONT;
|
|
104
|
+
let x = 0;
|
|
105
|
+
let row = 0;
|
|
106
|
+
const placed = tags.map((tag) => {
|
|
107
|
+
const w = Math.ceil(measure.measureText(tag.label).width) + 16;
|
|
108
|
+
if (x > 0 && x + w > width) {
|
|
109
|
+
x = 0;
|
|
110
|
+
row++;
|
|
111
|
+
}
|
|
112
|
+
const at = { tag, x, row, w };
|
|
113
|
+
x += w + TAG_SPACE;
|
|
114
|
+
return at;
|
|
115
|
+
});
|
|
116
|
+
return { placed, height: (row + 1) * (TAG_HEIGHT + TAG_SPACE) + 4 };
|
|
96
117
|
}
|
|
97
118
|
function svgOf(el) {
|
|
98
119
|
return el instanceof SVGSVGElement ? el : el.querySelector("svg");
|
|
@@ -344,9 +365,12 @@ export function useRmExport() {
|
|
|
344
365
|
const pad = 24;
|
|
345
366
|
const sources = sourcesOf(config, payload);
|
|
346
367
|
const head = config.options.includes("logo") ? sources.length ? 88 : 72 : 0;
|
|
347
|
-
const parts = drawn.map((chart) =>
|
|
368
|
+
const parts = drawn.map((chart) => {
|
|
369
|
+
const part = serialize(chart.svg);
|
|
370
|
+
return { ...part, title: chart.title, tags: layoutTags(chart.tags, part.width) };
|
|
371
|
+
});
|
|
348
372
|
const width = Math.max(...parts.map((part) => part.width)) + pad * 2;
|
|
349
|
-
const height = parts.reduce((total, part) => total + part.height + pad + titleGap(part.title), pad) + head;
|
|
373
|
+
const height = parts.reduce((total, part) => total + part.height + pad + titleGap(part.title) + part.tags.height, pad) + head;
|
|
350
374
|
const canvas = document.createElement("canvas");
|
|
351
375
|
canvas.width = width * scale;
|
|
352
376
|
canvas.height = height * scale;
|
|
@@ -373,6 +397,18 @@ export function useRmExport() {
|
|
|
373
397
|
context.fillText(part.title, pad, y + 12);
|
|
374
398
|
y += titleGap(part.title);
|
|
375
399
|
}
|
|
400
|
+
context.font = TAG_FONT;
|
|
401
|
+
for (const { tag, x, row, w } of part.tags.placed) {
|
|
402
|
+
const { fill, text } = rmExportTagColor(tag.variant);
|
|
403
|
+
const top = y + row * (TAG_HEIGHT + TAG_SPACE);
|
|
404
|
+
context.fillStyle = `rgb(${fill.join(",")})`;
|
|
405
|
+
context.beginPath();
|
|
406
|
+
context.roundRect(pad + x, top, w, TAG_HEIGHT, 4);
|
|
407
|
+
context.fill();
|
|
408
|
+
context.fillStyle = text;
|
|
409
|
+
context.fillText(tag.label, pad + x + 8, top + 15);
|
|
410
|
+
}
|
|
411
|
+
y += part.tags.height;
|
|
376
412
|
const raw = await raster(part.markup, part.width, part.height, scale);
|
|
377
413
|
context.drawImage(raw, pad, y, part.width, part.height);
|
|
378
414
|
y += part.height + pad;
|
|
@@ -389,16 +425,25 @@ export function useRmExport() {
|
|
|
389
425
|
const pad = 24;
|
|
390
426
|
const sources = sourcesOf(config, payload);
|
|
391
427
|
const head = config.options.includes("logo") ? sources.length ? 88 : 72 : 0;
|
|
392
|
-
const parts = drawn.map((chart) =>
|
|
428
|
+
const parts = drawn.map((chart) => {
|
|
429
|
+
const part = serialize(chart.svg);
|
|
430
|
+
return { ...part, title: chart.title, tags: layoutTags(chart.tags, part.width) };
|
|
431
|
+
});
|
|
393
432
|
const width = Math.max(...parts.map((part) => part.width)) + pad * 2;
|
|
394
|
-
const height = parts.reduce((total, part) => total + part.height + pad + titleGap(part.title), pad) + head;
|
|
433
|
+
const height = parts.reduce((total, part) => total + part.height + pad + titleGap(part.title) + part.tags.height, pad) + head;
|
|
395
434
|
let y = head + pad;
|
|
396
435
|
const nested = parts.map((part) => {
|
|
397
436
|
const label = part.title ? `<text x="${pad}" y="${y + 12}" font-family="Figtree, Helvetica, sans-serif" font-size="14" font-weight="bold" fill="#1A1A2E">${escapeXml(part.title)}</text>` : "";
|
|
398
437
|
y += titleGap(part.title);
|
|
438
|
+
const tags = part.tags.placed.map(({ tag, x, row, w }) => {
|
|
439
|
+
const { fill, text } = rmExportTagColor(tag.variant);
|
|
440
|
+
const top = y + row * (TAG_HEIGHT + TAG_SPACE);
|
|
441
|
+
return `<rect x="${pad + x}" y="${top}" width="${w}" height="${TAG_HEIGHT}" rx="4" fill="rgb(${fill.join(",")})"/><text x="${pad + x + 8}" y="${top + 15}" font-family="Figtree, Helvetica, sans-serif" font-size="12" font-weight="500" fill="${text}">${escapeXml(tag.label)}</text>`;
|
|
442
|
+
}).join("");
|
|
443
|
+
y += part.tags.height;
|
|
399
444
|
const markup2 = part.markup.replace(/^<svg /, `<svg x="${pad}" y="${y}" `);
|
|
400
445
|
y += part.height + pad;
|
|
401
|
-
return label + markup2;
|
|
446
|
+
return label + tags + markup2;
|
|
402
447
|
}).join("\n");
|
|
403
448
|
const header = head ? `<text x="${pad}" y="32" font-family="Figtree, Helvetica, sans-serif" font-size="20" font-weight="bold" fill="#1A1A2E">${BRAND_TITLE}</text><text x="${pad}" y="52" font-family="Figtree, Helvetica, sans-serif" font-size="12" fill="#6C6C8A">${escapeXml(`${payload.title} \xB7 ${BRAND_LINE} \xB7 ${longDate(lang)}`)}</text>` + (sources.length ? `<text x="${pad}" y="68" font-family="Figtree, Helvetica, sans-serif" font-size="12" fill="#6C6C8A">${escapeXml(`Source${sources.length > 1 ? "s" : ""} : ${sources.map((source) => sourceLabel(source, lang)).join(" \xB7 ")}`)}</text>` : "") : "";
|
|
404
449
|
const markup = `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${width} ${height}"><rect width="${width}" height="${height}" fill="#FFFFFF"/>${header}${nested}</svg>`;
|
|
@@ -566,7 +611,23 @@ export function useRmExport() {
|
|
|
566
611
|
drawWidth = part.width / part.height * drawHeight;
|
|
567
612
|
}
|
|
568
613
|
const titleHeight = chart.title ? 7 : 0;
|
|
569
|
-
|
|
614
|
+
doc.setFont("helvetica", "normal");
|
|
615
|
+
doc.setFontSize(8);
|
|
616
|
+
let tagX = 0;
|
|
617
|
+
let tagRow = 0;
|
|
618
|
+
const tagsPlaced = (chart.tags ?? []).map((tag) => {
|
|
619
|
+
const label = printable(tag.label);
|
|
620
|
+
const w = doc.getTextWidth(label) + 3.2;
|
|
621
|
+
if (tagX > 0 && tagX + w > inner - 10) {
|
|
622
|
+
tagX = 0;
|
|
623
|
+
tagRow++;
|
|
624
|
+
}
|
|
625
|
+
const at = { tag, label, x: tagX, row: tagRow, w };
|
|
626
|
+
tagX += w + 1.5;
|
|
627
|
+
return at;
|
|
628
|
+
});
|
|
629
|
+
const tagsHeight = tagsPlaced.length ? (tagRow + 1) * 6.5 + 1 : 0;
|
|
630
|
+
const cardHeight = titleHeight + tagsHeight + drawHeight + 8;
|
|
570
631
|
if (y + cardHeight > bottom) {
|
|
571
632
|
doc.addPage();
|
|
572
633
|
y = margin;
|
|
@@ -583,6 +644,19 @@ export function useRmExport() {
|
|
|
583
644
|
doc.text(printable(chart.title), margin + 5, chartY + 2);
|
|
584
645
|
chartY += titleHeight;
|
|
585
646
|
}
|
|
647
|
+
if (tagsPlaced.length) {
|
|
648
|
+
doc.setFont("helvetica", "normal");
|
|
649
|
+
doc.setFontSize(8);
|
|
650
|
+
for (const { tag, label, x, row, w } of tagsPlaced) {
|
|
651
|
+
const { fill, text } = rmExportTagColor(tag.variant);
|
|
652
|
+
const top = chartY - 1 + row * 6.5;
|
|
653
|
+
doc.setFillColor(...fill);
|
|
654
|
+
doc.roundedRect(margin + 5 + x, top, w, 5, 1, 1, "F");
|
|
655
|
+
doc.setTextColor(text);
|
|
656
|
+
doc.text(label, margin + 5 + x + 1.6, top + 3.5);
|
|
657
|
+
}
|
|
658
|
+
chartY += tagsHeight;
|
|
659
|
+
}
|
|
586
660
|
doc.addImage(
|
|
587
661
|
canvas.toDataURL("image/png"),
|
|
588
662
|
"PNG",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* - un graphe dessine dans une cellule (courbe de tendance d'une ligne) est
|
|
22
22
|
* une decoration du tableau : il ne fait pas un export a lui seul.
|
|
23
23
|
*/
|
|
24
|
-
import type { RmExportSheet } from './export.js';
|
|
24
|
+
import type { RmExportSheet, RmExportTag } from './export.js';
|
|
25
25
|
/** La carte qui contient un noeud, quel que soit le composant qui la rend. */
|
|
26
26
|
export declare function rmCardOf(el: Element | null): HTMLElement | null;
|
|
27
27
|
/**
|
|
@@ -30,6 +30,12 @@ export declare function rmCardOf(el: Element | null): HTMLElement | null;
|
|
|
30
30
|
* pareil ne se distinguent plus dans un dossier de telechargement.
|
|
31
31
|
*/
|
|
32
32
|
export declare function rmCardTitle(card: Element): string;
|
|
33
|
+
/**
|
|
34
|
+
* Etiquettes de perimetre de la carte (RmTagRow sous son titre), toutes, y
|
|
35
|
+
* compris celles que la rangee replie en « +N » faute de place : la rangee
|
|
36
|
+
* les porte en entier dans `data-rm-tags`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function rmCardTags(card: Element): RmExportTag[];
|
|
33
39
|
/** Les graphes exportables d'une carte, vides tant que la donnee n'est pas rendue. */
|
|
34
40
|
export declare function rmCardCharts(card: Element): HTMLElement[];
|
|
35
41
|
/**
|
|
@@ -16,6 +16,15 @@ export function rmCardTitle(card) {
|
|
|
16
16
|
const context = cellText(card.querySelector(".chart-card-context"));
|
|
17
17
|
return context ? `${title} (${context})` : title;
|
|
18
18
|
}
|
|
19
|
+
export function rmCardTags(card) {
|
|
20
|
+
const row = card.querySelector(".chart-card-head [data-rm-tags], .rm-table-card__header [data-rm-tags]");
|
|
21
|
+
try {
|
|
22
|
+
const tags = JSON.parse(row?.getAttribute("data-rm-tags") ?? "[]");
|
|
23
|
+
return Array.isArray(tags) ? tags : [];
|
|
24
|
+
} catch {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
19
28
|
export function rmCardCharts(card) {
|
|
20
29
|
return [...card.querySelectorAll(CHART_SELECTOR)].filter(
|
|
21
30
|
(holder) => holder.querySelector("svg") && !holder.closest("table")
|
|
@@ -263,6 +263,7 @@ export interface RmExportPayload {
|
|
|
263
263
|
charts?: {
|
|
264
264
|
title?: string;
|
|
265
265
|
el: Element;
|
|
266
|
+
tags?: RmExportTag[];
|
|
266
267
|
}[];
|
|
267
268
|
/**
|
|
268
269
|
* Cartes de l'ecran, a capturer telles quelles pour le rapport mis en page.
|
|
@@ -329,3 +330,18 @@ export declare function rmExportDuration(kb: number, rows: number): string;
|
|
|
329
330
|
* dossier de telechargements.
|
|
330
331
|
*/
|
|
331
332
|
export declare function rmExportFileName(...parts: (string | undefined | null)[]): string;
|
|
333
|
+
/**
|
|
334
|
+
* Etiquette de perimetre d'un graphe (element, mesure, periode, lieu), posee
|
|
335
|
+
* sous son titre a l'ecran par RmTagRow. Les exports la redessinent en
|
|
336
|
+
* pastille de la meme couleur : ecrite en texte a la suite du titre, elle
|
|
337
|
+
* donnait un intitule de deux lignes ou plus rien ne se distinguait.
|
|
338
|
+
*/
|
|
339
|
+
export interface RmExportTag {
|
|
340
|
+
label: string;
|
|
341
|
+
/** Variante de RmTag ; `gray` a defaut. */
|
|
342
|
+
variant?: string;
|
|
343
|
+
}
|
|
344
|
+
export declare function rmExportTagColor(variant?: string): {
|
|
345
|
+
fill: [number, number, number];
|
|
346
|
+
text: string;
|
|
347
|
+
};
|
|
@@ -101,3 +101,25 @@ export function rmExportFileName(...parts) {
|
|
|
101
101
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
102
102
|
return `${slug || "export"}-${today}`;
|
|
103
103
|
}
|
|
104
|
+
const RM_EXPORT_TAG_COLORS = {
|
|
105
|
+
gray: { fill: [244, 244, 247], text: "#1A1A2E" },
|
|
106
|
+
rose: { fill: [254, 236, 239], text: "#9f1239" },
|
|
107
|
+
pink: { fill: [253, 237, 245], text: "#9d174d" },
|
|
108
|
+
fushia: { fill: [251, 236, 253], text: "#86198f" },
|
|
109
|
+
purple: { fill: [246, 238, 254], text: "#6b21a8" },
|
|
110
|
+
violet: { fill: [243, 239, 254], text: "#5b21b6" },
|
|
111
|
+
indigo: { fill: [239, 240, 254], text: "#3730a3" },
|
|
112
|
+
blue: { fill: [235, 242, 254], text: "#1e40af" },
|
|
113
|
+
sky: { fill: [231, 246, 253], text: "#075985" },
|
|
114
|
+
cyan: { fill: [230, 248, 251], text: "#155e75" },
|
|
115
|
+
teal: { fill: [232, 248, 246], text: "#115e59" },
|
|
116
|
+
emerald: { fill: [231, 248, 242], text: "#065f46" },
|
|
117
|
+
green: { fill: [233, 249, 239], text: "#166534" },
|
|
118
|
+
lime: { fill: [243, 250, 232], text: "#3f6212" },
|
|
119
|
+
yellow: { fill: [253, 247, 230], text: "#854d0e" },
|
|
120
|
+
amber: { fill: [254, 245, 231], text: "#92400e" },
|
|
121
|
+
orange: { fill: [254, 241, 232], text: "#9a3412" }
|
|
122
|
+
};
|
|
123
|
+
export function rmExportTagColor(variant) {
|
|
124
|
+
return RM_EXPORT_TAG_COLORS[variant ?? "gray"] ?? RM_EXPORT_TAG_COLORS.gray;
|
|
125
|
+
}
|