dsh-calendar 0.14.3 → 0.14.4
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/CHANGELOG.md +7 -0
- package/lib/client.js +43 -22
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# 更新记录
|
|
2
2
|
|
|
3
|
+
## 0.14.4 (2026-11-03)
|
|
4
|
+
|
|
5
|
+
- 未配置首屏复用 Empty;月历 42 格补可及名与 aria-current;空范围/失败区分;未连接按钮打开连接设置;浮层补齐共享样式。
|
|
6
|
+
- Unconfigured states reuse Empty, calendar cells gain accessible names and aria-current, empty ranges are distinguished from failures, disconnected actions open connection settings, and floating panels share the workbench styles.
|
|
7
|
+
- 同步共享 workbench-ui v1.1:Page 外的 Empty / Dialog / Status 自带样式与 `.dshw` 主题作用域,Status 新增 warn 色调。
|
|
8
|
+
- Sync workbench-ui v1.1: Empty / Dialog / Status now carry their own styles and `.dshw` theme scope outside Page, and Status gains a warn tone.
|
|
9
|
+
|
|
3
10
|
## 0.14.3 (2026-10-30)
|
|
4
11
|
|
|
5
12
|
- 重整中英文首页:用途、三步流程图、安装入口与操作示例;详细配置与边界集中到完整说明。
|
package/lib/client.js
CHANGED
|
@@ -494,7 +494,7 @@ function createWorkbenchUI(React) {
|
|
|
494
494
|
}
|
|
495
495
|
function Page({ title, subtitle, actions, children, workbench = false, className, rootRef, ...props }) {
|
|
496
496
|
return h('section', { ...props, ref: rootRef, className: cx('dshw', 'w-page', className), 'data-main': workbench ? 'true' : 'false' },
|
|
497
|
-
h(
|
|
497
|
+
h(Styles, { key: 'styles' }),
|
|
498
498
|
h('header', { className: 'w-page-header' }, h('div', { className: 'w-heading' }, h('h1', null, title), subtitle ? h('p', { className: 'w-subtitle' }, subtitle) : null), actions ? h('div', { className: 'w-header-actions' }, actions) : null),
|
|
499
499
|
h('div', { className: 'w-body' }, children));
|
|
500
500
|
}
|
|
@@ -517,10 +517,10 @@ function createWorkbenchUI(React) {
|
|
|
517
517
|
}
|
|
518
518
|
function Status({ children, tone = 'info', className }) {
|
|
519
519
|
if (!children) return null;
|
|
520
|
-
return h('div', { className: cx('w-status', 'w-status-' + tone, className), role: tone === 'error' ? 'alert' : 'status', 'aria-live': tone === 'error' ? 'assertive' : 'polite' }, h(Icon, { name: tone === 'success' ? 'check' : 'info', size: 18 }), h('div', null, children));
|
|
520
|
+
return h('div', { className: cx('dshw', 'w-status', 'w-status-' + tone, className), role: tone === 'error' ? 'alert' : 'status', 'aria-live': tone === 'error' ? 'assertive' : 'polite' }, h(Icon, { name: tone === 'success' ? 'check' : 'info', size: 18 }), h('div', null, children));
|
|
521
521
|
}
|
|
522
522
|
function Empty({ title, children, action, icon = 'file' }) {
|
|
523
|
-
return h('div', { className: 'w-empty' }, h(Icon, { name: icon, size: 32 }), h('h2', null, title), children ? h('div', { className: 'w-muted' }, children) : null, action ? h('div', { className: 'w-toolbar' }, action) : null);
|
|
523
|
+
return h('div', { className: 'dshw w-empty' }, h(Styles, { key: 'styles' }), h(Icon, { name: icon, size: 32 }), h('h2', null, title), children ? h('div', { className: 'w-muted' }, children) : null, action ? h('div', { className: 'w-toolbar' }, action) : null);
|
|
524
524
|
}
|
|
525
525
|
function Split({ list, detail, selected, onBack, backLabel, className, listWidth = 360 }) {
|
|
526
526
|
const ref = useRef(null);
|
|
@@ -564,7 +564,8 @@ function createWorkbenchUI(React) {
|
|
|
564
564
|
else if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); }
|
|
565
565
|
else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); }
|
|
566
566
|
}
|
|
567
|
-
return h('div', { className: 'w-overlay', onClick: event => { if (!busy && event.target === event.currentTarget) onClose(); } },
|
|
567
|
+
return h('div', { className: 'dshw w-overlay', onClick: event => { if (!busy && event.target === event.currentTarget) onClose(); } },
|
|
568
|
+
h(Styles, { key: 'styles' }),
|
|
568
569
|
h('section', { ref: panel, className: cx('w-dialog', className), role: 'dialog', 'aria-modal': true, 'aria-labelledby': id, tabIndex: -1, onKeyDown: keydown },
|
|
569
570
|
h('header', { className: 'w-dialog-header' }, h('h2', { id }, title), h(IconButton, { icon: 'close', label: closeLabel, disabled: busy, onClick: onClose })), h('div', { className: 'w-dialog-body' }, children)));
|
|
570
571
|
}
|
|
@@ -578,7 +579,7 @@ function createWorkbenchUI(React) {
|
|
|
578
579
|
.dshw{--w-bg:var(--dsw-alias-bg-layer-1,#fff);--w-soft:var(--dsw-alias-bg-layer-2,#f7f8fa);--w-text:var(--dsw-alias-label-primary,#18202c);--w-muted:var(--dsw-alias-label-secondary,#667085);--w-border:var(--dsw-alias-border-l3,#e7e9ef);--w-accent:var(--dsh-plugin-workbench-accent,#4f6bdb);--w-selected:color-mix(in srgb,var(--w-accent) 10%,var(--w-bg));--w-primary:var(--w-text);--w-on-primary:var(--w-bg);container-type:inline-size;container-name:dsh-workbench;color:var(--w-text);background:var(--w-bg);font:14px/1.65 var(--dsh-font-family-content,system-ui,-apple-system,"Segoe UI","Microsoft YaHei",sans-serif);min-width:0;max-width:100%;box-sizing:border-box;text-align:start;color-scheme:inherit}
|
|
579
580
|
.dshw *,.dshw *:before,.dshw *:after{box-sizing:border-box}.dshw h1,.dshw h2,.dshw h3,.dshw h4,.dshw p{margin:0}.dshw h1{font-size:30px;line-height:1.25;letter-spacing:-.025em;font-weight:650}.dshw h2{font-size:24px;line-height:1.35;font-weight:650;letter-spacing:-.015em;overflow-wrap:anywhere}.dshw h3,.dshw h4{font-size:16px;line-height:1.4;font-weight:600}.dshw a{color:var(--w-accent);text-underline-offset:3px;overflow-wrap:anywhere}.dshw button,.dshw input,.dshw select,.dshw textarea{font:inherit;color:inherit;max-width:100%}.dshw input:not([type=checkbox]):not([type=radio]):not([type=file]),.dshw select,.dshw textarea{background:var(--w-bg);border:1px solid var(--w-border);border-radius:8px;padding:8px 11px;min-width:0;line-height:1.5}.dshw input:not([type=checkbox]):not([type=radio]):not([type=file]),.dshw select{min-height:38px}.dshw textarea{resize:vertical}.dshw input[type=checkbox],.dshw input[type=radio]{width:16px;height:16px;flex-shrink:0;accent-color:var(--w-accent)}.dshw :focus-visible{outline:2px solid var(--w-accent);outline-offset:3px}.dshw button:disabled,.dshw input:disabled,.dshw select:disabled,.dshw textarea:disabled{opacity:.5;cursor:not-allowed}.dshw label{font-size:13px}.dshw fieldset{min-width:0;border:1px solid var(--w-border);border-radius:8px}.dshw summary{cursor:pointer;font-weight:550;list-style:none;display:flex;align-items:center;gap:8px}.dshw summary::-webkit-details-marker{display:none}.dshw summary:after{content:'';display:block;margin-inline-start:auto;width:7px;height:7px;border-inline-end:1.75px solid currentColor;border-bottom:1.75px solid currentColor;transform:rotate(45deg);flex-shrink:0}.dshw details[open]>summary:after{transform:rotate(225deg)}.dshw details>summary+*{margin-top:12px}.dshw pre{white-space:pre-wrap;overflow-wrap:anywhere;font:12px/1.7 ui-monospace,SFMono-Regular,Consolas,monospace;max-width:100%;background:var(--w-soft);border-radius:6px;padding:14px}.dshw img,.dshw video,.dshw iframe{max-width:100%}
|
|
580
581
|
.w-page{display:flex;flex-direction:column;position:relative;padding:0;min-height:540px;gap:0}.w-page[data-main=true]{height:100%;min-height:0;padding:calc(24px + var(--dsh-frame-top-clearance,0px)) 28px 0 max(28px,var(--dsh-frame-leading-clearance,0px));overflow:auto}.w-page-header{display:flex;justify-content:space-between;gap:24px;align-items:flex-start;padding-bottom:22px;flex-shrink:0}.w-heading{min-width:0}.w-subtitle{margin-top:8px!important;font-size:14px;color:var(--w-muted);line-height:1.6}.w-header-actions,.w-toolbar,.w-actions{display:flex;align-items:center;flex-wrap:wrap;gap:8px;min-width:0}.w-header-actions{justify-content:flex-end}.w-body,.w-tabs-layout{display:flex;flex-direction:column;flex:1;min-height:0;min-width:0}.w-body{overflow:auto}.w-tab-panel{flex:1;min-width:0;min-height:0;display:flex;flex-direction:column;overflow:auto}.w-tabs{display:flex;align-items:stretch;gap:20px;border-bottom:1px solid var(--w-border);flex-shrink:0;overflow-x:auto;scrollbar-width:thin}.dshw .w-tabs>button{border:0;border-bottom:2px solid transparent;background:transparent;padding:11px 8px 13px;white-space:nowrap;font-size:14px;font-weight:550;cursor:pointer;color:var(--w-muted);display:flex;align-items:center;gap:7px}.dshw .w-tabs>button[aria-selected=true]{border-bottom-color:var(--w-accent);color:var(--w-accent)}.w-count,.w-tag{font-size:12px;line-height:1.5;display:inline-flex;align-items:center;flex-shrink:0;background:var(--w-soft);border-radius:5px;padding:1px 6px;color:var(--w-muted)}.w-tabs [aria-selected=true] .w-count,.w-selected .w-tag{color:var(--w-accent);background:var(--w-selected)}
|
|
581
|
-
.dshw .w-button{display:inline-flex;justify-content:center;align-items:center;gap:7px;background:var(--w-bg);border:1px solid var(--w-border);border-radius:8px;padding:8px 12px;min-height:36px;line-height:1.4;font-size:14px;font-weight:500;cursor:pointer;text-decoration:none;white-space:normal}.dshw .w-button:not(:disabled):hover{background:var(--w-soft)}.dshw .w-primary{background:var(--w-primary);border-color:var(--w-primary);color:var(--w-on-primary)}.dshw .w-primary:not(:disabled):hover{background:var(--w-primary);opacity:.9}.dshw .w-ghost{background:transparent;border-color:transparent}.dshw .w-danger{color:var(--dsw-alias-state-error-primary,#b43c3c)}.dshw .w-icon-button{width:36px;min-width:36px;padding:8px}.dshw .w-button svg{flex-shrink:0}.w-muted{color:var(--w-muted);font-size:12px;line-height:1.6}.w-section{padding:24px 0;border-bottom:1px solid var(--w-border);min-width:0}.w-section>h3{margin-bottom:12px}.w-section>p+p{margin-top:8px}.w-fields{display:grid;gap:16px;min-width:0}.w-field{display:grid;gap:6px;min-width:0}.w-field>input,.w-field>select,.w-field>textarea{width:100%}.w-status{display:flex;align-items:flex-start;gap:8px;padding:11px 13px;margin:12px 0;border:1px solid var(--w-border);border-radius:8px;background:var(--w-soft);font-size:13px;overflow-wrap:anywhere;flex-shrink:0}.w-status>svg{flex-shrink:0;margin-top:2px}.w-status-error{color:var(--dsw-alias-state-error-primary,#ad3636)}.w-status-success{color:var(--dsw-alias-state-success-primary,#24794a)}.w-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:14px;max-width:580px;padding:48px 24px;margin:auto;min-height:280px;overflow-wrap:anywhere}.w-empty>svg{color:var(--w-muted)}.w-empty h2{font-size:20px}.w-empty .w-muted{font-size:14px}.w-empty .w-toolbar{justify-content:center}
|
|
582
|
+
.dshw .w-button{display:inline-flex;justify-content:center;align-items:center;gap:7px;background:var(--w-bg);border:1px solid var(--w-border);border-radius:8px;padding:8px 12px;min-height:36px;line-height:1.4;font-size:14px;font-weight:500;cursor:pointer;text-decoration:none;white-space:normal}.dshw .w-button:not(:disabled):hover{background:var(--w-soft)}.dshw .w-primary{background:var(--w-primary);border-color:var(--w-primary);color:var(--w-on-primary)}.dshw .w-primary:not(:disabled):hover{background:var(--w-primary);opacity:.9}.dshw .w-ghost{background:transparent;border-color:transparent}.dshw .w-danger{color:var(--dsw-alias-state-error-primary,#b43c3c)}.dshw .w-icon-button{width:36px;min-width:36px;padding:8px}.dshw .w-button svg{flex-shrink:0}.w-muted{color:var(--w-muted);font-size:12px;line-height:1.6}.w-section{padding:24px 0;border-bottom:1px solid var(--w-border);min-width:0}.w-section>h3{margin-bottom:12px}.w-section>p+p{margin-top:8px}.w-fields{display:grid;gap:16px;min-width:0}.w-field{display:grid;gap:6px;min-width:0}.w-field>input,.w-field>select,.w-field>textarea{width:100%}.w-status{display:flex;align-items:flex-start;gap:8px;padding:11px 13px;margin:12px 0;border:1px solid var(--w-border);border-radius:8px;background:var(--w-soft);font-size:13px;overflow-wrap:anywhere;flex-shrink:0}.w-status>svg{flex-shrink:0;margin-top:2px}.w-status-error{color:var(--dsw-alias-state-error-primary,#ad3636)}.w-status-success{color:var(--dsw-alias-state-success-primary,#24794a)}.w-status-warn{color:var(--dsw-alias-state-warning-primary,#8a5a00)}.w-empty{display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:14px;max-width:580px;padding:48px 24px;margin:auto;min-height:280px;overflow-wrap:anywhere}.w-empty>svg{color:var(--w-muted)}.w-empty h2{font-size:20px}.w-empty .w-muted{font-size:14px}.w-empty .w-toolbar{justify-content:center}
|
|
582
583
|
.w-split{display:grid;grid-template-columns:minmax(240px,var(--w-list-width)) minmax(0,1fr);min-height:460px;flex:1;min-width:0}.w-master{min-width:0;border-inline-end:1px solid var(--w-border);overflow:auto;padding-bottom:24px}.w-detail{min-width:0;padding:26px 28px;overflow:auto;overflow-wrap:anywhere;display:flex;flex-direction:column}.w-master-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;padding:20px 16px}.w-search{display:flex;align-items:center;gap:8px;border:1px solid var(--w-border);border-radius:8px;padding:0 10px;min-width:0;flex:1;background:var(--w-bg)}.w-search>svg{color:var(--w-muted);flex-shrink:0}.dshw .w-search>input{border:0!important;background:transparent!important;padding:8px 0!important;width:100%;outline-offset:0}.w-row{display:flex;gap:0;min-width:0;position:relative;border-bottom:1px solid var(--w-border);border-inline-start:3px solid transparent}.w-row-select{display:flex;align-items:flex-start;padding:21px 0 0 14px}.dshw .w-row-button{display:flex;flex-direction:column;align-items:stretch;gap:7px;text-align:start;width:100%;padding:18px 18px 18px 16px;border:0;background:transparent;color:inherit;min-width:0;cursor:pointer;line-height:1.5}.dshw .w-row-button:hover{background:var(--w-soft)}.w-row-head{display:flex;align-items:flex-start;gap:10px;justify-content:space-between;min-width:0}.w-row-head>strong{font-size:14px;line-height:1.5;font-weight:600;overflow-wrap:anywhere}.w-row-meta,.w-row-description{color:var(--w-muted);font-size:12px;line-height:1.6;overflow-wrap:anywhere}.w-row-description{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.w-selected{background:var(--w-selected);border-inline-start-color:var(--w-accent)}.w-back{display:none!important}.w-detail-title{margin-bottom:12px!important}.w-detail-meta{color:var(--w-muted);font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}.w-detail-footer{padding:24px 0;display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin-top:auto;border-top:1px solid var(--w-border)}.w-detail-footer .w-muted{flex:1;min-width:160px}.w-definition{display:grid;grid-template-columns:minmax(80px,120px) minmax(0,1fr);gap:8px 16px;font-size:14px;margin:20px 0}.w-definition dt{color:var(--w-muted)}.w-definition dd{margin:0;min-width:0;overflow-wrap:anywhere}
|
|
583
584
|
.w-switch-label{display:inline-flex;align-items:center;gap:8px;font-size:13px;position:relative;cursor:pointer}.w-switch-label>input{position:absolute;opacity:0;inset-inline-end:0;width:36px!important;height:22px!important;margin:0;cursor:pointer}.w-switch-track{width:36px;height:22px;border-radius:12px;display:block;background:var(--w-border);border:1px solid var(--w-border);pointer-events:none;padding:2px;transition:background .15s}.w-switch-track:before{content:'';display:block;width:16px;height:16px;border-radius:50%;background:#fff;box-shadow:0 1px 2px #0002;transition:transform .15s}.w-switch-label>input:checked+.w-switch-track{background:var(--w-accent);border-color:var(--w-accent)}.w-switch-label>input:checked+.w-switch-track:before{transform:translateX(14px)}.w-switch-label>input:focus-visible+.w-switch-track{outline:2px solid var(--w-accent);outline-offset:3px}.w-switch-label:has(>input:disabled){opacity:.5;cursor:not-allowed}
|
|
584
585
|
.w-overlay{position:fixed;inset:0;background:#0005;display:flex;justify-content:flex-end;z-index:1000;padding:12px;overflow:auto}.w-dialog{width:min(620px,100%);max-height:100%;display:flex;flex-direction:column;min-height:0;background:var(--w-bg);color:var(--w-text);border:1px solid var(--w-border);border-radius:12px;box-shadow:0 18px 70px #0003}.w-dialog-header{display:flex;justify-content:space-between;align-items:center;gap:16px;padding:20px 24px;border-bottom:1px solid var(--w-border);flex-shrink:0}.w-dialog-header>h2{font-size:20px}.w-dialog-body{overflow:auto;padding:20px 24px;min-height:0}.w-editor-grid{display:grid;grid-template-columns:210px minmax(0,1fr) 300px;min-height:500px;flex:1}.w-editor-list{padding:20px 12px;border-inline-end:1px solid var(--w-border);min-width:0}.w-editor-canvas{background:var(--w-soft);padding:20px;min-width:0;display:flex;flex-direction:column;gap:14px}.w-editor-inspector{padding:24px;border-inline-start:1px solid var(--w-border);min-width:0;overflow:auto}.w-editor-inspector h3{margin-bottom:18px}.w-preview-empty{display:flex;flex-direction:column;justify-content:center;align-items:center;text-align:center;gap:12px;aspect-ratio:16/9;min-height:180px;background:var(--w-soft);border:1px solid var(--w-border);border-radius:8px;padding:24px;color:var(--w-muted)}.w-content-pad{padding:24px 0}.w-stack{display:flex;flex-direction:column;gap:16px;min-width:0}.w-scroll-x{overflow:auto;max-width:100%}
|
|
@@ -587,7 +588,8 @@ function createWorkbenchUI(React) {
|
|
|
587
588
|
@media(max-width:700px){.w-page[data-main=true]{padding:calc(16px + var(--dsh-frame-top-clearance,0px)) 16px 0 max(16px,var(--dsh-frame-leading-clearance,0px))}.w-overlay{padding:8px}.w-dialog{width:100%}}
|
|
588
589
|
@media(prefers-reduced-motion:reduce){.dshw *,.dshw *:before{scroll-behavior:auto!important;transition:none!important;animation:none!important}}
|
|
589
590
|
`;
|
|
590
|
-
|
|
591
|
+
function Styles() { return h('style', null, styles); }
|
|
592
|
+
return { Icon, Button, IconButton, Page, Tabs, Status, Empty, Split, Row, Search, Switch, Dialog, Styles, register, styles };
|
|
591
593
|
}
|
|
592
594
|
|
|
593
595
|
// Editable browser entry. Build with node scripts/build-client.mjs.
|
|
@@ -750,6 +752,7 @@ let calendarHostContext;
|
|
|
750
752
|
".dshc-meta{color:var(--dsw-alias-label-tertiary,#6b7280);font-size:12px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
|
|
751
753
|
".dshc-tag{display:inline-block;font-size:11px;padding:1px 6px;border-radius:999px;background:color-mix(in srgb,var(--dsw-alias-label-primary,#111) 7%,transparent);color:var(--dsw-alias-label-tertiary,#6b7280);margin-left:6px}",
|
|
752
754
|
".dshc-empty{padding:26px 18px;text-align:center;color:var(--dsw-alias-label-tertiary,#6b7280)}",
|
|
755
|
+
".dshc-emptyhint{margin:0 0 6px;font-size:12px;line-height:1.6;color:var(--dsw-alias-label-tertiary,#6b7280)}",
|
|
753
756
|
".dshc-empty h3{color:var(--dsw-alias-label-primary,#111);margin:0 0 6px;font-size:14px}",
|
|
754
757
|
".dshc-empty code{background:var(--dsw-alias-bg-layer-2,rgba(0,0,0,.05));padding:1px 5px;border-radius:5px;font-size:12px}",
|
|
755
758
|
".dshc-alert{display:flex;gap:8px;align-items:flex-start;border-radius:10px;padding:8px 10px;font-size:12px;margin-bottom:10px;background:color-mix(in srgb,var(--dsw-alias-label-primary,#111) 5%,transparent)}",
|
|
@@ -1329,7 +1332,8 @@ let calendarHostContext;
|
|
|
1329
1332
|
return null;
|
|
1330
1333
|
return h("div", { className: "dshc-modalwrap", onMouseDown: (e) => { if (e.target === e.currentTarget)
|
|
1331
1334
|
props.onClose(); } }, [
|
|
1332
|
-
|
|
1335
|
+
// 宿主没有官方 Modal 时的兜底:至少给出与官方版相同的对话框语义(标题就是可及名)。
|
|
1336
|
+
h("div", { className: "dshc-modal", role: "dialog", "aria-modal": "true", "aria-label": props.title }, [
|
|
1333
1337
|
h("div", { style: { position: "relative" } }, [
|
|
1334
1338
|
h("div", { className: "dshc-drawertitle" }, props.title),
|
|
1335
1339
|
h("button", { type: "button", className: "dshc-btn ghost dshc-close", onClick: props.onClose, "aria-label": props.closeLabel || props.title }, "\u2715")
|
|
@@ -1504,6 +1508,9 @@ let calendarHostContext;
|
|
|
1504
1508
|
role: "button",
|
|
1505
1509
|
tabIndex: 0,
|
|
1506
1510
|
className: "dshc-cell" + (day.getMonth() !== anchor.getMonth() ? " out" : "") + (key === today ? " today" : ""),
|
|
1511
|
+
// 读屏只会念出格子里的日期数字,不说这一格是干什么的;补上「哪天 + 新建」的完整名字。
|
|
1512
|
+
"aria-label": formatDay(day, { withYear: true }) + " · " + t("action.new"),
|
|
1513
|
+
"aria-current": key === today ? "date" : undefined,
|
|
1507
1514
|
onClick: () => onCreateAt(day),
|
|
1508
1515
|
onKeyDown: (e) => { if (e.key === "Enter" || e.key === " ") {
|
|
1509
1516
|
e.preventDefault();
|
|
@@ -1860,7 +1867,7 @@ let calendarHostContext;
|
|
|
1860
1867
|
groups[index[key]].items.push(event);
|
|
1861
1868
|
}
|
|
1862
1869
|
if (groups.length === 0)
|
|
1863
|
-
return h("
|
|
1870
|
+
return h(W.Empty, { icon: "calendar", title: t("state.empty"), action: h(W.Button, { icon: "plus", variant: "primary", onClick: () => onCreateAt(new Date()) }, t("action.new")) });
|
|
1864
1871
|
return h("div", { className: "dshc-agenda" }, groups.map((group) => h("div", { className: "dshc-daygroup", key: group.key }, [
|
|
1865
1872
|
h("div", { className: "dshc-daylabel" }, [
|
|
1866
1873
|
h("b", null, formatDay(group.day)),
|
|
@@ -2816,6 +2823,11 @@ __stardustUpdatesGuard(React, "dsh-calendar", { busy: busy || importBusy || laye
|
|
|
2816
2823
|
notify(t("move.failed", { message: error !== null && error !== undefined && error.message ? error.message : String(error) }));
|
|
2817
2824
|
}
|
|
2818
2825
|
};
|
|
2826
|
+
/** 未连接日历时的点法:别让按钮「点了没反应」,直接打开连接设置并说明原因。 */
|
|
2827
|
+
const connectFirst = () => {
|
|
2828
|
+
setConnOpen(true);
|
|
2829
|
+
notify(calendarText('请先连接日历,再新建日程或查找空闲时段。', 'Connect a calendar before creating events or finding available time.'));
|
|
2830
|
+
};
|
|
2819
2831
|
const notify = (text) => { setBanner(text); setTimeout(() => setBanner((current) => (current === text ? null : current)), 2200); };
|
|
2820
2832
|
const title = view === "week" ? formatWeekTitle(anchor) : view === "agenda" ? t("view.agenda") : formatMonthTitle(anchor);
|
|
2821
2833
|
const step = (delta) => setAnchor((current) => (view === "week" ? addDays(current, delta * 7) : addMonthShift(current, delta)));
|
|
@@ -2887,25 +2899,31 @@ __stardustUpdatesGuard(React, "dsh-calendar", { busy: busy || importBusy || laye
|
|
|
2887
2899
|
h('div',{className:'calendar-view-controls',role:'group','aria-label':calendarText('日历视图','Calendar view')},VIEWS.map(name=>h(W.Button,{key:name,'aria-pressed':view === name,onClick:()=>{setView(name);storeView(name);}},t('view.'+name))),demo?h(W.Button,{onClick:()=>setDemo(false)},t('action.exitDemo')):h(W.IconButton,{icon:'refresh',label:t('action.refresh'),onClick:reload})));;
|
|
2888
2900
|
const body = () => {
|
|
2889
2901
|
if (demo === false && configured === false) {
|
|
2890
|
-
return h(
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
h(
|
|
2902
|
+
return h(W.Empty, {
|
|
2903
|
+
icon: "calendar",
|
|
2904
|
+
title: t("state.notConfigured"),
|
|
2905
|
+
action: h(React.Fragment, null, [
|
|
2894
2906
|
h(Btn, { key: "cfg", variant: "primary", onClick: () => setConnOpen(true) }, t("conn.button")),
|
|
2895
2907
|
h(Btn, { key: "demo", onClick: () => setDemo(true) }, t("action.demo"))
|
|
2896
2908
|
])
|
|
2897
|
-
|
|
2909
|
+
}, h("p", null, t("state.notConfiguredHint")));
|
|
2898
2910
|
}
|
|
2899
2911
|
if (configured === null)
|
|
2900
2912
|
return h("div", { className: "dshc-grid" }, Array.from({ length: 7 }, (_, i) => h("div", { className: "dshc-skel", key: i })));
|
|
2901
2913
|
if (data.loading === true && data.events.length === 0) {
|
|
2902
2914
|
return h("div", { className: "dshc-grid" }, Array.from({ length: 14 }, (_, i) => h("div", { className: "dshc-skel", key: i })));
|
|
2903
2915
|
}
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2916
|
+
const viewNode = view === "week"
|
|
2917
|
+
? h(WeekView, { anchor, events: visibleEvents, onPick: openEvent, onCreateAt: createAt, onReschedule: demo === true ? undefined : reschedule })
|
|
2918
|
+
: view === "agenda"
|
|
2919
|
+
? h(AgendaView, { events: visibleEvents, onPick: openEvent, onCreateAt: createAt })
|
|
2920
|
+
: h(MonthView, { anchor, events: visibleEvents, onPick: openEvent, onCreateAt: createAt });
|
|
2921
|
+
// 空范围只给一行说明 + 下一步;出错时不冒充「没有日程」,把解释权留给错误条。
|
|
2922
|
+
const emptyHint = demo === false && view !== "agenda" && data.loading !== true && data.events.length === 0
|
|
2923
|
+
&& (data.error === null || data.error === undefined);
|
|
2924
|
+
return emptyHint
|
|
2925
|
+
? h(React.Fragment, null, h("p", { className: "dshc-emptyhint", role: "status" }, calendarText("这段时间没有日程。点日期格或「新建日程」开始。", "Nothing scheduled in this range. Click a date or use New event.")), viewNode)
|
|
2926
|
+
: viewNode;
|
|
2909
2927
|
};
|
|
2910
2928
|
const openEvent = (event) => { setConfirmDelete(false); setSelected(event); };
|
|
2911
2929
|
const createAt = (day, hour) => {
|
|
@@ -2915,7 +2933,10 @@ __stardustUpdatesGuard(React, "dsh-calendar", { busy: busy || importBusy || laye
|
|
|
2915
2933
|
}
|
|
2916
2934
|
setDraft(draftAt(day, hour));
|
|
2917
2935
|
};
|
|
2918
|
-
|
|
2936
|
+
// 浮层面板不是 W.Page,拿不到 ui/workbench-ui 的样式表;W.Button 之类会变成裸控件。
|
|
2937
|
+
// 这里补一份 kit 自己的 stylesheet(唯一规范源),不再另画一套按钮。
|
|
2938
|
+
const content = h("div", { ref: rootRef, className: "dshc-root" + (compact === true ? " dshw" : "") }, [
|
|
2939
|
+
compact === true ? h("style", { key: "kit-styles" }, W.styles) : null,
|
|
2919
2940
|
h("div", { className: "dshc-shell" }, [
|
|
2920
2941
|
banner !== null ? h("div", { className: "dshc-alert demo", role: "status", "aria-live": "polite" }, banner) : null,
|
|
2921
2942
|
undo !== null
|
|
@@ -2994,8 +3015,8 @@ if(compact) return content;
|
|
|
2994
3015
|
return __stardustUpdatesInlinePage(React,h(W.Page,{workbench:props.workbench===true,title:t('section.title'),subtitle:calendarText('查看日程、安排时间和管理导入。','View events, plan time and manage imports.'),className:'calendar-workbench',actions:h(React.Fragment,null,
|
|
2995
3016
|
h(W.Button,{icon:'link',disabled:configured===null,onClick:()=>setConnOpen(true)},calendarText('日历连接','Calendar connection')),
|
|
2996
3017
|
h(W.Button,{icon:'upload',disabled:demo || importBusy,onClick:()=>setImportOpen(value=>!value)},t('import.open')),
|
|
2997
|
-
h(W.Button,{disabled:demo || configured
|
|
2998
|
-
h(W.Button,{variant:'primary',disabled:demo || configured
|
|
3018
|
+
h(W.Button,{disabled:demo || configured===null,onClick:()=>configured===true?setAvailabilityOpen(v=>!v):connectFirst()},calendarText('找空闲时段','Find available time')),
|
|
3019
|
+
h(W.Button,{variant:'primary',disabled:demo || configured===null,title:configured===true?undefined:calendarText('请先连接日历','Connect a calendar first'),onClick:()=>configured===true?setDraft(draftAt(anchor)):connectFirst()},t('action.new')))},h('style',null,CALENDAR_WORKBENCH_CSS),content),"dsh-calendar");
|
|
2999
3020
|
}
|
|
3000
3021
|
/** 月份平移:先跳到本月 1 号再加月,避免 1 月 31 日 +1 个月变成 3 月 3 日。 */
|
|
3001
3022
|
function addMonthShift(date, delta) {
|
|
@@ -3125,7 +3146,7 @@ calendarHostContext=ctx;W.register(ctx,{id:'dsh-calendar.workbench',label:()=>t(
|
|
|
3125
3146
|
exports.apply = apply;
|
|
3126
3147
|
exports.inject = inject;
|
|
3127
3148
|
return module.exports;
|
|
3128
|
-
} },{"name":"dsh-calendar","version":"0.1.0","hasWorkbench":true,"packageVersion":"0.14.
|
|
3149
|
+
} },{"name":"dsh-calendar","version":"0.1.0","hasWorkbench":true,"packageVersion":"0.14.4","label":"日历","labelEn":"Calendar","suiteComponent":true}));
|
|
3129
3150
|
|
|
3130
3151
|
})();
|
|
3131
3152
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-calendar",
|
|
3
|
-
"version": "0.14.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.14.4",
|
|
4
|
+
"description": "DSH 日历工作台:CalDAV 日程、月 / 周 / 议程视图、空闲时段建议与 ICS 预览导入。欢迎提交 issues 和 PR。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/index.d.ts",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "tsc -p tsconfig.json && node scripts/build-client.mjs && node scripts/build-updates.mjs",
|
|
29
29
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
30
|
-
"test": "
|
|
31
|
-
"prepublishOnly": "
|
|
30
|
+
"test": "npm run build && node --test \"test/*.test.mjs\"",
|
|
31
|
+
"prepublishOnly": "npm run build"
|
|
32
32
|
},
|
|
33
33
|
"dsh": {
|
|
34
34
|
"bundle": {
|