@jungherz-de/notionkit-elements 1.5.3 → 1.7.0
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/README.md +27 -18
- package/dist/components/base.js +346 -0
- package/dist/components/nk-ai-input-row.js +2 -1
- package/dist/components/nk-ai-msg.js +10 -3
- package/dist/components/nk-ai-thread.js +2 -1
- package/dist/components/nk-app.js +2 -1
- package/dist/components/nk-avatar-group.js +2 -1
- package/dist/components/nk-avatar.js +57 -0
- package/dist/components/nk-banner.js +2 -1
- package/dist/components/nk-block-host.js +2 -1
- package/dist/components/nk-board-view.js +4 -2
- package/dist/components/nk-breadcrumb.js +2 -1
- package/dist/components/nk-btn.js +31 -4
- package/dist/components/nk-callout.js +2 -1
- package/dist/components/nk-check.js +2 -1
- package/dist/components/nk-cmdk.js +3 -2
- package/dist/components/nk-code.js +2 -1
- package/dist/components/nk-comment.js +9 -6
- package/dist/components/nk-comments.js +2 -1
- package/dist/components/nk-danger-zone.js +2 -1
- package/dist/components/nk-database.js +16 -6
- package/dist/components/nk-divider.js +2 -1
- package/dist/components/nk-emoji-picker.js +2 -1
- package/dist/components/nk-empty.js +2 -1
- package/dist/components/nk-field.js +2 -1
- package/dist/components/nk-fields.js +2 -1
- package/dist/components/nk-filter-bar.js +59 -37
- package/dist/components/nk-heading.js +2 -1
- package/dist/components/nk-input.js +2 -1
- package/dist/components/nk-kbd.js +2 -1
- package/dist/components/nk-list-view.js +96 -0
- package/dist/components/nk-member-list.js +2 -1
- package/dist/components/nk-member-row.js +10 -6
- package/dist/components/nk-mention.js +2 -1
- package/dist/components/nk-menu-item.js +27 -3
- package/dist/components/nk-menu.js +88 -2
- package/dist/components/nk-modal.js +3 -2
- package/dist/components/nk-model-card.js +2 -1
- package/dist/components/nk-page-actions.js +2 -1
- package/dist/components/nk-page-cover.js +12 -11
- package/dist/components/nk-page-title.js +2 -1
- package/dist/components/nk-page.js +12 -4
- package/dist/components/nk-panel.js +61 -0
- package/dist/components/nk-panels.js +18 -0
- package/dist/components/nk-pop.js +2 -1
- package/dist/components/nk-profile-row.js +2 -1
- package/dist/components/nk-progress.js +5 -2
- package/dist/components/nk-prop.js +54 -0
- package/dist/components/nk-props.js +21 -0
- package/dist/components/nk-quote.js +2 -1
- package/dist/components/nk-radio.js +2 -1
- package/dist/components/nk-section-label.js +2 -1
- package/dist/components/nk-segmented.js +21 -1
- package/dist/components/nk-select.js +2 -1
- package/dist/components/nk-settings-pane.js +2 -1
- package/dist/components/nk-settings-user.js +2 -1
- package/dist/components/nk-sheet.js +97 -0
- package/dist/components/nk-sidebar.js +17 -37
- package/dist/components/nk-skeleton.js +2 -1
- package/dist/components/nk-slider.js +2 -1
- package/dist/components/nk-stat.js +2 -1
- package/dist/components/nk-stats.js +2 -1
- package/dist/components/nk-steps.js +61 -0
- package/dist/components/nk-switch.js +2 -1
- package/dist/components/nk-synced.js +2 -1
- package/dist/components/nk-tab-bar-item.js +2 -1
- package/dist/components/nk-tab-bar.js +2 -1
- package/dist/components/nk-tab.js +2 -1
- package/dist/components/nk-table-view.js +6 -2
- package/dist/components/nk-tabs.js +2 -1
- package/dist/components/nk-tag.js +2 -1
- package/dist/components/nk-template-btn.js +2 -1
- package/dist/components/nk-textarea.js +2 -1
- package/dist/components/nk-theme-toggle.js +2 -1
- package/dist/components/nk-toast.js +2 -1
- package/dist/components/nk-todo.js +2 -1
- package/dist/components/nk-toggle.js +2 -1
- package/dist/components/nk-topbar.js +2 -1
- package/dist/components/nk-tree-item.js +2 -1
- package/dist/components/nk-tree.js +2 -1
- package/dist/components/nk-workspace-switcher.js +2 -1
- package/dist/components/shared/avatar-BiqCaHOt.js +19 -0
- package/dist/components/shared/{focus-DXrK9oLe.js → focus-BNAChOXO.js} +12 -4
- package/dist/components/shared/{property-cell-CtXQpUjQ.js → property-cell-o7N30kAQ.js} +8 -3
- package/dist/notionkit-elements.esm.js +759 -120
- package/dist/notionkit-elements.js +767 -119
- package/dist/notionkit-elements.min.js +1 -1
- package/package.json +7 -6
- package/src/components/content/nk-progress.js +3 -1
- package/src/components/data/nk-ai-msg.js +8 -2
- package/src/components/data/nk-comment.js +7 -5
- package/src/components/data/nk-database.js +14 -5
- package/src/components/data/nk-filter-bar.js +57 -36
- package/src/components/data/nk-list-view.js +93 -0
- package/src/components/data/nk-table-view.js +2 -0
- package/src/components/forms/nk-btn.js +29 -3
- package/src/components/overlays/nk-menu-item.js +25 -2
- package/src/components/overlays/nk-menu.js +86 -1
- package/src/components/overlays/nk-sheet.js +95 -0
- package/src/components/page/nk-avatar.js +55 -0
- package/src/components/page/nk-member-row.js +8 -5
- package/src/components/page/nk-page-cover.js +10 -10
- package/src/components/page/nk-page.js +10 -3
- package/src/components/page/nk-panel.js +59 -0
- package/src/components/page/nk-panels.js +16 -0
- package/src/components/page/nk-prop.js +52 -0
- package/src/components/page/nk-props.js +19 -0
- package/src/components/page/nk-segmented.js +19 -0
- package/src/components/page/nk-steps.js +59 -0
- package/src/components/shell/nk-sidebar.js +15 -36
- package/src/index.js +18 -0
- package/src/util/avatar.js +17 -0
- package/src/util/focus.js +11 -3
- package/src/util/property-cell.js +7 -3
- package/dist/components/shared/base-C3eJwHKA.js +0 -366
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
// NotionKit v1.
|
|
1
|
+
// NotionKit v1.7.1 – Constructable Stylesheet
|
|
2
2
|
// Auto-generated by build-styles-js.mjs – do not edit manually.
|
|
3
3
|
|
|
4
4
|
// The :root and [data-theme="dark"] blocks that declare --nk-* …
|
|
5
|
-
const tokensCss = ":root{color-scheme:light;--nk-bg
|
|
5
|
+
const tokensCss = ":root{color-scheme:light;--nk-bg: #ffffff;--nk-bg-sidebar: #f9f8f7;--nk-bg-hover: rgba(55,53,47,.06);--nk-bg-active: rgba(55,53,47,.08);--nk-bg-callout: #f0efed;--nk-bg-code: #f7f6f3;--nk-bg-card: #ffffff;--nk-bg-input: rgba(242,241,238,.6);--nk-text: #2c2c2b;--nk-text-secondary: #7d7a75;--nk-text-tertiary: #91918e;--nk-text-sidebar: #5f5e5b;--nk-border: rgba(28,19,1,.11);--nk-border-strong: rgba(27,21,0,.19);--nk-accent: #2383e2;--nk-on-accent: #ffffff;--nk-danger: #cd3c3a;--nk-tag-gray-bg: #e3e2e0;--nk-tag-gray-text: #32302c;--nk-tag-brown-bg: #eee0da;--nk-tag-brown-text: #442a1e;--nk-tag-orange-bg: #fadec9;--nk-tag-orange-text: #49290e;--nk-tag-yellow-bg: #fdecc8;--nk-tag-yellow-text: #402c1b;--nk-tag-green-bg: #dbeddb;--nk-tag-green-text: #1c3829;--nk-tag-blue-bg: #d3e5ef;--nk-tag-blue-text: #183347;--nk-tag-purple-bg: #e8deee;--nk-tag-purple-text: #412454;--nk-tag-pink-bg: #f5e0e9;--nk-tag-pink-text: #4c2337;--nk-tag-red-bg: #ffe2dd;--nk-tag-red-text: #5d1715;--nk-tint-gray: #f1f1ef;--nk-color-gray: #787774;--nk-tint-brown: #f4eeee;--nk-color-brown: #9f6b53;--nk-tint-orange: #fbecdd;--nk-color-orange: #d9730d;--nk-tint-yellow: #fbf3db;--nk-color-yellow: #cb912f;--nk-tint-green: #edf3ec;--nk-color-green: #448361;--nk-tint-blue: #e7f3f8;--nk-color-blue: #337ea9;--nk-tint-purple: #f8f3fc;--nk-color-purple: #9065b0;--nk-tint-pink: #fcf1f6;--nk-color-pink: #c14c8a;--nk-tint-red: #fdebec;--nk-color-red: #cd3c3a;--nk-decor-purple: #9065b0;--nk-decor-blue: #529cca;--nk-decor-orange: #d9730d;--nk-scrim: rgba(15,15,15,.6);--nk-scrim-soft: rgba(15,15,15,.5);--nk-sidebar-width: 260px;--nk-tab-bar-height: 58px;--nk-radius: 6px;--nk-font: ui-sans-serif, -apple-system, \"Segoe UI\", Inter, Helvetica, Arial, sans-serif;--nk-font-mono: ui-monospace, \"SF Mono\", Menlo, Consolas, monospace;--nk-shadow-menu: rgba(15,15,15,.05) 0px 0px 0px 1px, rgba(15,15,15,.1) 0px 3px 6px, rgba(15,15,15,.2) 0px 9px 24px;--nk-shadow-card: 0 1px 2px rgba(0,0,0,.04);--nk-shadow-btn: inset 0 0 0 1px rgba(15,15,15,.1), 0 1px 2px rgba(15,15,15,.1);--nk-shadow-knob: 0 1px 2px rgba(0,0,0,.2);--nk-shadow-segment: 0 1px 2px rgba(0,0,0,.08)}[data-theme=dark]{color-scheme:dark;--nk-bg: #191919;--nk-bg-sidebar: #202020;--nk-bg-hover: rgba(255,255,255,.055);--nk-bg-active: rgba(255,255,255,.08);--nk-bg-callout: #252525;--nk-bg-code: #202020;--nk-bg-card: #202020;--nk-bg-input: rgba(255,255,255,.055);--nk-text: rgba(255,255,255,.81);--nk-text-secondary: rgba(255,255,255,.46);--nk-text-tertiary: rgba(255,255,255,.32);--nk-text-sidebar: rgba(255,255,255,.62);--nk-border: rgba(255,255,255,.094);--nk-border-strong: rgba(255,255,255,.16);--nk-accent: #529CCA;--nk-danger: #df5452;--nk-tag-gray-bg: #373737;--nk-tag-gray-text: rgba(255,255,255,.85);--nk-tag-brown-bg: #603b2c;--nk-tag-brown-text: rgba(255,255,255,.85);--nk-tag-orange-bg: #854c1d;--nk-tag-orange-text: rgba(255,255,255,.85);--nk-tag-yellow-bg: #89632a;--nk-tag-yellow-text: rgba(255,255,255,.85);--nk-tag-green-bg: #2b593f;--nk-tag-green-text: rgba(255,255,255,.85);--nk-tag-blue-bg: #28456c;--nk-tag-blue-text: rgba(255,255,255,.85);--nk-tag-purple-bg: #492f64;--nk-tag-purple-text: rgba(255,255,255,.85);--nk-tag-pink-bg: #69314c;--nk-tag-pink-text: rgba(255,255,255,.85);--nk-tag-red-bg: #6e3630;--nk-tag-red-text: rgba(255,255,255,.85);--nk-tint-gray: #252525;--nk-color-gray: #9b9b9b;--nk-tint-brown: #2e2724;--nk-color-brown: #ba856f;--nk-tint-orange: #36291f;--nk-color-orange: #c77d48;--nk-tint-yellow: #372e20;--nk-color-yellow: #ca8f3d;--nk-tint-green: #242b26;--nk-color-green: #529e72;--nk-tint-blue: #1f282d;--nk-color-blue: #5e87c9;--nk-tint-purple: #2a2430;--nk-color-purple: #9d68d3;--nk-tint-pink: #2e2328;--nk-color-pink: #d15796;--nk-tint-red: #332523;--nk-color-red: #df5452;--nk-shadow-menu: rgba(15,15,15,.2) 0px 0px 0px 1px, rgba(15,15,15,.4) 0px 3px 6px, rgba(15,15,15,.6) 0px 9px 24px;--nk-shadow-card: none;--nk-shadow-btn: inset 0 0 0 1px rgba(255,255,255,.1), 0 1px 2px rgba(0,0,0,.3)}";
|
|
6
6
|
|
|
7
7
|
// … and everything else, in two pieces around where they were.
|
|
8
|
-
const componentsHead = "[class*=nk-],[class*=nk-] *,[class*=nk-]
|
|
9
|
-
const componentsTail = ".nk-body{margin:0;min-height:100vh;min-height:100dvh;font-family:var(--nk-font);font-size:14px;background:var(--nk-bg);color:var(--nk-text);-webkit-font-smoothing:auto;transition:background .25s,color .25s}.nk-app{display:flex;height:100vh;height:100dvh;overflow:hidden}.nk-sidebar{width:calc(var(--nk-sidebar-width) + env(safe-area-inset-left,0px));min-width:calc(var(--nk-sidebar-width) + env(safe-area-inset-left,0px));padding-left:env(safe-area-inset-left,0);background:var(--nk-bg-sidebar);display:flex;flex-direction:column;border-right:1px solid var(--nk-border);transition:background .25s}.nk-workspace{display:flex;align-items:center;gap:8px;padding:10px 12px;margin:6px 8px 2px;border-radius:var(--nk-radius);cursor:pointer;font-weight:500;user-select:none}.nk-workspace:hover{background:var(--nk-bg-hover)}.nk-workspace .avatar,.nk-workspace ::slotted(.avatar),.nk-workspace ::slotted([slot=avatar]){width:22px;height:22px;border-radius:4px;background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-size:11px;font-weight:600;display:flex;align-items:center;justify-content:center}.nk-workspace .chev{margin-left:auto;color:var(--nk-text-tertiary);font-size:11px}.nk-sidebar-scroll{flex:1;overflow-y:auto;padding:4px 8px 16px}.nk-sidebar-scroll::-webkit-scrollbar{width:8px}.nk-sidebar-scroll::-webkit-scrollbar-thumb{background:var(--nk-border-strong);border-radius:4px}.nk-section-label{font-size:12px;font-weight:500;letter-spacing:.01em;color:var(--nk-text-tertiary);padding:14px 10px 4px;display:flex;justify-content:space-between;align-items:center}.nk-section-label .plus{cursor:pointer;border-radius:4px;padding:0 4px;font-size:13px;opacity:0;transition:opacity .15s}.nk-section-label:hover .plus{opacity:1}.nk-section-label .plus:hover{background:var(--nk-bg-hover)}.nk-sidebar-footer{padding:8px;border-top:1px solid var(--nk-border);color:var(--nk-text-sidebar);font-size:14px}.nk-sidebar-footer .nk-tree-item{min-height:26px}.nk-main{flex:1;display:flex;flex-direction:column;min-width:0}.nk-topbar{height:44px;display:flex;align-items:center;padding:0 max(12px,env(safe-area-inset-right,0px)) 0 max(12px,env(safe-area-inset-left,0px));gap:8px;flex-shrink:0}.nk-breadcrumb{display:flex;align-items:center;gap:4px;font-size:14px}.nk-breadcrumb .crumb,.nk-breadcrumb ::slotted(.crumb){padding:2px 6px;border-radius:4px;cursor:pointer;color:var(--nk-text-sidebar);display:flex;align-items:center;gap:5px}.nk-breadcrumb .crumb:hover{background:var(--nk-bg-hover)}a.crumb{text-decoration:none}.nk-breadcrumb .crumb.current,.nk-breadcrumb ::slotted(.crumb.current){color:var(--nk-text)}.nk-breadcrumb .sep{color:var(--nk-text-tertiary);font-size:12px}.nk-topbar-actions{margin-left:auto;display:flex;align-items:center;gap:4px}.nk-topbar-btn{padding:4px 8px;border-radius:var(--nk-radius);cursor:pointer;color:var(--nk-text-sidebar);font-size:14px;user-select:none;border:none;background:0 0;font-family:inherit}.nk-topbar-btn:hover{background:var(--nk-bg-hover)}.nk-topbar-btn ::slotted(svg),.nk-topbar-btn svg{width:16px;height:16px;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.nk-share-btn{font-size:14px;padding:4px 8px}.nk-topbar-actions ::slotted(.nk-topbar-meta),.nk-topbar-meta{padding:4px 8px;font-size:12px;color:var(--nk-text-tertiary);white-space:nowrap}.nk-theme-toggle{font-size:15px;width:30px;height:28px;padding:0}.nk-tab-bar{display:none;flex:none;align-items:stretch;gap:2px;position:sticky;bottom:0;z-index:30;box-sizing:border-box;height:calc(var(--nk-tab-bar-height) - 6px + max(6px,env(safe-area-inset-bottom,0px)));padding:6px max(4px,env(safe-area-inset-right,0px)) max(6px,env(safe-area-inset-bottom,0px)) max(4px,env(safe-area-inset-left,0px));background:var(--nk-bg-sidebar);border-top:1px solid var(--nk-border)}.nk-tab-bar.always{display:flex}.nk-tab-bar.fixed{position:fixed;left:0;right:0;bottom:0}.nk-tab-bar-spacer{display:none;flex:none;height:calc(var(--nk-tab-bar-height) - 6px + max(6px,env(safe-area-inset-bottom,0px)))}.nk-tab-bar.always.fixed+.nk-tab-bar-spacer{display:block}.nk-tab-bar.floating{position:fixed;left:max(12px,env(safe-area-inset-left,0px));right:max(12px,env(safe-area-inset-right,0px));bottom:calc(12px + env(safe-area-inset-bottom,0px));height:var(--nk-tab-bar-height);padding:6px;border:1px solid var(--nk-border);border-radius:16px;box-shadow:var(--nk-shadow-menu)}.nk-tab-bar-item{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;padding:4px 2px;border:none;border-radius:var(--nk-radius);background:0 0;font-family:inherit;font-size:10.5px;line-height:1.2;color:var(--nk-text-secondary);text-decoration:none;cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent}.nk-tab-bar-item:hover{color:var(--nk-text);background:var(--nk-bg-hover)}.nk-tab-bar-item.active{color:var(--nk-accent)}.nk-tab-bar-item:disabled{opacity:.5;cursor:not-allowed}.nk-tab-bar-item .icon,.nk-tab-bar-item ::slotted([slot=icon]){font-size:20px;line-height:1}.nk-tab-bar-item .label,.nk-tab-bar-item ::slotted(.label){max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.nk-tree-item{display:flex;align-items:center;gap:6px;padding:3px 8px 3px 10px;border-radius:var(--nk-radius);cursor:pointer;user-select:none;color:var(--nk-text-sidebar);position:relative;min-height:28px}.nk-tree-item:hover{background:var(--nk-bg-hover)}.nk-tree-item.active{background:var(--nk-bg-active);color:var(--nk-text);font-weight:500}.nk-tree-item.compact{min-height:26px}.nk-tree-item .icon,.nk-tree-item ::slotted(.icon),.nk-tree-item ::slotted([slot=icon]){font-size:15px;width:20px;text-align:center;flex-shrink:0}.nk-tree-item .label,.nk-tree-item ::slotted(.label){white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nk-tree-item .actions{margin-left:auto;display:none;gap:2px;color:var(--nk-text-tertiary)}.nk-tree-item:hover .actions{display:flex}.nk-tree-item .actions span{padding:0 3px;border-radius:3px;font-size:12px}.nk-tree-item .actions span:hover{background:var(--nk-bg-active)}.nk-tree-children{margin-left:14px;border-left:1px solid var(--nk-border);padding-left:4px;overflow:hidden}.nk-tree-children.collapsed{display:none}.nk-toggle-arrow{width:16px;height:16px;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;font-size:9px;color:var(--nk-text-tertiary);border-radius:3px;transition:transform .15s}.nk-toggle-arrow.open{transform:rotate(90deg)}.nk-kbd-hint{margin-left:auto;display:flex;gap:3px;align-items:center}.nk-kbd{font-family:inherit;font-size:10.5px;background:var(--nk-bg-callout);border:1px solid var(--nk-border-strong);border-bottom-width:2px;border-radius:4px;padding:0 4px}.nk-page-scroll{flex:1;overflow-y:auto}.nk-page-scroll::-webkit-scrollbar{width:10px}.nk-page-scroll::-webkit-scrollbar-thumb{background:var(--nk-border-strong);border-radius:5px;border:2px solid var(--nk-bg)}.nk-cover{height:200px;background:radial-gradient(ellipse at 20% 40%,color-mix(in srgb,var(--nk-decor-purple) 35%,transparent),transparent 55%),radial-gradient(ellipse at 80% 20%,color-mix(in srgb,var(--nk-decor-blue) 35%,transparent),transparent 55%),radial-gradient(ellipse at 60% 90%,color-mix(in srgb,var(--nk-decor-orange) 25%,transparent),transparent 55%),var(--nk-bg-callout)}.nk-page{max-width:760px;margin:0 auto;padding:24px max(64px,env(safe-area-inset-right,0px)) 120px max(64px,env(safe-area-inset-left,0px));font-size:16px;line-height:1.5}.nk-cover+.nk-page,.nk-page.covered{padding-top:0}.nk-page ::slotted(.nk-page-icon),.nk-page ::slotted([slot=icon]),.nk-page-icon{font-size:64px;line-height:1;margin-top:0;cursor:pointer;user-select:none;display:inline-block}.nk-cover+.nk-page .nk-page-icon,.nk-cover+.nk-page ::slotted(.nk-page-icon),.nk-cover+.nk-page ::slotted([slot=icon]),.nk-page.covered .nk-page-icon,.nk-page.covered ::slotted(.nk-page-icon),.nk-page.covered ::slotted([slot=icon]){margin-top:-42px}.nk-page-title{font-size:40px;font-weight:700;line-height:1.2;margin:8px 0 4px;outline:0;letter-spacing:0}.nk-page-meta{color:var(--nk-text-tertiary);font-size:13px;margin-bottom:24px;display:flex;gap:16px}.nk-page p.lead{font-size:16px;line-height:1.6;color:var(--nk-text-secondary);margin-bottom:20px}.nk-page ::slotted(p.lead){font-size:16px;line-height:1.6;color:var(--nk-text-secondary);margin-bottom:20px!important}.nk-heading{font-size:24px;font-weight:600;line-height:1.3;margin:32px 0 10px;display:flex;align-items:center;gap:8px}.nk-callout{display:flex;gap:10px;align-items:flex-start;background:var(--nk-bg-callout);border-radius:var(--nk-radius);padding:16px 16px 16px 12px;margin:16px 0;line-height:1.5}.nk-callout .c-icon,.nk-callout ::slotted(.c-icon),.nk-callout ::slotted([slot=icon]){font-size:17px}.nk-todo{display:flex;align-items:flex-start;gap:8px;padding:4px 0}.nk-todo input[type=checkbox]{appearance:none;width:16px;height:16px;margin-top:3px;border:1.4px solid var(--nk-border-strong);border-radius:2px;cursor:pointer;flex-shrink:0;position:relative;background:var(--nk-bg)}.nk-todo input[type=checkbox]:checked{background:var(--nk-accent);border-color:var(--nk-accent)}.nk-todo input[type=checkbox]:checked::after{content:\"✓\";color:var(--nk-on-accent);font-size:11px;position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.nk-todo input:checked+span{text-decoration:line-through;color:var(--nk-text-tertiary)}.nk-todo input:disabled{opacity:.5;cursor:not-allowed}.nk-toggle{margin:6px 0}.nk-toggle summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:6px;padding:4px 6px;border-radius:var(--nk-radius);font-weight:500;user-select:none}.nk-toggle summary::-webkit-details-marker{display:none}.nk-toggle summary:hover{background:var(--nk-bg-hover)}.nk-toggle summary::before{content:\"▸\";color:var(--nk-text-tertiary);font-size:11px;transition:transform .15s;display:inline-block}.nk-toggle[open] summary::before{transform:rotate(90deg)}.nk-toggle .toggle-body,.nk-toggle ::slotted(.toggle-body){padding:4px 0 8px 26px;color:var(--nk-text-secondary);line-height:1.55}.nk-divider{border:none;border-top:1px solid var(--nk-border);margin:24px 0}.nk-quote{border-left:3px solid var(--nk-text);padding:2px 0 2px 14px;margin:16px 0;color:var(--nk-text-secondary);line-height:1.5}.nk-quote .q-cite{display:block;margin-top:6px;font-size:12.5px;color:var(--nk-text-tertiary)}.nk-mention{display:inline-flex;align-items:center;gap:4px;padding:0 4px;border-radius:4px;font-weight:500;cursor:pointer;white-space:nowrap}.nk-mention:hover{background:var(--nk-bg-hover)}.nk-mention.person{color:var(--nk-text)}.nk-mention.person .mini-avatar,.nk-mention.person ::slotted(.mini-avatar),.nk-mention.person ::slotted([slot=avatar]){width:16px;height:16px;border-radius:50%;color:var(--nk-on-accent);font-size:8.5px;font-weight:600;display:inline-flex;align-items:center;justify-content:center}.nk-mention.page{color:var(--nk-text-secondary);text-decoration:underline;text-decoration-color:var(--nk-border-strong);text-underline-offset:2px}.nk-mention.date{color:var(--nk-color-orange)}.nk-inline-code{font-family:var(--nk-font-mono);font-size:85%;color:var(--nk-danger);background:color-mix(in srgb,var(--nk-danger) 8%,transparent);border-radius:4px;padding:1px 5px}.nk-code{background:var(--nk-bg-code);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:20px 24px;font-family:var(--nk-font-mono);font-size:13px;line-height:1.6;margin:14px 0;overflow-x:auto;color:var(--nk-text-secondary);white-space:pre;position:relative}.nk-code .lang{position:absolute;top:6px;right:10px;font-size:11px;color:var(--nk-text-tertiary);font-family:var(--nk-font)}.nk-code .tag,.nk-code ::slotted(.tag){color:var(--nk-accent)}.nk-code .attr,.nk-code ::slotted(.attr){color:var(--nk-color-orange)}.nk-database{margin:12px 0 8px}.nk-db-tabs{display:flex;gap:2px;align-items:center;padding:0 0 6px;margin-bottom:0;font-size:14px}.nk-db-tab{padding:4px 8px;cursor:pointer;color:var(--nk-text-secondary);border-radius:var(--nk-radius);user-select:none;line-height:20px;display:flex;align-items:center;gap:6px}.nk-db-tab:hover{color:var(--nk-text);background:var(--nk-bg-hover)}.nk-db-tab.active{color:var(--nk-text);background:var(--nk-bg-active);font-weight:500}.nk-db-tab .badge,.nk-db-tab ::slotted(.badge){background:var(--nk-bg-callout);border-radius:8px;font-size:11px;padding:0 6px;color:var(--nk-text-tertiary)}.nk-table-wrap{overflow-x:auto}.nk-table{width:100%;border-collapse:collapse;font-size:14px}.nk-table th{text-align:left;font-weight:400;color:var(--nk-text-secondary);height:36px;padding:0 8px;border-bottom:1px solid var(--nk-border);border-right:1px solid var(--nk-border);font-size:14px;white-space:nowrap;user-select:none;cursor:pointer}.nk-table th:hover{background:var(--nk-bg-hover)}.nk-table th .th-icon,.nk-table th ::slotted(.th-icon){margin-right:6px;font-size:13px;color:var(--nk-text-tertiary)}.nk-table td{height:36px;padding:6px 8px;line-height:1.5;border-bottom:1px solid var(--nk-border);border-right:1px solid var(--nk-border);white-space:nowrap;vertical-align:middle}.nk-table td:last-child,.nk-table th:last-child{border-right:none}.nk-table td.wrap,.nk-table.wrap td{white-space:normal;vertical-align:top}.nk-table tbody tr:hover{background:var(--nk-bg-hover)}.nk-table .row-title{display:flex;align-items:center;gap:7px;font-weight:500;cursor:pointer}.nk-table .row-title:hover{text-decoration:underline;text-decoration-color:var(--nk-text-tertiary)}.nk-table .date-cell{color:var(--nk-text-secondary)}.nk-table .person-cell{display:flex;align-items:center;gap:6px;color:var(--nk-text-secondary)}.nk-table .person-cell .mini-avatar,.nk-table .person-cell ::slotted(.mini-avatar){width:20px;height:20px;border-radius:50%;font-size:10px;color:var(--nk-on-accent);display:inline-flex;align-items:center;justify-content:center;font-weight:600}.nk-new-row,.nk-table .new-row{color:var(--nk-text-tertiary);cursor:pointer;padding:8px;display:flex;align-items:center;gap:7px;font-size:14px}.nk-new-row:hover,.nk-table .new-row:hover{background:var(--nk-bg-hover)}.nk-tag{display:inline-flex;align-items:center;max-width:100%;height:20px;padding:0 6px;border-radius:3px;font-size:14px;font-weight:400;line-height:20px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;background:var(--nk-tag-gray-bg);color:var(--nk-tag-gray-text)}.nk-tag.gray{background:var(--nk-tag-gray-bg);color:var(--nk-tag-gray-text)}.nk-tag.brown{background:var(--nk-tag-brown-bg);color:var(--nk-tag-brown-text)}.nk-tag.orange{background:var(--nk-tag-orange-bg);color:var(--nk-tag-orange-text)}.nk-tag.yellow{background:var(--nk-tag-yellow-bg);color:var(--nk-tag-yellow-text)}.nk-tag.green{background:var(--nk-tag-green-bg);color:var(--nk-tag-green-text)}.nk-tag.blue{background:var(--nk-tag-blue-bg);color:var(--nk-tag-blue-text)}.nk-tag.purple{background:var(--nk-tag-purple-bg);color:var(--nk-tag-purple-text)}.nk-tag.pink{background:var(--nk-tag-pink-bg);color:var(--nk-tag-pink-text)}.nk-tag.red{background:var(--nk-tag-red-bg);color:var(--nk-tag-red-text)}.nk-progress{width:110px;height:6px;border-radius:3px;background:var(--nk-tint-blue);overflow:hidden;display:inline-block}.nk-progress>i{display:block;height:100%;background:var(--nk-color-blue);border-radius:3px}.nk-progress-label{font-size:12px;color:var(--nk-text-tertiary);margin-left:7px}.nk-board{display:none;gap:12px;padding:14px 2px;overflow-x:auto}.nk-board.active{display:flex}.nk-board-col{min-width:220px;width:220px;flex-shrink:0}.nk-board-col-header{display:flex;align-items:center;gap:7px;margin-bottom:8px;font-size:13.5px;font-weight:500}.nk-board-col-header .count{color:var(--nk-text-tertiary);font-weight:400}.nk-card{background:var(--nk-bg-card);border:1px solid var(--nk-border);border-radius:8px;padding:10px 12px;margin-bottom:8px;cursor:grab;box-shadow:var(--nk-shadow-card);transition:border-color .15s}.nk-card:hover{border-color:var(--nk-border-strong)}.nk-card .card-title,.nk-card ::slotted(.card-title){font-weight:500;margin-bottom:7px;display:flex;gap:6px;align-items:center}.nk-card .card-meta,.nk-card ::slotted(.card-meta){display:flex;gap:6px;flex-wrap:wrap;align-items:center;font-size:12px;color:var(--nk-text-secondary)}.nk-field{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:9px 0}.nk-field .f-label,.nk-field ::slotted(.f-label),.nk-field ::slotted([slot=label]){font-size:14px}.nk-field .f-desc,.nk-field ::slotted(.f-desc),.nk-field ::slotted([slot=desc]){font-size:12px;color:var(--nk-text-secondary);margin-top:2px;line-height:1.45}.nk-field .f-control,.nk-field ::slotted(.f-control){flex-shrink:0}.nk-field.stacked,.nk-fields>.nk-field{flex-direction:column;align-items:stretch;gap:6px;min-width:0}.nk-field.stacked .f-control,.nk-field.stacked .nk-input,.nk-field.stacked .nk-select,.nk-field.stacked .nk-textarea,.nk-fields>.nk-field .f-control,.nk-fields>.nk-field .nk-input,.nk-fields>.nk-field .nk-select,.nk-fields>.nk-field .nk-textarea{width:100%;min-width:0}.nk-field.compact,.nk-fields>.nk-field{padding:0;gap:4px;min-width:0}.nk-field.compact .f-label,.nk-field.compact ::slotted([slot=label]),.nk-fields>.nk-field .f-label,.nk-fields>.nk-field ::slotted([slot=label]){font-size:12px;color:var(--nk-text-tertiary)}.nk-fields{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px 12px;padding:9px 0}.nk-fields>.nk-field{min-width:0}.nk-input,.nk-select,.nk-textarea{font-family:inherit;font-size:14px;line-height:20px;color:var(--nk-text);background:var(--nk-bg-input);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:5px 10px;outline:0;transition:border-color .15s,box-shadow .15s;min-width:210px}.nk-input:hover,.nk-select:hover,.nk-textarea:hover{border-color:var(--nk-border-strong)}.nk-input:focus,.nk-select:focus,.nk-textarea:focus{border-color:color-mix(in srgb,var(--nk-accent) 60%,transparent);box-shadow:0 0 0 2px color-mix(in srgb,var(--nk-accent) 30%,transparent)}.nk-input::placeholder,.nk-textarea::placeholder{color:var(--nk-text-tertiary)}.nk-input.wide,.nk-select.wide,.nk-textarea.wide{width:100%;min-width:0}.nk-input[type=date],.nk-input[type=datetime-local],.nk-input[type=month],.nk-input[type=time]{appearance:none}.nk-input::-webkit-date-and-time-value{text-align:start;min-height:1lh}.nk-select.compact{min-width:120px}.nk-textarea{resize:vertical;min-height:70px;line-height:1.5}.nk-select{appearance:none;cursor:pointer;padding-right:26px;background-image:linear-gradient(45deg,transparent 50%,var(--nk-text-tertiary) 50%),linear-gradient(135deg,var(--nk-text-tertiary) 50%,transparent 50%);background-position:calc(100% - 14px) 55%,calc(100% - 10px) 55%;background-size:4px 4px;background-repeat:no-repeat}.nk-btn{font-family:inherit;font-size:14px;line-height:20px;font-weight:500;border-radius:var(--nk-radius);cursor:pointer;padding:3px 12px;border:1px solid transparent;transition:background .15s,border-color .15s,box-shadow .15s,opacity .15s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap}.nk-btn ::slotted(svg),.nk-btn svg{width:15px;height:15px;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.nk-btn.primary{background:var(--nk-accent);color:var(--nk-on-accent)}.nk-btn.primary:hover{opacity:.88}.nk-btn.secondary{background:var(--nk-bg-card);color:var(--nk-text);box-shadow:var(--nk-shadow-btn)}.nk-btn.secondary:hover{background:color-mix(in srgb,var(--nk-bg-card),var(--nk-text) 6%)}.nk-btn.danger{background:var(--nk-bg-card);color:var(--nk-danger);box-shadow:var(--nk-shadow-btn)}.nk-btn.danger:hover{background:color-mix(in srgb,var(--nk-danger) 8%,var(--nk-bg-card))}.nk-btn.danger-solid{background:var(--nk-danger);color:var(--nk-on-accent)}.nk-btn.danger-solid:hover{opacity:.88}.nk-btn.small{padding:1px 8px;font-size:13px;line-height:20px}a.nk-btn{text-decoration:none}.nk-btn:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.nk-switch{position:relative;width:34px;height:20px;flex-shrink:0;appearance:none;border:none;cursor:pointer;border-radius:20px;background:var(--nk-border-strong);transition:background .2s}.nk-switch::after{content:\"\";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--nk-on-accent);transition:transform .2s;box-shadow:var(--nk-shadow-knob)}.nk-switch:checked,.nk-switch[aria-checked=true]{background:var(--nk-accent)}.nk-switch:checked::after,.nk-switch[aria-checked=true]::after{transform:translateX(14px)}.nk-switch:disabled{opacity:.5;cursor:not-allowed}.nk-switch-label{display:inline-flex;align-items:flex-start;gap:8px;font-size:14px;cursor:pointer}.nk-switch-label>.nk-switch{font-size:inherit;line-height:inherit;margin-top:max(0px,calc((1lh - 20px)/ 2))}.nk-switch-label>span{padding-top:max(0px,calc((20px - 1lh)/ 2))}.nk-switch-label:has(.nk-switch:disabled){cursor:not-allowed;color:var(--nk-text-tertiary)}.nk-check{display:flex;align-items:flex-start;gap:8px;padding:4px 0;font-size:14px;cursor:pointer}.nk-check input{appearance:none;width:16px;height:16px;flex-shrink:0;border:1.4px solid var(--nk-border-strong);border-radius:3px;cursor:pointer;position:relative;background:var(--nk-bg);font-size:inherit;line-height:inherit;margin-top:max(0px,calc((1lh - 16px)/ 2))}.nk-check input[type=radio]{border-radius:50%}.nk-check input:checked{background:var(--nk-accent);border-color:var(--nk-accent)}.nk-check input:checked::after{content:\"✓\";color:var(--nk-on-accent);font-size:10.5px;position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.nk-check input[type=radio]:checked::after{content:\"●\";font-size:7px}.nk-check input:disabled{opacity:.5;cursor:not-allowed}.nk-check input:disabled+*{opacity:.6}.nk-slider{width:210px;accent-color:var(--nk-accent);cursor:pointer}.nk-slider-value{font-size:12.5px;color:var(--nk-text-tertiary);margin-top:3px}.nk-profile-row{display:flex;align-items:center;gap:14px;padding:8px 0}.nk-profile-row .big-avatar,.nk-profile-row ::slotted(.big-avatar),.nk-profile-row ::slotted([slot=avatar]){width:56px;height:56px;border-radius:50%;background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-size:20px;font-weight:600;display:flex;align-items:center;justify-content:center}.nk-model-card{border:1px solid var(--nk-border-strong);border-radius:8px;padding:12px 14px;margin-bottom:10px;cursor:pointer;display:flex;align-items:flex-start;gap:11px;transition:border-color .15s,background .15s}.nk-model-card:hover{background:var(--nk-bg-hover)}.nk-model-card.selected{border-color:var(--nk-accent);background:color-mix(in srgb,var(--nk-accent) 6%,transparent)}.nk-model-card .m-radio{width:15px;height:15px;border-radius:50%;flex-shrink:0;margin-top:2px;border:1.4px solid var(--nk-border-strong);position:relative}.nk-model-card.selected .m-radio{border-color:var(--nk-accent)}.nk-model-card.selected .m-radio::after{content:\"\";position:absolute;inset:3px;border-radius:50%;background:var(--nk-accent)}.nk-model-card .m-name,.nk-model-card ::slotted(.m-name),.nk-model-card ::slotted([slot=title]){font-weight:500;font-size:14px;display:flex;align-items:center;gap:7px}.nk-model-card .m-desc,.nk-model-card ::slotted(.m-desc),.nk-model-card ::slotted([slot=desc]){font-size:12px;color:var(--nk-text-secondary);margin-top:2px;line-height:1.45}.nk-danger-zone{border:1px solid color-mix(in srgb,var(--nk-danger) 40%,transparent);border-radius:8px;padding:14px 16px;margin-top:26px}.nk-danger-zone .dz-title{color:var(--nk-danger);font-weight:600;font-size:13px;margin-bottom:8px}.nk-member-row{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--nk-border)}.nk-member-list ::slotted(.nk-member-row:last-child),.nk-member-list>.nk-member-row:last-child,.nk-member-row.last{border-bottom:none}.nk-member-row .mini-avatar,.nk-member-row ::slotted(.mini-avatar),.nk-member-row ::slotted([slot=avatar]){width:28px;height:28px;border-radius:50%;color:var(--nk-on-accent);display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600;flex-shrink:0}.nk-member-row>:has(> .m-mail){min-width:0}.nk-member-row .m-mail{font-size:12px;color:var(--nk-text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.nk-member-row .nk-select{min-width:120px;margin-left:auto}.nk-member-row ::slotted([slot=role]){margin-left:auto}.nk-modal-backdrop{position:fixed;inset:0;background:var(--nk-scrim);padding:env(safe-area-inset-top,0) env(safe-area-inset-right,0) env(safe-area-inset-bottom,0) env(safe-area-inset-left,0);display:flex;align-items:center;justify-content:center;z-index:100;opacity:0;pointer-events:none;transition:opacity .2s}.nk-modal-backdrop.open{opacity:1;pointer-events:auto}.nk-modal{width:min(1150px,92vw);height:min(715px,86vh);max-width:100%;max-height:100%;background:var(--nk-bg);border-radius:10px;box-shadow:var(--nk-shadow-menu);display:flex;overflow:hidden;transform:scale(.98) translateY(6px);transition:transform .2s}.nk-modal-backdrop.open .nk-modal{transform:scale(1) translateY(0)}.nk-settings-nav{width:240px;min-width:240px;background:var(--nk-bg-sidebar);border-right:1px solid var(--nk-border);padding:10px 8px;overflow-y:auto;flex-shrink:0}.nk-settings-user{display:flex;align-items:center;gap:9px;padding:6px 10px 12px;margin-bottom:4px}.nk-settings-user .avatar,.nk-settings-user ::slotted(.avatar),.nk-settings-user ::slotted([slot=avatar]){width:34px;height:34px;border-radius:50%;background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-weight:600;font-size:13px;display:flex;align-items:center;justify-content:center}.nk-settings-user .name{font-weight:500;font-size:14px}.nk-settings-user .mail{font-size:12px;color:var(--nk-text-secondary)}.nk-settings-nav .nk-tree-item{min-height:28px}.nk-settings-nav .nk-tree-item.active{background:var(--nk-bg-active);color:var(--nk-text);font-weight:500}.nk-settings-content{flex:1;overflow-y:auto;padding:36px 60px 80px;min-width:0}.nk-settings-content::-webkit-scrollbar{width:10px}.nk-settings-content::-webkit-scrollbar-thumb{background:var(--nk-border-strong);border-radius:5px;border:2px solid var(--nk-bg)}.nk-settings-pane{display:none;max-width:800px}.nk-settings-pane.active{display:block}.nk-settings-pane>h2{font-size:22px;font-weight:600;line-height:1.3;margin-bottom:20px}.nk-settings-pane>h3{font-size:16px;font-weight:500;padding-bottom:8px;border-bottom:1px solid var(--nk-border);margin:30px 0 12px}.nk-settings-pane ::slotted(h2){font-size:22px;font-weight:600;line-height:1.3;padding:0!important;margin:0 0 20px!important}.nk-settings-pane ::slotted(h3){font-size:16px;font-weight:500;border:0;border-bottom:1px solid var(--nk-border);padding:0 0 8px!important;margin:30px 0 12px!important}.nk-pop{background:var(--nk-bg);border-radius:10px;box-shadow:var(--nk-shadow-menu);padding:10px;width:296px}.nk-emoji-search{width:100%;font-family:inherit;font-size:14px;color:var(--nk-text);background:var(--nk-bg-input);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:6px 10px;outline:0;margin-bottom:8px}.nk-emoji-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:2px}.nk-emoji-grid ::slotted(span),.nk-emoji-grid span{font-size:18px;text-align:center;padding:4px 0;border-radius:5px;cursor:pointer;user-select:none}.nk-emoji-grid span:hover{background:var(--nk-bg-hover)}.nk-emoji-cats{display:flex;gap:2px;margin-top:8px;padding-top:8px;border-top:1px solid var(--nk-border)}.nk-emoji-cats span{font-size:14px;padding:3px 7px;border-radius:5px;cursor:pointer;color:var(--nk-text-tertiary);filter:grayscale(1);opacity:.6}.nk-emoji-cats span.active,.nk-emoji-cats span:hover{filter:none;opacity:1;background:var(--nk-bg-hover)}.nk-menu{padding:5px;width:230px}.nk-menu-item{display:flex;align-items:center;gap:9px;padding:4px 8px;min-height:28px;border-radius:5px;cursor:pointer;font-size:14px;user-select:none}.nk-menu-item:hover{background:var(--nk-bg-hover)}.nk-menu-item .m-icon,.nk-menu-item ::slotted(.m-icon),.nk-menu-item ::slotted([slot=icon]){width:17px;text-align:center;font-size:14px}.nk-menu-item .m-shortcut,.nk-menu-item ::slotted(.m-shortcut){margin-left:auto;font-size:12px;color:var(--nk-text-tertiary)}.nk-menu-item.danger{color:var(--nk-danger)}.nk-menu-sep{border-top:1px solid var(--nk-border);margin:5px 4px}.nk-menu-label{font-size:12px;color:var(--nk-text-tertiary);padding:5px 8px 2px}.nk-cmdk-backdrop{position:fixed;inset:0;background:var(--nk-scrim-soft);display:flex;justify-content:center;align-items:flex-start;padding:max(14vh,env(safe-area-inset-top,0px)) env(safe-area-inset-right,0) env(safe-area-inset-bottom,0) env(safe-area-inset-left,0);z-index:110;opacity:0;pointer-events:none;transition:opacity .18s}.nk-cmdk-backdrop.open{opacity:1;pointer-events:auto}.nk-cmdk{max-width:100%;width:min(560px,92vw);background:var(--nk-bg);border-radius:12px;box-shadow:var(--nk-shadow-menu);overflow:hidden;transform:scale(.98);transition:transform .18s}.nk-cmdk-backdrop.open .nk-cmdk{transform:scale(1)}.nk-cmdk-input-row{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--nk-border)}.nk-cmdk-input-row input{flex:1;border:none;outline:0;background:0 0;font-family:inherit;font-size:16px;color:var(--nk-text)}.nk-cmdk-input-row input::placeholder{color:var(--nk-text-tertiary)}.nk-cmdk-list{max-height:320px;overflow-y:auto;padding:6px}.nk-cmdk-group{font-size:12px;color:var(--nk-text-tertiary);padding:8px 10px 3px}.nk-cmdk-item{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer;font-size:14px;user-select:none}.nk-cmdk-item.selected{background:var(--nk-bg-active)}.nk-cmdk-item .m-icon,.nk-cmdk-item ::slotted(.m-icon),.nk-cmdk-item ::slotted([slot=icon]){width:17px;text-align:center;font-size:14px}.nk-cmdk-item .m-shortcut,.nk-cmdk-item ::slotted(.m-shortcut){margin-left:auto;font-size:12px;color:var(--nk-text-tertiary)}.nk-cmdk-empty{padding:30px;text-align:center;color:var(--nk-text-tertiary);font-size:13.5px}.nk-cmdk-footer{display:flex;gap:14px;padding:8px 16px;border-top:1px solid var(--nk-border);font-size:11.5px;color:var(--nk-text-tertiary)}.nk-toast{position:fixed;bottom:max(20px,calc(env(safe-area-inset-bottom,0px) + 12px));left:50%;transform:translateX(-50%) translateY(80px);z-index:120;width:max-content;max-width:calc(100% - 32px);background:var(--nk-text);color:var(--nk-bg);padding:8px 16px;border-radius:8px;font-size:14px;opacity:0;transition:.3s;pointer-events:none;box-shadow:var(--nk-shadow-menu);display:flex;gap:8px;align-items:center}.nk-toast.show{opacity:1;transform:translateX(-50%) translateY(0)}.nk-gallery-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(280px,100%),1fr));gap:20px 32px;margin:12px 0}.nk-g-item>h4{font-size:12px;font-weight:500;color:var(--nk-text-tertiary);text-transform:uppercase;letter-spacing:.04em;margin-bottom:8px}.nk-g-item ::slotted(h4){font-size:12px;font-weight:500;color:var(--nk-text-tertiary);text-transform:uppercase;letter-spacing:.04em;margin-bottom:8px!important}.nk-tabs{display:flex;gap:2px;border-bottom:1px solid var(--nk-border);font-size:14px}.nk-tab{padding:7px 11px;cursor:pointer;color:var(--nk-text-secondary);border-bottom:2px solid transparent;margin-bottom:-1px;user-select:none}.nk-tab:hover{color:var(--nk-text)}.nk-tab.active{color:var(--nk-text);border-bottom-color:var(--nk-text);font-weight:500}.nk-tab-panel{padding:12px 2px;color:var(--nk-text-secondary);line-height:1.55;font-size:14px}.nk-template-btn{display:flex;align-items:center;gap:8px;width:100%;font-family:inherit;font-size:14px;color:var(--nk-text-secondary);background:var(--nk-bg-callout);border:none;border-radius:var(--nk-radius);padding:8px 12px;cursor:pointer;margin-bottom:6px;text-align:left}.nk-template-btn:hover{background:var(--nk-bg-hover)}.nk-stats{display:flex;gap:10px}.nk-stat{flex:1;border:1px solid var(--nk-border);border-radius:8px;padding:12px 14px}.nk-stat .s-label,.nk-stat ::slotted(.s-label),.nk-stat ::slotted([slot=label]){font-size:12px;color:var(--nk-text-secondary);margin-bottom:4px}.nk-stat .s-value,.nk-stat ::slotted(.s-value),.nk-stat ::slotted([slot=value]){font-size:22px;font-weight:600;letter-spacing:-.01em}.nk-stat .s-delta,.nk-stat ::slotted(.s-delta),.nk-stat ::slotted([slot=delta]){font-size:12px;margin-top:3px}.nk-stat .s-delta.up,.nk-stat ::slotted(.s-delta.up),.nk-stat ::slotted([slot=delta].up){color:var(--nk-color-green)}.nk-stat .s-delta.down,.nk-stat ::slotted(.s-delta.down),.nk-stat ::slotted([slot=delta].down){color:var(--nk-danger)}.nk-synced{border:1.5px solid color-mix(in srgb,var(--nk-danger) 55%,transparent);border-radius:8px;padding:12px 14px;position:relative;margin:8px 0}.nk-synced .synced-badge{position:absolute;top:-9px;right:10px;font-size:11px;background:var(--nk-danger);color:var(--nk-on-accent);border-radius:8px;padding:1px 8px}.nk-segmented{display:inline-flex;background:var(--nk-bg-callout);border-radius:7px;padding:2px}.nk-segmented button{font-family:inherit;font-size:14px;border:none;background:0 0;color:var(--nk-text-secondary);padding:4px 12px;border-radius:5px;cursor:pointer}.nk-segmented ::slotted(button){font-family:inherit;font-size:14px;border:none;background:0 0;color:var(--nk-text-secondary);padding:4px 12px!important;border-radius:5px;cursor:pointer}.nk-segmented ::slotted(button.active),.nk-segmented button.active{background:var(--nk-bg);color:var(--nk-text);font-weight:500;box-shadow:var(--nk-shadow-segment)}.nk-segmented.wrap{flex-wrap:wrap}.nk-segmented.scroll{max-width:100%;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}.nk-segmented.scroll::-webkit-scrollbar{display:none}.nk-segmented.scroll ::slotted(button),.nk-segmented.scroll button{flex-shrink:0;white-space:nowrap}.nk-banner{display:flex;align-items:center;gap:10px;font-size:14px;border-radius:8px;padding:10px 14px;margin-bottom:8px;color:var(--nk-text)}.nk-banner.info{background:var(--nk-tint-blue)}.nk-banner.success{background:var(--nk-tint-green)}.nk-banner.warning{background:var(--nk-tint-yellow)}.nk-banner.danger{background:var(--nk-tint-red)}.nk-banner .b-action,.nk-banner ::slotted(.b-action),.nk-banner ::slotted([slot=action]){margin-left:auto;font-weight:500;cursor:pointer;text-decoration:underline;text-underline-offset:2px}.nk-avatar-group{display:flex}.nk-avatar-group .mini-avatar,.nk-avatar-group ::slotted(.mini-avatar){width:26px;height:26px;border-radius:50%;color:var(--nk-on-accent);font-size:10.5px;font-weight:600;border:2px solid var(--nk-bg);display:flex;align-items:center;justify-content:center;margin-left:-7px}.nk-avatar-group .mini-avatar:first-child,.nk-avatar-group ::slotted(.mini-avatar:first-child){margin-left:0}.nk-avatar-group .more,.nk-avatar-group ::slotted(.more){background:var(--nk-bg-callout);color:var(--nk-text-secondary)}.nk-skeleton{border-radius:5px;margin-bottom:10px;background:linear-gradient(90deg,var(--nk-bg-callout) 25%,var(--nk-bg-hover) 50%,var(--nk-bg-callout) 75%);background-size:200% 100%;animation:1.6s infinite nk-shimmer}@keyframes nk-shimmer{to{background-position:-200% 0}}.nk-empty{text-align:center;padding:36px 20px;border:1.5px dashed var(--nk-border-strong);border-radius:10px;color:var(--nk-text-tertiary)}.nk-empty .e-icon,.nk-empty ::slotted(.e-icon),.nk-empty ::slotted([slot=icon]){font-size:30px;margin-bottom:8px}.nk-empty .e-title,.nk-empty ::slotted(.e-title),.nk-empty ::slotted([slot=title]){font-weight:500;color:var(--nk-text-secondary);margin-bottom:3px;font-size:14px}.nk-empty .e-desc,.nk-empty ::slotted(.e-desc),.nk-empty ::slotted([slot=desc]){font-size:13px;margin-bottom:12px}.nk-empty .e-actions,.nk-empty ::slotted(.e-actions){display:flex;flex-wrap:wrap;justify-content:center;gap:8px}.nk-comments{border-left:1px solid var(--nk-border);padding:4px 0 4px 18px;margin:8px 0 8px 8px}.nk-comment{display:flex;gap:9px;margin-bottom:14px}.nk-comment .mini-avatar,.nk-comment ::slotted(.mini-avatar),.nk-comment ::slotted([slot=avatar]){width:24px;height:24px;border-radius:50%;color:var(--nk-on-accent);flex-shrink:0;font-size:10px;font-weight:600;display:flex;align-items:center;justify-content:center}.nk-comment .c-head,.nk-comment ::slotted(.c-head){font-size:12px;color:var(--nk-text-tertiary);margin-bottom:2px}.nk-comment .c-head b{color:var(--nk-text);font-weight:600}.nk-comment .c-body,.nk-comment ::slotted(.c-body){font-size:14px;line-height:1.5}.nk-comment-input{display:flex;gap:8px;align-items:center;margin-top:4px}.nk-comment-input input{min-width:0;flex:1}.nk-ai-thread{display:flex;flex-direction:column;gap:14px}.nk-ai-msg{display:flex;gap:9px}.nk-ai-msg .mini-avatar,.nk-ai-msg ::slotted(.mini-avatar),.nk-ai-msg ::slotted([slot=avatar]){width:24px;height:24px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:12px;background:var(--nk-bg-callout)}.nk-ai-msg.user .mini-avatar,.nk-ai-msg.user ::slotted(.mini-avatar),.nk-ai-msg.user ::slotted([slot=avatar]){background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-size:9.5px;font-weight:600}.nk-ai-msg .a-body,.nk-ai-msg ::slotted(.a-body){font-size:14px;line-height:1.55;padding-top:2px}.nk-ai-msg .a-name,.nk-ai-msg ::slotted(.a-name){font-size:12px;font-weight:600;margin-bottom:2px}.nk-ai-msg .a-name span{color:var(--nk-text-tertiary);font-weight:400}.nk-ai-actions{display:flex;gap:4px;margin-top:6px}.nk-ai-actions button{font-family:inherit;font-size:12px;color:var(--nk-text-secondary);background:0 0;border:1px solid var(--nk-border);border-radius:5px;padding:2px 8px;cursor:pointer}.nk-ai-actions ::slotted(button){font-family:inherit;font-size:12px;color:var(--nk-text-secondary);background:0 0;border:1px solid var(--nk-border);border-radius:5px;padding:2px 8px!important;cursor:pointer}.nk-ai-actions ::slotted(button:hover),.nk-ai-actions button:hover{background:var(--nk-bg-hover);color:var(--nk-text)}.nk-ai-input-row{display:flex;align-items:center;gap:8px;margin-top:14px;border:1px solid var(--nk-border-strong);border-radius:10px;padding:8px 12px}.nk-ai-input-row:focus-within{border-color:var(--nk-accent)}.nk-ai-input-row input{flex:1;border:none;outline:0;background:0 0;font-family:inherit;font-size:14px;color:var(--nk-text);min-width:0}.nk-ai-input-row input::placeholder{color:var(--nk-text-tertiary)}.nk-ai-send{border:none;background:var(--nk-accent);color:var(--nk-on-accent);border-radius:6px;width:26px;height:26px;cursor:pointer;font-size:13px;flex-shrink:0}.nk-block-host{position:relative;border-radius:var(--nk-radius);margin:8px 0;padding:2px 0 2px 2px;transition:background .15s,box-shadow .15s}.nk-block-host:hover{background:var(--nk-bg-hover)}.nk-block-host:focus-within{background:0 0;box-shadow:0 0 0 2px color-mix(in srgb,var(--nk-accent) 25%,transparent)}.nk-block-host.nk-drop-target{box-shadow:0 -2px 0 0 var(--nk-accent);background:0 0}.nk-block-host .nk-block-handle,.nk-block-host ::slotted(.nk-block-handle){position:absolute;left:-26px;top:4px;width:18px;height:20px;border-radius:4px;display:flex;align-items:center;justify-content:center;color:var(--nk-text-tertiary);font-size:13px;cursor:grab;opacity:0;transition:opacity .15s;user-select:none}.nk-block-host:hover .nk-block-handle{opacity:1}.nk-block-host .nk-block-actions{position:absolute;display:flex;gap:1px;z-index:2;opacity:0;transition:opacity .15s;pointer-events:none}.nk-block-host .nk-block-actions.show{opacity:1;pointer-events:auto}.nk-block-host .nk-block-actions ::slotted(button),.nk-block-host .nk-block-actions button{width:20px;height:22px;padding:0;border:none;border-radius:4px;background:0 0;color:var(--nk-text-tertiary);font-family:inherit;font-size:14px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center}.nk-block-host .nk-block-actions button:hover{background:var(--nk-bg-hover);color:var(--nk-text)}.nk-block-host .nk-block-actions .drag{cursor:grab}.nk-block-host .nk-block-actions .drag:active{cursor:grabbing}.nk-block-host .ProseMirror{outline:0;font-family:var(--nk-font);font-size:14px;line-height:1.6;color:var(--nk-text);min-height:60px;padding:4px 2px}.nk-block-host .ProseMirror>*+*{margin-top:6px}.nk-block-host .ProseMirror h1{font-size:30px;font-weight:600;letter-spacing:-.01em;margin:24px 0 6px}.nk-block-host .ProseMirror h2{font-size:22px;font-weight:600;margin:20px 0 6px}.nk-block-host .ProseMirror h3{font-size:17px;font-weight:600;margin:16px 0 4px}.nk-block-host .ProseMirror p{margin:0}.nk-block-host .ProseMirror ol,.nk-block-host .ProseMirror ul{padding-left:24px;margin:4px 0}.nk-block-host .ProseMirror ul{list-style:disc}.nk-block-host .ProseMirror ol{list-style:decimal}.nk-block-host .ProseMirror li{margin:2px 0}.nk-block-host .ProseMirror li::marker{color:var(--nk-text-tertiary)}.nk-block-host .ProseMirror ul[data-type=taskList]{list-style:none;padding-left:2px}.nk-block-host .ProseMirror ul[data-type=taskList] li{display:flex;gap:8px;align-items:flex-start}.nk-block-host .ProseMirror ul[data-type=taskList] li>label{flex-shrink:0;margin-top:3px;user-select:none}.nk-block-host .ProseMirror ul[data-type=taskList] li>div{flex:1;min-width:0}.nk-block-host .ProseMirror ul[data-type=taskList] input[type=checkbox]{appearance:none;width:16px;height:16px;margin:0;border:1.4px solid var(--nk-border-strong);border-radius:2px;cursor:pointer;position:relative;background:var(--nk-bg);display:block}.nk-block-host .ProseMirror ul[data-type=taskList] input[type=checkbox]:checked{background:var(--nk-accent);border-color:var(--nk-accent)}.nk-block-host .ProseMirror ul[data-type=taskList] input[type=checkbox]:checked::after{content:\"✓\";color:var(--nk-on-accent);font-size:11px;position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.nk-block-host .ProseMirror li[data-checked=true]>div{text-decoration:line-through;color:var(--nk-text-tertiary)}.nk-block-host .ProseMirror-gapcursor::after{border-top-color:var(--nk-text)}.nk-block-host .ProseMirror .ProseMirror-selectednode{background:color-mix(in srgb,var(--nk-accent) 8%,transparent)}.nk-block-host .ProseMirror blockquote{border-left:3px solid var(--nk-text);padding:2px 0 2px 14px;margin:12px 0;color:var(--nk-text-secondary)}.nk-block-host .ProseMirror code{font-family:var(--nk-font-mono);font-size:85%;color:var(--nk-danger);background:color-mix(in srgb,var(--nk-danger) 8%,transparent);border-radius:4px;padding:1px 5px}.nk-block-host .ProseMirror pre{background:var(--nk-bg-code);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:16px 20px;margin:12px 0;font-family:var(--nk-font-mono);font-size:13px;line-height:1.6;color:var(--nk-text-secondary);overflow-x:auto}.nk-block-host .ProseMirror pre code{background:0 0;color:inherit;padding:0;font-size:inherit}.nk-block-host .ProseMirror hr{border:none;border-top:1px solid var(--nk-border);margin:20px 0}.nk-block-host .ProseMirror a{color:var(--nk-accent);text-decoration:underline;text-underline-offset:2px}.nk-block-host .ProseMirror-selectednode{box-shadow:0 0 0 2px color-mix(in srgb,var(--nk-accent) 35%,transparent);border-radius:3px}.nk-block-host .ProseMirror ::selection{background:color-mix(in srgb,var(--nk-accent) 25%,transparent)}.nk-block-host .ProseMirror .is-empty::before,.nk-block-host .ProseMirror p.is-editor-empty:first-child::before{content:attr(data-placeholder);color:var(--nk-text-tertiary);float:left;height:0;pointer-events:none}.nk-block-host .bn-container{font-family:var(--nk-font);color:var(--nk-text);background:0 0}.nk-block-host .bn-editor{padding:4px 2px}.nk-block-host .bn-block-content{font-size:14px;line-height:1.6}.nk-block-host .bn-side-menu{color:var(--nk-text-tertiary)}.nk-block-host .bn-drag-handle{border-radius:4px}.nk-block-host .bn-drag-handle:hover{background:var(--nk-bg-hover)}.nk-block-host .novel-editor{font-family:var(--nk-font);color:var(--nk-text)}.nk-block-host .novel-prose{max-width:none}.nk-block-host .bn-suggestion-menu,.nk-block-host .tippy-box,.nk-slash-menu{background:var(--nk-bg);border-radius:10px;box-shadow:var(--nk-shadow-menu);padding:6px;width:280px;max-height:320px;overflow-y:auto;font-family:var(--nk-font);font-size:14px;color:var(--nk-text)}.nk-slash-menu-label{font-size:12px;color:var(--nk-text-tertiary);padding:6px 9px 2px}.nk-slash-item{display:flex;align-items:center;gap:10px;padding:6px 9px;border-radius:5px;cursor:pointer;user-select:none}.nk-slash-item.selected,.nk-slash-item:hover{background:var(--nk-bg-hover)}.nk-slash-item .m-icon,.nk-slash-item ::slotted(.m-icon){width:28px;height:28px;flex-shrink:0;border-radius:4px;background:var(--nk-bg-callout);border:1px solid var(--nk-border);display:flex;align-items:center;justify-content:center;font-size:15px}.nk-slash-item .m-desc{font-size:12px;color:var(--nk-text-tertiary)}.nk-bubble-menu{display:flex;align-items:center;gap:2px;background:var(--nk-bg);border-radius:8px;box-shadow:var(--nk-shadow-menu);padding:4px}.nk-bubble-menu button{font-family:inherit;font-size:13px;border:none;background:0 0;color:var(--nk-text-secondary);padding:4px 8px;border-radius:5px;cursor:pointer}.nk-bubble-menu ::slotted(button){font-family:inherit;font-size:13px;border:none;background:0 0;color:var(--nk-text-secondary);padding:4px 8px!important;border-radius:5px;cursor:pointer}.nk-bubble-menu ::slotted(button:hover),.nk-bubble-menu button:hover{background:var(--nk-bg-hover);color:var(--nk-text)}.nk-bubble-menu ::slotted(button.active),.nk-bubble-menu button.active{color:var(--nk-accent)}@media (max-width:860px){.nk-sidebar{display:none}.nk-tab-bar{display:flex}.nk-tab-bar.fixed+.nk-tab-bar-spacer{display:block}.nk-page{padding-left:max(24px,env(safe-area-inset-left,0px));padding-right:max(24px,env(safe-area-inset-right,0px));padding-bottom:80px}.nk-settings-nav{width:60px;min-width:60px}.nk-settings-nav .label,.nk-settings-nav .nk-section-label,.nk-settings-user .u-text{display:none}.nk-settings-content{padding:24px}.nk-cmdk-backdrop{padding-top:max(6vh,env(safe-area-inset-top,0px))}.nk-cmdk{width:min(560px,96vw)}.nk-stats{flex-wrap:wrap}.nk-breadcrumb{min-width:0}.nk-breadcrumb ::slotted(.crumb:not(:last-child)),.nk-breadcrumb ::slotted(.sep),.nk-breadcrumb>.crumb:not(:last-child),.nk-breadcrumb>.sep,.nk-topbar-actions ::slotted(.nk-topbar-meta),.nk-topbar-meta{display:none}.nk-breadcrumb ::slotted(.crumb:last-child),.nk-breadcrumb>.crumb:last-child{display:block;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nk-topbar-actions{flex-shrink:0}.nk-field{flex-wrap:wrap;row-gap:6px}.nk-field .f-control,.nk-field ::slotted(.f-control){max-width:100%;min-width:0}.nk-input,.nk-select,.nk-slider,.nk-textarea{max-width:100%}:root:has(.nk-tab-bar:not([hidden])) .nk-toast{bottom:calc(var(--nk-tab-bar-height) + max(6px,env(safe-area-inset-bottom,0px)) + 6px)}:root:has(.nk-tab-bar.floating:not([hidden])) .nk-toast{bottom:calc(var(--nk-tab-bar-height) + 24px + env(safe-area-inset-bottom,0px))}}@media (prefers-reduced-motion:reduce){.nk-skeleton{animation:none;background:var(--nk-bg-callout)}[class*=nk-],[class*=nk-]::after,[class*=nk-]::before{animation-duration:NaNs!important;animation-iteration-count:1!important;transition-duration:NaNs!important;scroll-behavior:auto!important}}\n/*# sourceMappingURL=notionkit.min.css.map */";
|
|
8
|
+
const componentsHead = "[class*=nk-],[class*=nk-] *,[class*=nk-]:before,[class*=nk-]:after,[class*=nk-] *:before,[class*=nk-] *:after{box-sizing:border-box}[class*=nk-] :where(h1,h2,h3,h4,h5,h6,p,figure,blockquote,dl,dd,pre,ul,ol,li){margin:0;padding:0}[class*=nk-] :where(ul,ol){list-style:none}[class*=nk-] :where(button,input,select,textarea,option,optgroup,fieldset,legend),:where(button,input,select,textarea)[class*=nk-]{margin:0;padding:0}[class*=nk-][hidden]:not([hidden=until-found i]){display:none!important}::slotted([hidden]:not([hidden=\"until-found\" i])){display:none!important}";
|
|
9
|
+
const componentsTail = ".nk-body{margin:0;min-height:100vh;min-height:100dvh;font-family:var(--nk-font);font-size:14px;background:var(--nk-bg);color:var(--nk-text);-webkit-font-smoothing:auto;transition:background .25s ease,color .25s ease}.nk-app{display:flex;height:100vh;height:100dvh;overflow:hidden}.nk-sidebar{width:calc(var(--nk-sidebar-width) + env(safe-area-inset-left,0px));min-width:calc(var(--nk-sidebar-width) + env(safe-area-inset-left,0px));padding-left:env(safe-area-inset-left,0px);background:var(--nk-bg-sidebar);display:flex;flex-direction:column;border-right:1px solid var(--nk-border);transition:background .25s ease}.nk-workspace{display:flex;align-items:center;gap:8px;padding:10px 12px;margin:6px 8px 2px;border-radius:var(--nk-radius);cursor:pointer;font-weight:500;user-select:none}.nk-workspace:hover{background:var(--nk-bg-hover)}.nk-workspace .avatar,.nk-workspace ::slotted(.avatar),.nk-workspace ::slotted([slot=\"avatar\"]){width:22px;height:22px;border-radius:4px;background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-size:11px;font-weight:600;display:flex;align-items:center;justify-content:center}.nk-workspace .chev{margin-left:auto;color:var(--nk-text-tertiary);font-size:11px}.nk-sidebar-scroll{flex:1;overflow-y:auto;padding:4px 8px 16px}.nk-sidebar-scroll::-webkit-scrollbar{width:8px}.nk-sidebar-scroll::-webkit-scrollbar-thumb{background:var(--nk-border-strong);border-radius:4px}.nk-section-label{font-size:12px;font-weight:500;letter-spacing:.01em;color:var(--nk-text-tertiary);padding:14px 10px 4px;display:flex;justify-content:space-between;align-items:center}.nk-section-label .plus{cursor:pointer;border-radius:4px;padding:0 4px;font-size:13px;opacity:0;transition:opacity .15s}.nk-section-label:hover .plus{opacity:1}.nk-section-label .plus:hover{background:var(--nk-bg-hover)}.nk-sidebar-footer{padding:8px;border-top:1px solid var(--nk-border);color:var(--nk-text-sidebar);font-size:14px}.nk-sidebar-footer .nk-tree-item{min-height:26px}.nk-sidebar-backdrop{display:none;position:fixed;inset:0;z-index:59;background:var(--nk-scrim-soft)}.nk-sidebar-toggle{display:none}.nk-main{flex:1;display:flex;flex-direction:column;min-width:0}.nk-topbar{height:44px;display:flex;align-items:center;padding:0 max(12px,env(safe-area-inset-right,0px)) 0 max(12px,env(safe-area-inset-left,0px));gap:8px;flex-shrink:0}.nk-breadcrumb{display:flex;align-items:center;gap:4px;font-size:14px}.nk-breadcrumb .crumb,.nk-breadcrumb ::slotted(.crumb){padding:2px 6px;border-radius:4px;cursor:pointer;color:var(--nk-text-sidebar);display:flex;align-items:center;gap:5px}.nk-breadcrumb .crumb:hover{background:var(--nk-bg-hover)}a.crumb{text-decoration:none}.nk-breadcrumb .crumb.current,.nk-breadcrumb ::slotted(.crumb.current){color:var(--nk-text)}.nk-breadcrumb .sep{color:var(--nk-text-tertiary);font-size:12px}.nk-topbar-actions{margin-left:auto;display:flex;align-items:center;gap:4px}.nk-topbar-btn{padding:4px 8px;border-radius:var(--nk-radius);cursor:pointer;color:var(--nk-text-sidebar);font-size:14px;user-select:none;border:none;background:transparent;font-family:inherit}.nk-topbar-btn:hover{background:var(--nk-bg-hover)}.nk-topbar-btn svg,.nk-topbar-btn ::slotted(svg){width:16px;height:16px;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.nk-share-btn{font-size:14px;padding:4px 8px}.nk-topbar-meta,.nk-topbar-actions ::slotted(.nk-topbar-meta){padding:4px 8px;font-size:12px;color:var(--nk-text-tertiary);white-space:nowrap}.nk-theme-toggle{font-size:15px;width:30px;height:28px;padding:0}.nk-tab-bar{display:none;flex:none;align-items:stretch;gap:2px;position:sticky;bottom:0;z-index:30;box-sizing:border-box;height:calc(var(--nk-tab-bar-height) - 6px + max(6px,env(safe-area-inset-bottom,0px)));padding:6px max(4px,env(safe-area-inset-right,0px)) max(6px,env(safe-area-inset-bottom,0px)) max(4px,env(safe-area-inset-left,0px));background:var(--nk-bg-sidebar);border-top:1px solid var(--nk-border)}.nk-tab-bar.always{display:flex}.nk-tab-bar.fixed{position:fixed;left:0;right:0;bottom:0}.nk-tab-bar-spacer{display:none;flex:none;height:calc(var(--nk-tab-bar-height) - 6px + max(6px,env(safe-area-inset-bottom,0px)))}.nk-tab-bar.always.fixed+.nk-tab-bar-spacer{display:block}.nk-tab-bar.floating{position:fixed;left:max(12px,env(safe-area-inset-left,0px));right:max(12px,env(safe-area-inset-right,0px));bottom:calc(12px + env(safe-area-inset-bottom,0px));height:var(--nk-tab-bar-height);padding:6px;border:1px solid var(--nk-border);border-radius:16px;box-shadow:var(--nk-shadow-menu)}.nk-tab-bar-item{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;padding:4px 2px;border:none;border-radius:var(--nk-radius);background:transparent;font-family:inherit;font-size:10.5px;line-height:1.2;color:var(--nk-text-secondary);text-decoration:none;cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent}.nk-tab-bar-item:hover{color:var(--nk-text);background:var(--nk-bg-hover)}.nk-tab-bar-item.active{color:var(--nk-accent)}.nk-tab-bar-item:disabled{opacity:.5;cursor:not-allowed}.nk-tab-bar-item .icon,.nk-tab-bar-item ::slotted([slot=\"icon\"]){font-size:20px;line-height:1}.nk-tab-bar-item .label,.nk-tab-bar-item ::slotted(.label){max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.nk-tree-item{display:flex;align-items:center;gap:6px;padding:3px 8px 3px 10px;border-radius:var(--nk-radius);cursor:pointer;user-select:none;color:var(--nk-text-sidebar);position:relative;min-height:var(--_nk-row, 28px)}.nk-tree-item:hover{background:var(--nk-bg-hover)}.nk-tree-item.active{background:var(--nk-bg-active);color:var(--nk-text);font-weight:500}.nk-tree-item.compact{min-height:26px}.nk-tree-item .icon,.nk-tree-item ::slotted(.icon),.nk-tree-item ::slotted([slot=\"icon\"]){font-size:15px;width:20px;text-align:center;flex-shrink:0}.nk-tree-item .label,.nk-tree-item ::slotted(.label){white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nk-tree-item .actions{margin-left:auto;display:none;gap:2px;color:var(--nk-text-tertiary)}.nk-tree-item:hover .actions{display:flex}.nk-tree-item .actions span{padding:0 3px;border-radius:3px;font-size:12px}.nk-tree-item .actions span:hover{background:var(--nk-bg-active)}.nk-tree-children{margin-left:14px;border-left:1px solid var(--nk-border);padding-left:4px;overflow:hidden}.nk-tree-children.collapsed{display:none}.nk-toggle-arrow{width:16px;height:16px;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;font-size:9px;color:var(--nk-text-tertiary);border-radius:3px;transition:transform .15s}.nk-toggle-arrow.open{transform:rotate(90deg)}.nk-kbd-hint{margin-left:auto;display:flex;gap:3px;align-items:center}.nk-kbd{font-family:inherit;font-size:10.5px;background:var(--nk-bg-callout);border:1px solid var(--nk-border-strong);border-bottom-width:2px;border-radius:4px;padding:0 4px}.nk-page-scroll{flex:1;overflow-y:auto}.nk-page-scroll::-webkit-scrollbar{width:10px}.nk-page-scroll::-webkit-scrollbar-thumb{background:var(--nk-border-strong);border-radius:5px;border:2px solid var(--nk-bg)}.nk-cover{height:200px;background:radial-gradient(ellipse at 20% 40%,color-mix(in srgb,var(--nk-decor-purple) 35%,transparent),transparent 55%),radial-gradient(ellipse at 80% 20%,color-mix(in srgb,var(--nk-decor-blue) 35%,transparent),transparent 55%),radial-gradient(ellipse at 60% 90%,color-mix(in srgb,var(--nk-decor-orange) 25%,transparent),transparent 55%),var(--nk-bg-callout)}.nk-cover>img,.nk-cover ::slotted(img){display:block;width:100%;height:100%;object-fit:cover}.nk-page{max-width:760px;margin:0 auto;padding:24px max(64px,env(safe-area-inset-right,0px)) 120px max(64px,env(safe-area-inset-left,0px));font-size:16px;line-height:1.5}.nk-page.full{max-width:none}.nk-page.small{font-size:14px}.nk-cover+.nk-page,.nk-page.covered{padding-top:0}.nk-page-icon,.nk-page ::slotted(.nk-page-icon),.nk-page ::slotted([slot=\"icon\"]){font-size:64px;line-height:1;margin-top:0;cursor:pointer;user-select:none;display:inline-block}.nk-cover+.nk-page .nk-page-icon,.nk-cover+.nk-page ::slotted(.nk-page-icon),.nk-cover+.nk-page ::slotted([slot=\"icon\"]),.nk-page.covered .nk-page-icon,.nk-page.covered ::slotted(.nk-page-icon),.nk-page.covered ::slotted([slot=\"icon\"]){margin-top:-42px}.nk-page-title{font-size:40px;font-weight:700;line-height:1.2;margin:8px 0 4px;outline:none;letter-spacing:0}.nk-page-meta{color:var(--nk-text-tertiary);font-size:13px;margin-bottom:24px;display:flex;gap:16px}.nk-props{display:flex;flex-direction:column;margin:0 0 20px;font-size:14px;line-height:1.5}.nk-prop{display:flex;align-items:flex-start;min-width:0}.nk-prop .p-name{flex:0 0 160px;min-width:0;min-height:34px;padding:0 6px;display:flex;align-items:center;gap:6px;overflow:hidden;border-radius:var(--nk-radius);color:var(--nk-text-secondary);white-space:nowrap;user-select:none}.nk-prop .p-icon,.nk-prop ::slotted([slot=\"icon\"]){width:16px;flex-shrink:0;text-align:center;font-size:13px}.nk-prop .p-value{flex:1 1 auto;min-width:0;min-height:34px;padding:5px 8px;display:flex;align-items:center;flex-wrap:wrap;gap:4px 6px;border-radius:var(--nk-radius);overflow-wrap:anywhere}.nk-prop .p-name:hover,.nk-prop .p-value:hover{background:var(--nk-bg-hover)}.nk-page p.lead{font-size:1em;line-height:1.6;color:var(--nk-text-secondary);margin-bottom:20px}.nk-page ::slotted(p.lead){font-size:1em;line-height:1.6;color:var(--nk-text-secondary);margin-bottom:20px!important}.nk-heading{font-size:1.5em;font-weight:600;line-height:1.3;margin:32px 0 10px;display:flex;align-items:center;gap:8px}.nk-callout{display:flex;gap:10px;align-items:flex-start;background:var(--nk-bg-callout);border-radius:var(--nk-radius);padding:16px 16px 16px 12px;margin:16px 0;line-height:1.5}.nk-callout .c-icon,.nk-callout ::slotted(.c-icon),.nk-callout ::slotted([slot=\"icon\"]){font-size:17px}.nk-todo{display:flex;align-items:flex-start;gap:8px;padding:4px 0}.nk-todo input[type=checkbox]{appearance:none;width:16px;height:16px;margin-top:3px;border:1.4px solid var(--nk-border-strong);border-radius:2px;cursor:pointer;flex-shrink:0;position:relative;background:var(--nk-bg)}.nk-todo input[type=checkbox]:checked{background:var(--nk-accent);border-color:var(--nk-accent)}.nk-todo input[type=checkbox]:checked:after{content:\"\\2713\";color:var(--nk-on-accent);font-size:11px;position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.nk-todo input:checked+span{text-decoration:line-through;color:var(--nk-text-tertiary)}.nk-todo input:disabled{opacity:.5;cursor:not-allowed}.nk-toggle{margin:6px 0}.nk-toggle summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:6px;padding:4px 6px;border-radius:var(--nk-radius);font-weight:500;user-select:none}.nk-toggle summary::-webkit-details-marker{display:none}.nk-toggle summary:hover{background:var(--nk-bg-hover)}.nk-toggle summary:before{content:\"\\25b8\";color:var(--nk-text-tertiary);font-size:11px;transition:transform .15s;display:inline-block}.nk-toggle[open] summary:before{transform:rotate(90deg)}.nk-toggle .toggle-body,.nk-toggle ::slotted(.toggle-body){padding:4px 0 8px 26px;color:var(--nk-text-secondary);line-height:1.55}.nk-divider{border:none;border-top:1px solid var(--nk-border);margin:24px 0}.nk-quote{border-left:3px solid var(--nk-text);padding:2px 0 2px 14px;margin:16px 0;color:var(--nk-text-secondary);line-height:1.5}.nk-quote .q-cite{display:block;margin-top:6px;font-size:12.5px;color:var(--nk-text-tertiary)}.nk-mention{display:inline-flex;align-items:center;gap:4px;padding:0 4px;border-radius:4px;font-weight:500;cursor:pointer;white-space:nowrap}.nk-mention:hover{background:var(--nk-bg-hover)}.nk-mention.person{color:var(--nk-text)}.nk-mention.person .mini-avatar,.nk-mention.person .nk-avatar,.nk-mention.person ::slotted(.mini-avatar),.nk-mention.person ::slotted([slot=\"avatar\"]){width:16px;height:16px;border-radius:50%;color:var(--nk-on-accent);font-size:8.5px;font-weight:600;display:inline-flex;align-items:center;justify-content:center}.nk-mention.page{color:var(--nk-text-secondary);text-decoration:underline;text-decoration-color:var(--nk-border-strong);text-underline-offset:2px}.nk-mention.date{color:var(--nk-color-orange)}.nk-inline-code{font-family:var(--nk-font-mono);font-size:85%;color:var(--nk-danger);background:color-mix(in srgb,var(--nk-danger) 8%,transparent);border-radius:4px;padding:1px 5px}.nk-code{background:var(--nk-bg-code);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:20px 24px;font-family:var(--nk-font-mono);font-size:13px;line-height:1.6;margin:14px 0;overflow-x:auto;color:var(--nk-text-secondary);white-space:pre;position:relative}.nk-code .lang{position:absolute;top:6px;right:10px;font-size:11px;color:var(--nk-text-tertiary);font-family:var(--nk-font)}.nk-code .tag,.nk-code ::slotted(.tag){color:var(--nk-accent)}.nk-code .attr,.nk-code ::slotted(.attr){color:var(--nk-color-orange)}.nk-database{margin:12px 0 8px}.nk-db-tabs{display:flex;gap:2px;align-items:center;padding:0 0 6px;margin-bottom:0;font-size:14px}.nk-db-tab{padding:4px 8px;cursor:pointer;color:var(--nk-text-secondary);border-radius:var(--nk-radius);user-select:none;line-height:20px;display:flex;align-items:center;gap:6px;flex-shrink:0;white-space:nowrap}.nk-db-tab:hover{color:var(--nk-text);background:var(--nk-bg-hover)}.nk-db-tab.active{color:var(--nk-text);background:var(--nk-bg-active);font-weight:500}.nk-db-tab.add{color:var(--nk-text-tertiary)}.nk-db-tab .badge,.nk-db-tab ::slotted(.badge){background:var(--nk-bg-callout);border-radius:8px;font-size:11px;padding:0 6px;color:var(--nk-text-tertiary)}.nk-db-toolbar{display:flex;align-items:center;gap:8px;min-width:0;padding-bottom:6px}.nk-db-toolbar>.nk-db-tabs{flex:1 1 auto;min-width:0;padding-bottom:0;overflow-x:auto;scrollbar-width:none}.nk-db-toolbar>.nk-db-tabs::-webkit-scrollbar{display:none}.nk-db-toolbar .tools{flex:none;display:flex;align-items:center;gap:4px;margin-left:auto}.nk-db-tool{display:inline-flex;align-items:center;gap:4px;height:28px;padding:0 8px;border:none;border-radius:var(--nk-radius);background:transparent;font-family:inherit;font-size:14px;color:var(--nk-text-secondary);white-space:nowrap;cursor:pointer;user-select:none}.nk-db-tool:hover{background:var(--nk-bg-hover);color:var(--nk-text)}.nk-db-tool.active{color:var(--nk-accent)}.nk-filter-row{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:2px 0 8px}.nk-filter-pill{display:inline-flex;align-items:center;gap:4px;height:24px;padding:0 8px;border:1px solid var(--nk-border-strong);border-radius:12px;background:transparent;font-family:inherit;font-size:13px;line-height:1;color:var(--nk-text-secondary);white-space:nowrap;cursor:pointer;user-select:none}.nk-filter-pill:hover{background:var(--nk-bg-hover)}.nk-filter-pill.active{color:var(--nk-accent);border-color:color-mix(in srgb,var(--nk-accent) 35%,transparent);background:color-mix(in srgb,var(--nk-accent) 6%,transparent)}.nk-filter-pill.add{border-color:transparent;color:var(--nk-text-tertiary)}.nk-filter-pill.add:hover{color:var(--nk-text-secondary)}.nk-filter-pill button{padding:0;border:none;background:none;font:inherit;color:inherit;cursor:pointer}.nk-filter-pill .fp-remove{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:-4px;border-radius:50%;font-size:13px}.nk-filter-pill .fp-remove:hover{background:color-mix(in srgb,currentColor 15%,transparent)}.nk-table-wrap{overflow-x:auto}.nk-table{width:100%;border-collapse:collapse;font-size:14px}.nk-table th{text-align:left;font-weight:400;color:var(--nk-text-secondary);height:36px;padding:0 8px;border-bottom:1px solid var(--nk-border);border-right:1px solid var(--nk-border);font-size:14px;white-space:nowrap;user-select:none;cursor:pointer}.nk-table th:hover{background:var(--nk-bg-hover)}.nk-table th .th-icon,.nk-table th ::slotted(.th-icon){margin-right:6px;font-size:13px;color:var(--nk-text-tertiary)}.nk-table td{height:36px;padding:6px 8px;line-height:1.5;border-bottom:1px solid var(--nk-border);border-right:1px solid var(--nk-border);white-space:nowrap;vertical-align:middle}.nk-table th:last-child,.nk-table td:last-child{border-right:none}.nk-table.wrap td,.nk-table td.wrap{white-space:normal;vertical-align:top}.nk-table tbody tr:hover{background:var(--nk-bg-hover)}.nk-table .row-title{display:flex;align-items:center;gap:7px;font-weight:500;cursor:pointer}.nk-table .row-title:hover{text-decoration:underline;text-decoration-color:var(--nk-text-tertiary)}.nk-table .date-cell{color:var(--nk-text-secondary)}.nk-table .num{text-align:right;font-variant-numeric:tabular-nums}.nk-table .person-cell{display:flex;align-items:center;gap:6px;color:var(--nk-text-secondary)}.nk-table .person-cell .mini-avatar,.nk-table .person-cell ::slotted(.mini-avatar){width:20px;height:20px;border-radius:50%;font-size:10px;color:var(--nk-on-accent);display:inline-flex;align-items:center;justify-content:center;font-weight:600}.nk-new-row,.nk-table .new-row{color:var(--nk-text-tertiary);cursor:pointer;padding:8px;display:flex;align-items:center;gap:7px;font-size:14px}.nk-new-row:hover,.nk-table .new-row:hover{background:var(--nk-bg-hover)}.nk-tag{display:inline-flex;align-items:center;max-width:100%;height:20px;padding:0 6px;border-radius:3px;font-size:14px;font-weight:400;line-height:20px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;background:var(--nk-tag-gray-bg);color:var(--nk-tag-gray-text)}.nk-tag.gray{background:var(--nk-tag-gray-bg);color:var(--nk-tag-gray-text)}.nk-tag.brown{background:var(--nk-tag-brown-bg);color:var(--nk-tag-brown-text)}.nk-tag.orange{background:var(--nk-tag-orange-bg);color:var(--nk-tag-orange-text)}.nk-tag.yellow{background:var(--nk-tag-yellow-bg);color:var(--nk-tag-yellow-text)}.nk-tag.green{background:var(--nk-tag-green-bg);color:var(--nk-tag-green-text)}.nk-tag.blue{background:var(--nk-tag-blue-bg);color:var(--nk-tag-blue-text)}.nk-tag.purple{background:var(--nk-tag-purple-bg);color:var(--nk-tag-purple-text)}.nk-tag.pink{background:var(--nk-tag-pink-bg);color:var(--nk-tag-pink-text)}.nk-tag.red{background:var(--nk-tag-red-bg);color:var(--nk-tag-red-text)}.nk-progress{width:110px;height:6px;border-radius:3px;background:var(--nk-tint-blue);overflow:hidden;display:inline-block}.nk-progress>i{display:block;height:100%;background:var(--nk-color-blue);border-radius:3px}.nk-progress.wide{width:100%;flex:1 1 60px}.nk-progress-label{font-size:12px;color:var(--nk-text-tertiary);margin-left:7px;white-space:nowrap}.nk-list{display:flex;flex-direction:column;font-size:14px}.nk-list-item{display:flex;align-items:center;gap:8px;min-width:0;overflow:hidden;min-height:36px;padding:4px 6px;border-bottom:1px solid var(--nk-border);color:inherit;text-decoration:none;cursor:pointer}.nk-list-item:hover{background:var(--nk-bg-hover)}.nk-list>.nk-list-item:last-child,.nk-list ::slotted(.nk-list-item:last-child),.nk-list-item.last{border-bottom:none}.nk-list-item .l-icon,.nk-list-item ::slotted([slot=\"icon\"]){width:20px;flex-shrink:0;text-align:center;font-size:15px}.nk-list-item .l-title,.nk-list-item ::slotted(.l-title){flex:1 1 auto;min-width:0;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nk-list-item .l-meta,.nk-list-item ::slotted(.l-meta){flex:none;display:flex;align-items:center;gap:8px;margin-left:auto;font-size:12px;color:var(--nk-text-secondary);white-space:nowrap}.nk-board{display:none;gap:12px;padding:14px 2px;overflow-x:auto}.nk-board.active{display:flex}.nk-board-col{min-width:220px;width:220px;flex-shrink:0}.nk-board-col-header{display:flex;align-items:center;gap:7px;margin-bottom:8px;font-size:13.5px;font-weight:500}.nk-board-col-header .count{color:var(--nk-text-tertiary);font-weight:400}.nk-card{background:var(--nk-bg-card);border:1px solid var(--nk-border);border-radius:8px;padding:10px 12px;margin-bottom:8px;cursor:grab;box-shadow:var(--nk-shadow-card);transition:border-color .15s}.nk-card:hover{border-color:var(--nk-border-strong)}.nk-card .card-title,.nk-card ::slotted(.card-title){font-weight:500;margin-bottom:7px;display:flex;gap:6px;align-items:center}.nk-card .card-meta,.nk-card ::slotted(.card-meta){display:flex;gap:6px;flex-wrap:wrap;align-items:center;font-size:12px;color:var(--nk-text-secondary)}.nk-field{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:9px 0}.nk-field .f-label,.nk-field ::slotted(.f-label),.nk-field ::slotted([slot=\"label\"]){font-size:14px}.nk-field .f-desc,.nk-field ::slotted(.f-desc),.nk-field ::slotted([slot=\"desc\"]){font-size:12px;color:var(--nk-text-secondary);margin-top:2px;line-height:1.45}.nk-field .f-control,.nk-field ::slotted(.f-control){flex-shrink:0}.nk-field.stacked,.nk-fields>.nk-field{flex-direction:column;align-items:stretch;gap:6px;min-width:0}.nk-field.stacked .f-control,.nk-fields>.nk-field .f-control{width:100%;min-width:0}.nk-field.stacked .nk-input,.nk-field.stacked .nk-textarea,.nk-field.stacked .nk-select,.nk-fields>.nk-field .nk-input,.nk-fields>.nk-field .nk-textarea,.nk-fields>.nk-field .nk-select{width:100%;min-width:0}.nk-field.compact,.nk-fields>.nk-field{padding:0;gap:4px;min-width:0}.nk-field.compact .f-label,.nk-field.compact ::slotted([slot=\"label\"]),.nk-fields>.nk-field .f-label,.nk-fields>.nk-field ::slotted([slot=\"label\"]){font-size:12px;color:var(--nk-text-tertiary)}.nk-fields{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px 12px;padding:9px 0}.nk-fields>.nk-field{min-width:0}.nk-input,.nk-select,.nk-textarea{font-family:inherit;font-size:14px;line-height:20px;color:var(--nk-text);background:var(--nk-bg-input);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:5px 10px;outline:none;transition:border-color .15s,box-shadow .15s;min-width:210px}.nk-input:hover,.nk-select:hover,.nk-textarea:hover{border-color:var(--nk-border-strong)}.nk-input:focus,.nk-select:focus,.nk-textarea:focus{border-color:color-mix(in srgb,var(--nk-accent) 60%,transparent);box-shadow:0 0 0 2px color-mix(in srgb,var(--nk-accent) 30%,transparent)}.nk-input::placeholder,.nk-textarea::placeholder{color:var(--nk-text-tertiary)}.nk-input.wide,.nk-textarea.wide,.nk-select.wide{width:100%;min-width:0}.nk-input[type=date],.nk-input[type=time],.nk-input[type=datetime-local],.nk-input[type=month]{appearance:none}.nk-input::-webkit-date-and-time-value{text-align:start;min-height:1lh}.nk-select.compact{min-width:120px}.nk-textarea{resize:vertical;min-height:70px;line-height:1.5}.nk-select{appearance:none;cursor:pointer;padding-right:26px;background-image:linear-gradient(45deg,transparent 50%,var(--nk-text-tertiary) 50%),linear-gradient(135deg,var(--nk-text-tertiary) 50%,transparent 50%);background-position:calc(100% - 14px) 55%,calc(100% - 10px) 55%;background-size:4px 4px;background-repeat:no-repeat}.nk-btn{font-family:inherit;font-size:14px;line-height:20px;font-weight:500;border-radius:var(--nk-radius);cursor:pointer;padding:3px 12px;border:1px solid transparent;transition:background .15s,border-color .15s,box-shadow .15s,opacity .15s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap}.nk-btn svg,.nk-btn ::slotted(svg){width:15px;height:15px;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.nk-btn.primary{background:var(--nk-accent);color:var(--nk-on-accent)}.nk-btn.primary:hover{opacity:.88}.nk-btn.secondary{background:var(--nk-bg-card);color:var(--nk-text);box-shadow:var(--nk-shadow-btn)}.nk-btn.secondary:hover{background:color-mix(in srgb,var(--nk-bg-card),var(--nk-text) 6%)}.nk-btn.danger{background:var(--nk-bg-card);color:var(--nk-danger);box-shadow:var(--nk-shadow-btn)}.nk-btn.danger:hover{background:color-mix(in srgb,var(--nk-danger) 8%,var(--nk-bg-card))}.nk-btn.danger-solid{background:var(--nk-danger);color:var(--nk-on-accent)}.nk-btn.danger-solid:hover{opacity:.88}.nk-btn.small{padding:1px 8px;font-size:13px;line-height:20px}a.nk-btn{text-decoration:none}.nk-btn:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.nk-switch{position:relative;width:34px;height:20px;flex-shrink:0;appearance:none;border:none;cursor:pointer;border-radius:20px;background:var(--nk-border-strong);transition:background .2s}.nk-switch:after{content:\"\";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--nk-on-accent);transition:transform .2s;box-shadow:var(--nk-shadow-knob)}.nk-switch:checked,.nk-switch[aria-checked=true]{background:var(--nk-accent)}.nk-switch:checked:after,.nk-switch[aria-checked=true]:after{transform:translate(14px)}.nk-switch:disabled{opacity:.5;cursor:not-allowed}.nk-switch-label{display:inline-flex;align-items:flex-start;gap:8px;font-size:14px;cursor:pointer}.nk-switch-label>.nk-switch{font-size:inherit;line-height:inherit;margin-top:max(0px,calc((1lh - 20px)/2))}.nk-switch-label>span{padding-top:max(0px,calc((20px - 1lh)/2))}.nk-switch-label:has(.nk-switch:disabled){cursor:not-allowed;color:var(--nk-text-tertiary)}.nk-check{display:flex;align-items:flex-start;gap:8px;padding:4px 0;font-size:14px;cursor:pointer}.nk-check input{appearance:none;width:16px;height:16px;flex-shrink:0;border:1.4px solid var(--nk-border-strong);border-radius:3px;cursor:pointer;position:relative;background:var(--nk-bg);font-size:inherit;line-height:inherit;margin-top:max(0px,calc((1lh - 16px)/2))}.nk-check input[type=radio]{border-radius:50%}.nk-check input:checked{background:var(--nk-accent);border-color:var(--nk-accent)}.nk-check input:checked:after{content:\"\\2713\";color:var(--nk-on-accent);font-size:10.5px;position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.nk-check input[type=radio]:checked:after{content:\"\\25cf\";font-size:7px}.nk-check input:disabled{opacity:.5;cursor:not-allowed}.nk-check input:disabled+*{opacity:.6}.nk-slider{width:210px;accent-color:var(--nk-accent);cursor:pointer}.nk-slider-value{font-size:12.5px;color:var(--nk-text-tertiary);margin-top:3px}.nk-profile-row{display:flex;align-items:center;gap:14px;padding:8px 0}.nk-profile-row .big-avatar,.nk-profile-row ::slotted(.big-avatar),.nk-profile-row ::slotted([slot=\"avatar\"]){width:56px;height:56px;border-radius:50%;background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-size:20px;font-weight:600;display:flex;align-items:center;justify-content:center}.nk-model-card{border:1px solid var(--nk-border-strong);border-radius:8px;padding:12px 14px;margin-bottom:10px;cursor:pointer;display:flex;align-items:flex-start;gap:11px;transition:border-color .15s,background .15s}.nk-model-card:hover{background:var(--nk-bg-hover)}.nk-model-card.selected{border-color:var(--nk-accent);background:color-mix(in srgb,var(--nk-accent) 6%,transparent)}.nk-model-card .m-radio{width:15px;height:15px;border-radius:50%;flex-shrink:0;margin-top:2px;border:1.4px solid var(--nk-border-strong);position:relative}.nk-model-card.selected .m-radio{border-color:var(--nk-accent)}.nk-model-card.selected .m-radio:after{content:\"\";position:absolute;inset:3px;border-radius:50%;background:var(--nk-accent)}.nk-model-card .m-name,.nk-model-card ::slotted(.m-name),.nk-model-card ::slotted([slot=\"title\"]){font-weight:500;font-size:14px;display:flex;align-items:center;gap:7px}.nk-model-card .m-desc,.nk-model-card ::slotted(.m-desc),.nk-model-card ::slotted([slot=\"desc\"]){font-size:12px;color:var(--nk-text-secondary);margin-top:2px;line-height:1.45}.nk-danger-zone{border:1px solid color-mix(in srgb,var(--nk-danger) 40%,transparent);border-radius:8px;padding:14px 16px;margin-top:26px}.nk-danger-zone .dz-title{color:var(--nk-danger);font-weight:600;font-size:13px;margin-bottom:8px}.nk-member-row{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--nk-border)}.nk-member-list>.nk-member-row:last-child,.nk-member-list ::slotted(.nk-member-row:last-child),.nk-member-row.last{border-bottom:none}.nk-member-row .mini-avatar,.nk-member-row .nk-avatar,.nk-member-row ::slotted(.mini-avatar),.nk-member-row ::slotted([slot=\"avatar\"]){width:28px;height:28px;border-radius:50%;color:var(--nk-on-accent);display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600;flex-shrink:0}.nk-member-row>:has(>.m-mail){min-width:0}.nk-member-row .m-mail{font-size:12px;color:var(--nk-text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.nk-member-row .nk-select{min-width:120px;margin-left:auto}.nk-member-row ::slotted([slot=\"role\"]){margin-left:auto}.nk-modal-backdrop{position:fixed;inset:0;background:var(--nk-scrim);padding:env(safe-area-inset-top,0px) env(safe-area-inset-right,0px) env(safe-area-inset-bottom,0px) env(safe-area-inset-left,0px);display:flex;align-items:center;justify-content:center;z-index:100;opacity:0;pointer-events:none;transition:opacity .2s ease}.nk-modal-backdrop.open{opacity:1;pointer-events:auto}.nk-modal{width:min(1150px,92vw);height:min(715px,86vh);max-width:100%;max-height:100%;background:var(--nk-bg);border-radius:10px;box-shadow:var(--nk-shadow-menu);display:flex;overflow:hidden;transform:scale(.98) translateY(6px);transition:transform .2s ease}.nk-modal-backdrop.open .nk-modal{transform:scale(1) translateY(0)}.nk-settings-nav{width:240px;min-width:240px;background:var(--nk-bg-sidebar);border-right:1px solid var(--nk-border);padding:10px 8px;overflow-y:auto;flex-shrink:0}.nk-settings-user{display:flex;align-items:center;gap:9px;padding:6px 10px 12px;margin-bottom:4px}.nk-settings-user .avatar,.nk-settings-user ::slotted(.avatar),.nk-settings-user ::slotted([slot=\"avatar\"]){width:34px;height:34px;border-radius:50%;background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-weight:600;font-size:13px;display:flex;align-items:center;justify-content:center}.nk-settings-user .name{font-weight:500;font-size:14px}.nk-settings-user .mail{font-size:12px;color:var(--nk-text-secondary)}.nk-settings-nav .nk-tree-item{min-height:28px}.nk-settings-nav .nk-tree-item.active{background:var(--nk-bg-active);color:var(--nk-text);font-weight:500}.nk-settings-content{flex:1;overflow-y:auto;padding:36px 60px 80px;min-width:0}.nk-settings-content::-webkit-scrollbar{width:10px}.nk-settings-content::-webkit-scrollbar-thumb{background:var(--nk-border-strong);border-radius:5px;border:2px solid var(--nk-bg)}.nk-settings-pane{display:none;max-width:800px}.nk-settings-pane.active{display:block}.nk-settings-pane>h2{font-size:22px;font-weight:600;line-height:1.3;margin-bottom:20px}.nk-settings-pane>h3{font-size:16px;font-weight:500;padding-bottom:8px;border-bottom:1px solid var(--nk-border);margin:30px 0 12px}.nk-settings-pane ::slotted(h2){font-size:22px;font-weight:600;line-height:1.3;padding:0!important;margin:0 0 20px!important}.nk-settings-pane ::slotted(h3){font-size:16px;font-weight:500;border:0;border-bottom:1px solid var(--nk-border);padding:0 0 8px!important;margin:30px 0 12px!important}.nk-pop{background:var(--nk-bg);border-radius:10px;box-shadow:var(--nk-shadow-menu);padding:10px;width:296px}.nk-emoji-search{width:100%;font-family:inherit;font-size:14px;color:var(--nk-text);background:var(--nk-bg-input);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:6px 10px;outline:none;margin-bottom:8px}.nk-emoji-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:2px}.nk-emoji-grid span,.nk-emoji-grid ::slotted(span){font-size:18px;text-align:center;padding:4px 0;border-radius:5px;cursor:pointer;user-select:none}.nk-emoji-grid span:hover{background:var(--nk-bg-hover)}.nk-emoji-cats{display:flex;gap:2px;margin-top:8px;padding-top:8px;border-top:1px solid var(--nk-border)}.nk-emoji-cats span{font-size:14px;padding:3px 7px;border-radius:5px;cursor:pointer;color:var(--nk-text-tertiary);filter:grayscale(1);opacity:.6}.nk-emoji-cats span.active,.nk-emoji-cats span:hover{filter:none;opacity:1;background:var(--nk-bg-hover)}.nk-menu{padding:5px;width:230px}.nk-menu-item{display:flex;align-items:center;gap:9px;padding:4px 8px;min-height:var(--_nk-row, 28px);border-radius:5px;cursor:pointer;font-size:14px;user-select:none}.nk-menu-item:hover{background:var(--nk-bg-hover)}.nk-menu-item .m-icon,.nk-menu-item ::slotted(.m-icon),.nk-menu-item ::slotted([slot=\"icon\"]){width:17px;text-align:center;font-size:14px}.nk-menu-item .m-shortcut,.nk-menu-item ::slotted(.m-shortcut){margin-left:auto;font-size:12px;color:var(--nk-text-tertiary)}.nk-menu-item.danger{color:var(--nk-danger)}.nk-menu-item>.nk-switch{margin-left:auto}.nk-menu-sep{border-top:1px solid var(--nk-border);margin:5px 4px}.nk-menu-label{font-size:12px;color:var(--nk-text-tertiary);padding:5px 8px 2px}.nk-pop.floating{z-index:60;opacity:0;visibility:hidden;pointer-events:none;transform:translateY(-4px) scale(.98);transform-origin:top;transition:opacity .15s ease,transform .15s ease,visibility 0s linear .15s}.nk-pop.floating.open{opacity:1;visibility:visible;pointer-events:auto;transform:none;transition:opacity .15s ease,transform .15s ease,visibility 0s}.nk-cmdk-backdrop{position:fixed;inset:0;background:var(--nk-scrim-soft);display:flex;justify-content:center;align-items:flex-start;padding:max(14vh,env(safe-area-inset-top,0px)) env(safe-area-inset-right,0px) env(safe-area-inset-bottom,0px) env(safe-area-inset-left,0px);z-index:110;opacity:0;pointer-events:none;transition:opacity .18s ease}.nk-cmdk-backdrop.open{opacity:1;pointer-events:auto}.nk-cmdk{max-width:100%;width:min(560px,92vw);background:var(--nk-bg);border-radius:12px;box-shadow:var(--nk-shadow-menu);overflow:hidden;transform:scale(.98);transition:transform .18s ease}.nk-cmdk-backdrop.open .nk-cmdk{transform:scale(1)}.nk-cmdk-input-row{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--nk-border)}.nk-cmdk-input-row input{flex:1;border:none;outline:none;background:transparent;font-family:inherit;font-size:16px;color:var(--nk-text)}.nk-cmdk-input-row input::placeholder{color:var(--nk-text-tertiary)}.nk-cmdk-list{max-height:320px;overflow-y:auto;padding:6px}.nk-cmdk-group{font-size:12px;color:var(--nk-text-tertiary);padding:8px 10px 3px}.nk-cmdk-item{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer;font-size:14px;user-select:none}.nk-cmdk-item.selected{background:var(--nk-bg-active)}.nk-cmdk-item .m-icon,.nk-cmdk-item ::slotted(.m-icon),.nk-cmdk-item ::slotted([slot=\"icon\"]){width:17px;text-align:center;font-size:14px}.nk-cmdk-item .m-shortcut,.nk-cmdk-item ::slotted(.m-shortcut){margin-left:auto;font-size:12px;color:var(--nk-text-tertiary)}.nk-cmdk-empty{padding:30px;text-align:center;color:var(--nk-text-tertiary);font-size:13.5px}.nk-cmdk-footer{display:flex;gap:14px;padding:8px 16px;border-top:1px solid var(--nk-border);font-size:11.5px;color:var(--nk-text-tertiary)}.nk-sheet-backdrop{position:fixed;inset:0;z-index:100;display:none;flex-direction:column;align-items:center;justify-content:flex-end;padding-top:max(24px,env(safe-area-inset-top,0px));background:var(--nk-scrim-soft);opacity:0;transition:opacity .2s ease,display .25s allow-discrete}.nk-sheet-backdrop.open{display:flex;opacity:1}@starting-style{.nk-sheet-backdrop.open{opacity:0}}.nk-sheet{--_nk-row: 40px;width:100%;max-width:640px;max-height:100%;overflow-y:auto;overscroll-behavior:contain;padding:6px max(10px,env(safe-area-inset-right,0px)) max(16px,env(safe-area-inset-bottom,0px)) max(10px,env(safe-area-inset-left,0px));background:var(--nk-bg);color:var(--nk-text);border-radius:14px 14px 0 0;box-shadow:var(--nk-shadow-menu);translate:0 100%;transition:translate .25s cubic-bezier(.2,.8,.2,1)}.nk-sheet-backdrop.open .nk-sheet{translate:0 0}@starting-style{.nk-sheet-backdrop.open .nk-sheet{translate:0 100%}}.nk-sheet .sh-grabber,.nk-sheet ::slotted(.sh-grabber){width:36px;height:4px;margin:4px auto 10px;border-radius:2px;background:var(--nk-border-strong)}.nk-sheet .sh-title,.nk-sheet ::slotted(.sh-title){font-size:14px;font-weight:600;text-align:center;padding:0 8px 10px}.nk-toast{position:fixed;bottom:max(20px,calc(env(safe-area-inset-bottom,0px) + 12px));left:50%;transform:translate(-50%) translateY(80px);z-index:120;width:max-content;max-width:calc(100% - 32px);background:var(--nk-text);color:var(--nk-bg);padding:8px 16px;border-radius:8px;font-size:14px;opacity:0;transition:all .3s ease;pointer-events:none;box-shadow:var(--nk-shadow-menu);display:flex;gap:8px;align-items:center}.nk-toast.show{opacity:1;transform:translate(-50%) translateY(0)}.nk-gallery-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(280px,100%),1fr));gap:20px 32px;margin:12px 0}.nk-g-item>h4{font-size:12px;font-weight:500;color:var(--nk-text-tertiary);text-transform:uppercase;letter-spacing:.04em;margin-bottom:8px}.nk-g-item ::slotted(h4){font-size:12px;font-weight:500;color:var(--nk-text-tertiary);text-transform:uppercase;letter-spacing:.04em;margin-bottom:8px!important}.nk-tabs{display:flex;gap:2px;border-bottom:1px solid var(--nk-border);font-size:14px}.nk-tab{padding:7px 11px;cursor:pointer;color:var(--nk-text-secondary);border-bottom:2px solid transparent;margin-bottom:-1px;user-select:none}.nk-tab:hover{color:var(--nk-text)}.nk-tab.active{color:var(--nk-text);border-bottom-color:var(--nk-text);font-weight:500}.nk-tab-panel{padding:12px 2px;color:var(--nk-text-secondary);line-height:1.55;font-size:14px}.nk-template-btn{display:flex;align-items:center;gap:8px;width:100%;font-family:inherit;font-size:14px;color:var(--nk-text-secondary);background:var(--nk-bg-callout);border:none;border-radius:var(--nk-radius);padding:8px 12px;cursor:pointer;margin-bottom:6px;text-align:left}.nk-template-btn:hover{background:var(--nk-bg-hover)}.nk-stats{display:flex;gap:10px}.nk-stat{flex:1;border:1px solid var(--nk-border);border-radius:8px;padding:12px 14px}.nk-stat .s-label,.nk-stat ::slotted(.s-label),.nk-stat ::slotted([slot=\"label\"]){font-size:12px;color:var(--nk-text-secondary);margin-bottom:4px}.nk-stat .s-value,.nk-stat ::slotted(.s-value),.nk-stat ::slotted([slot=\"value\"]){font-size:22px;font-weight:600;letter-spacing:-.01em}.nk-stat .s-delta,.nk-stat ::slotted(.s-delta),.nk-stat ::slotted([slot=\"delta\"]){font-size:12px;margin-top:3px}.nk-stat .s-delta.up,.nk-stat ::slotted(.s-delta.up),.nk-stat ::slotted([slot=\"delta\"].up){color:var(--nk-color-green)}.nk-stat .s-delta.down,.nk-stat ::slotted(.s-delta.down),.nk-stat ::slotted([slot=\"delta\"].down){color:var(--nk-danger)}.nk-synced{border:1.5px solid color-mix(in srgb,var(--nk-danger) 55%,transparent);border-radius:8px;padding:12px 14px;position:relative;margin:8px 0}.nk-synced .synced-badge{position:absolute;top:-9px;right:10px;font-size:11px;background:var(--nk-danger);color:var(--nk-on-accent);border-radius:8px;padding:1px 8px}.nk-segmented{display:inline-flex;background:var(--nk-bg-callout);border-radius:7px;padding:2px}.nk-segmented button{font-family:inherit;font-size:14px;border:none;background:transparent;color:var(--nk-text-secondary);padding:4px 12px;border-radius:5px;cursor:pointer}.nk-segmented ::slotted(button){font-family:inherit;font-size:14px;border:none;background:transparent;color:var(--nk-text-secondary);padding:4px 12px!important;border-radius:5px;cursor:pointer}.nk-segmented button.active,.nk-segmented ::slotted(button.active){background:var(--nk-bg);color:var(--nk-text);font-weight:500;box-shadow:var(--nk-shadow-segment)}.nk-segmented.wrap{flex-wrap:wrap}.nk-segmented.scroll{max-width:100%;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}.nk-segmented.scroll::-webkit-scrollbar{display:none}.nk-segmented.scroll button,.nk-segmented.scroll ::slotted(button){flex-shrink:0;white-space:nowrap}.nk-banner{display:flex;align-items:center;gap:10px;font-size:14px;border-radius:8px;padding:10px 14px;margin-bottom:8px;color:var(--nk-text)}.nk-banner.info{background:var(--nk-tint-blue)}.nk-banner.success{background:var(--nk-tint-green)}.nk-banner.warning{background:var(--nk-tint-yellow)}.nk-banner.danger{background:var(--nk-tint-red)}.nk-banner .b-action,.nk-banner ::slotted(.b-action),.nk-banner ::slotted([slot=\"action\"]){margin-left:auto;font-weight:500;cursor:pointer;text-decoration:underline;text-underline-offset:2px}.nk-avatar-group{display:flex}.nk-avatar-group .mini-avatar,.nk-avatar-group .nk-avatar,.nk-avatar-group ::slotted(.mini-avatar),.nk-avatar-group ::slotted(.nk-avatar){width:26px;height:26px;border-radius:50%;color:var(--nk-on-accent);font-size:10.5px;font-weight:600;border:2px solid var(--nk-bg);display:flex;align-items:center;justify-content:center;margin-left:-7px}.nk-avatar-group .mini-avatar:first-child,.nk-avatar-group .nk-avatar:first-child,.nk-avatar-group ::slotted(.mini-avatar:first-child),.nk-avatar-group ::slotted(.nk-avatar:first-child){margin-left:0}.nk-avatar-group .more,.nk-avatar-group ::slotted(.more){background:var(--nk-bg-callout);color:var(--nk-text-secondary)}.nk-avatar{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:24px;height:24px;border-radius:50%;overflow:hidden;vertical-align:middle;font-size:10px;font-weight:600;line-height:1;color:var(--nk-on-accent);user-select:none;background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));object-fit:cover}.nk-avatar.small{width:20px;height:20px;font-size:9px}.nk-avatar.large{width:32px;height:32px;font-size:12px}.nk-avatar.xlarge{width:56px;height:56px;font-size:20px}.nk-avatar.square{border-radius:4px}.nk-avatar>img,.nk-avatar ::slotted(img){display:block;width:100%;height:100%;object-fit:cover}.nk-avatar.gray{background:var(--nk-color-gray)}.nk-avatar.brown{background:var(--nk-color-brown)}.nk-avatar.orange{background:var(--nk-color-orange)}.nk-avatar.yellow{background:var(--nk-color-yellow)}.nk-avatar.green{background:var(--nk-color-green)}.nk-avatar.blue{background:var(--nk-color-blue)}.nk-avatar.purple{background:var(--nk-color-purple)}.nk-avatar.pink{background:var(--nk-color-pink)}.nk-avatar.red{background:var(--nk-color-red)}.nk-panels{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(200px,100%),1fr));gap:12px;margin:12px 0}.nk-panel{display:flex;flex-direction:column;gap:6px;min-width:0;padding:14px 16px;border:1px solid var(--nk-border);border-radius:10px;background:var(--nk-bg-card);box-shadow:var(--nk-shadow-card);font-size:14px;line-height:1.5;color:inherit;text-decoration:none;text-align:left}:is(a,button).nk-panel{cursor:pointer;font-family:inherit;transition:border-color .15s,background .15s}:is(a,button).nk-panel:hover{border-color:var(--nk-border-strong)}.nk-panel>h3{font-size:14px;font-weight:600;line-height:1.4}.nk-panel ::slotted(h3){font-size:14px;font-weight:600;line-height:1.4;margin:0!important}.nk-panel>p{font-size:13px;color:var(--nk-text-secondary)}.nk-panel ::slotted(p){font-size:13px;color:var(--nk-text-secondary);margin:0!important}.nk-panel>.nk-cover{flex:none;height:64px;margin:-14px -16px 2px;border-radius:9px 9px 0 0}.nk-panel>.nk-page-icon{font-size:28px}.nk-panel>.nk-cover+.nk-page-icon{margin-top:-24px}.nk-skeleton{border-radius:5px;margin-bottom:10px;background:linear-gradient(90deg,var(--nk-bg-callout) 25%,var(--nk-bg-hover) 50%,var(--nk-bg-callout) 75%);background-size:200% 100%;animation:nk-shimmer 1.6s infinite}@keyframes nk-shimmer{to{background-position:-200% 0}}.nk-empty{text-align:center;padding:36px 20px;border:1.5px dashed var(--nk-border-strong);border-radius:10px;color:var(--nk-text-tertiary)}.nk-empty .e-icon,.nk-empty ::slotted(.e-icon),.nk-empty ::slotted([slot=\"icon\"]){font-size:30px;margin-bottom:8px}.nk-empty .e-title,.nk-empty ::slotted(.e-title),.nk-empty ::slotted([slot=\"title\"]){font-weight:500;color:var(--nk-text-secondary);margin-bottom:3px;font-size:14px}.nk-empty .e-desc,.nk-empty ::slotted(.e-desc),.nk-empty ::slotted([slot=\"desc\"]){font-size:13px;margin-bottom:12px}.nk-empty .e-actions,.nk-empty ::slotted(.e-actions){display:flex;flex-wrap:wrap;justify-content:center;gap:8px}.nk-steps{display:flex;flex-direction:column;margin:8px 0;padding:0;list-style:none;font-size:14px}.nk-step{position:relative;display:flex;align-items:flex-start;gap:10px;padding-bottom:14px;line-height:20px;color:var(--nk-text-tertiary)}.nk-step:last-child{padding-bottom:0}.nk-step:not(:last-child):after{content:\"\";position:absolute;left:10px;top:24px;bottom:4px;width:1px;background:var(--nk-border)}.nk-step .st-mark{flex:none;width:20px;height:20px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--nk-border-strong);background:var(--nk-bg);font-size:11px;font-weight:600;line-height:1}.nk-step .st-desc{display:block;font-size:12px;line-height:18px;color:var(--nk-text-tertiary);font-weight:400}.nk-step.done{color:var(--nk-text-secondary)}.nk-step.done .st-mark{background:var(--nk-tag-green-bg);color:var(--nk-tag-green-text);border-color:transparent}.nk-step.current{color:var(--nk-text);font-weight:500}.nk-step.current .st-mark{border-color:var(--nk-accent);color:var(--nk-accent)}.nk-comments{border-left:1px solid var(--nk-border);padding:4px 0 4px 18px;margin:8px 0 8px 8px}.nk-comment{display:flex;gap:9px;margin-bottom:14px}.nk-comment .mini-avatar,.nk-comment ::slotted(.mini-avatar),.nk-comment ::slotted([slot=\"avatar\"]){width:24px;height:24px;border-radius:50%;color:var(--nk-on-accent);flex-shrink:0;font-size:10px;font-weight:600;display:flex;align-items:center;justify-content:center}.nk-comment .c-head,.nk-comment ::slotted(.c-head){font-size:12px;color:var(--nk-text-tertiary);margin-bottom:2px}.nk-comment .c-head b{color:var(--nk-text);font-weight:600}.nk-comment .c-body,.nk-comment ::slotted(.c-body){font-size:14px;line-height:1.5}.nk-comment-input{display:flex;gap:8px;align-items:center;margin-top:4px}.nk-comment-input input{min-width:0;flex:1}.nk-ai-thread{display:flex;flex-direction:column;gap:14px}.nk-ai-msg{display:flex;gap:9px}.nk-ai-msg .mini-avatar,.nk-ai-msg ::slotted(.mini-avatar),.nk-ai-msg ::slotted([slot=\"avatar\"]){width:24px;height:24px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:12px;background:var(--nk-bg-callout)}.nk-ai-msg.user .mini-avatar,.nk-ai-msg.user ::slotted(.mini-avatar),.nk-ai-msg.user ::slotted([slot=\"avatar\"]){background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-size:9.5px;font-weight:600}.nk-ai-msg .a-body,.nk-ai-msg ::slotted(.a-body){font-size:14px;line-height:1.55;padding-top:2px}.nk-ai-msg .a-name,.nk-ai-msg ::slotted(.a-name){font-size:12px;font-weight:600;margin-bottom:2px}.nk-ai-msg .a-name span{color:var(--nk-text-tertiary);font-weight:400}.nk-ai-msg.user.bubble{justify-content:flex-end}.nk-ai-msg.bubble .a-body,.nk-ai-msg.bubble ::slotted(.a-body){max-width:85%;padding:6px 12px;border-radius:16px;background:var(--nk-bg-callout)}.nk-ai-actions{display:flex;gap:4px;margin-top:6px}.nk-ai-actions button{font-family:inherit;font-size:12px;color:var(--nk-text-secondary);background:transparent;border:1px solid var(--nk-border);border-radius:5px;padding:2px 8px;cursor:pointer}.nk-ai-actions ::slotted(button){font-family:inherit;font-size:12px;color:var(--nk-text-secondary);background:transparent;border:1px solid var(--nk-border);border-radius:5px;padding:2px 8px!important;cursor:pointer}.nk-ai-actions button:hover,.nk-ai-actions ::slotted(button:hover){background:var(--nk-bg-hover);color:var(--nk-text)}.nk-ai-input-row{display:flex;align-items:center;gap:8px;margin-top:14px;border:1px solid var(--nk-border-strong);border-radius:10px;padding:8px 12px}.nk-ai-input-row:focus-within{border-color:var(--nk-accent)}.nk-ai-input-row input{flex:1;border:none;outline:none;background:transparent;font-family:inherit;font-size:14px;color:var(--nk-text);min-width:0}.nk-ai-input-row input::placeholder{color:var(--nk-text-tertiary)}.nk-ai-send{border:none;background:var(--nk-accent);color:var(--nk-on-accent);border-radius:6px;width:26px;height:26px;cursor:pointer;font-size:13px;flex-shrink:0}.nk-block-host{position:relative;border-radius:var(--nk-radius);margin:8px 0;padding:2px 0 2px 2px;transition:background .15s,box-shadow .15s}.nk-block-host:hover{background:var(--nk-bg-hover)}.nk-block-host:focus-within{background:transparent;box-shadow:0 0 0 2px color-mix(in srgb,var(--nk-accent) 25%,transparent)}.nk-block-host.nk-drop-target{box-shadow:0 -2px 0 0 var(--nk-accent);background:transparent}.nk-block-host .nk-block-handle,.nk-block-host ::slotted(.nk-block-handle){position:absolute;left:-26px;top:4px;width:18px;height:20px;border-radius:4px;display:flex;align-items:center;justify-content:center;color:var(--nk-text-tertiary);font-size:13px;cursor:grab;opacity:0;transition:opacity .15s;user-select:none}.nk-block-host:hover .nk-block-handle{opacity:1}.nk-block-host .nk-block-actions{position:absolute;display:flex;gap:1px;z-index:2;opacity:0;transition:opacity .15s;pointer-events:none}.nk-block-host .nk-block-actions.show{opacity:1;pointer-events:auto}.nk-block-host .nk-block-actions button,.nk-block-host .nk-block-actions ::slotted(button){width:20px;height:22px;padding:0;border:none;border-radius:4px;background:transparent;color:var(--nk-text-tertiary);font-family:inherit;font-size:14px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center}.nk-block-host .nk-block-actions button:hover{background:var(--nk-bg-hover);color:var(--nk-text)}.nk-block-host .nk-block-actions .drag{cursor:grab}.nk-block-host .nk-block-actions .drag:active{cursor:grabbing}.nk-prose,.nk-block-host .ProseMirror{font-family:var(--nk-font);line-height:1.5;color:var(--nk-text);overflow-wrap:break-word}.nk-block-host .ProseMirror{outline:none;min-height:60px;padding:4px 2px}.nk-prose>*+*,.nk-block-host .ProseMirror>*+*{margin-top:6px}.nk-prose h1,.nk-block-host .ProseMirror h1{font-size:1.875em;font-weight:600;line-height:1.3;letter-spacing:-.01em;margin:32px 0 4px}.nk-prose h2,.nk-block-host .ProseMirror h2{font-size:1.5em;font-weight:600;line-height:1.3;margin:24px 0 4px}.nk-prose h3,.nk-block-host .ProseMirror h3{font-size:1.25em;font-weight:600;line-height:1.3;margin:16px 0 2px}.nk-prose :is(h4,h5,h6),.nk-block-host .ProseMirror :is(h4,h5,h6){font-size:1em;font-weight:600;margin:12px 0 0}.nk-prose>:first-child,.nk-block-host .ProseMirror>:first-child{margin-top:0}.nk-prose>:last-child,.nk-block-host .ProseMirror>:last-child{margin-bottom:0}.nk-prose p:empty:before{content:\"\";display:inline-block}.nk-prose :is(strong,b),.nk-block-host .ProseMirror :is(strong,b){font-weight:600}.nk-prose :is(ul,ol),.nk-block-host .ProseMirror :is(ul,ol){padding-left:24px;margin:4px 0}.nk-prose ul,.nk-block-host .ProseMirror ul{list-style:disc}.nk-prose ol,.nk-block-host .ProseMirror ol{list-style:decimal}.nk-prose li,.nk-block-host .ProseMirror li{margin:2px 0}.nk-prose li::marker,.nk-block-host .ProseMirror li::marker{color:var(--nk-text-tertiary)}.nk-prose ul[data-type=taskList],.nk-block-host .ProseMirror ul[data-type=taskList]{list-style:none;padding-left:2px}.nk-prose ul[data-type=taskList] li,.nk-block-host .ProseMirror ul[data-type=taskList] li{display:flex;gap:8px;align-items:flex-start}.nk-prose ul[data-type=taskList] li>label,.nk-block-host .ProseMirror ul[data-type=taskList] li>label{flex-shrink:0;margin-top:max(0px,calc((1lh - 16px)/2));user-select:none}.nk-prose ul[data-type=taskList] li>div,.nk-block-host .ProseMirror ul[data-type=taskList] li>div{flex:1;min-width:0}.nk-prose ul[data-type=taskList] input[type=checkbox],.nk-block-host .ProseMirror ul[data-type=taskList] input[type=checkbox]{appearance:none;width:16px;height:16px;margin:0;border:1.4px solid var(--nk-border-strong);border-radius:2px;cursor:pointer;position:relative;background:var(--nk-bg);display:block}.nk-prose ul[data-type=taskList] input[type=checkbox]:checked,.nk-block-host .ProseMirror ul[data-type=taskList] input[type=checkbox]:checked{background:var(--nk-accent);border-color:var(--nk-accent)}.nk-prose ul[data-type=taskList] input[type=checkbox]:checked:after,.nk-block-host .ProseMirror ul[data-type=taskList] input[type=checkbox]:checked:after{content:\"\\2713\";color:var(--nk-on-accent);font-size:11px;position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.nk-prose li[data-checked=true]>div,.nk-block-host .ProseMirror li[data-checked=true]>div{text-decoration:line-through;color:var(--nk-text-tertiary)}.nk-prose blockquote,.nk-block-host .ProseMirror blockquote{border-left:3px solid var(--nk-text);padding:2px 0 2px 14px;margin:12px 0;color:var(--nk-text-secondary)}.nk-prose code,.nk-block-host .ProseMirror code{font-family:var(--nk-font-mono);font-size:85%;color:var(--nk-danger);background:color-mix(in srgb,var(--nk-danger) 8%,transparent);border-radius:4px;padding:1px 5px}.nk-prose pre,.nk-block-host .ProseMirror pre{background:var(--nk-bg-code);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:16px 20px;margin:12px 0;font-family:var(--nk-font-mono);font-size:13px;line-height:1.6;color:var(--nk-text-secondary);overflow-x:auto}.nk-prose pre code,.nk-block-host .ProseMirror pre code{background:none;color:inherit;padding:0;font-size:inherit}.nk-prose hr,.nk-block-host .ProseMirror hr{border:none;border-top:1px solid var(--nk-border);margin:20px 0}.nk-prose a,.nk-block-host .ProseMirror a{color:var(--nk-accent);text-decoration:underline;text-underline-offset:2px}.nk-prose img{max-width:100%;height:auto}.nk-prose table{display:block;width:max-content;max-width:100%;overflow-x:auto;border-collapse:collapse;font-size:14px;margin:12px 0}.nk-prose :is(th,td){padding:6px 10px;border:1px solid var(--nk-border);text-align:left;vertical-align:top}.nk-prose th{font-weight:600}.nk-block-host .ProseMirror-gapcursor:after{border-top-color:var(--nk-text)}.nk-block-host .ProseMirror .ProseMirror-selectednode{background:color-mix(in srgb,var(--nk-accent) 8%,transparent)}.nk-block-host .ProseMirror-selectednode{box-shadow:0 0 0 2px color-mix(in srgb,var(--nk-accent) 35%,transparent);border-radius:3px}.nk-block-host .ProseMirror ::selection{background:color-mix(in srgb,var(--nk-accent) 25%,transparent)}.nk-block-host .ProseMirror p.is-editor-empty:first-child:before,.nk-block-host .ProseMirror .is-empty:before{content:attr(data-placeholder);color:var(--nk-text-tertiary);float:left;height:0;pointer-events:none}.nk-block-host .bn-container{font-family:var(--nk-font);color:var(--nk-text);background:transparent}.nk-block-host .bn-editor{padding:4px 2px}.nk-block-host .bn-block-content{font-size:14px;line-height:1.6}.nk-block-host .bn-side-menu{color:var(--nk-text-tertiary)}.nk-block-host .bn-drag-handle{border-radius:4px}.nk-block-host .bn-drag-handle:hover{background:var(--nk-bg-hover)}.nk-block-host .novel-editor{font-family:var(--nk-font);color:var(--nk-text)}.nk-block-host .novel-prose{max-width:none}.nk-slash-menu,.nk-block-host .bn-suggestion-menu,.nk-block-host .tippy-box{background:var(--nk-bg);border-radius:10px;box-shadow:var(--nk-shadow-menu);padding:6px;width:280px;max-height:320px;overflow-y:auto;font-family:var(--nk-font);font-size:14px;color:var(--nk-text)}.nk-slash-menu-label{font-size:12px;color:var(--nk-text-tertiary);padding:6px 9px 2px}.nk-slash-item{display:flex;align-items:center;gap:10px;padding:6px 9px;border-radius:5px;cursor:pointer;user-select:none}.nk-slash-item:hover,.nk-slash-item.selected{background:var(--nk-bg-hover)}.nk-slash-item .m-icon,.nk-slash-item ::slotted(.m-icon){width:28px;height:28px;flex-shrink:0;border-radius:4px;background:var(--nk-bg-callout);border:1px solid var(--nk-border);display:flex;align-items:center;justify-content:center;font-size:15px}.nk-slash-item .m-desc{font-size:12px;color:var(--nk-text-tertiary)}.nk-bubble-menu{display:flex;align-items:center;gap:2px;background:var(--nk-bg);border-radius:8px;box-shadow:var(--nk-shadow-menu);padding:4px}.nk-bubble-menu button{font-family:inherit;font-size:13px;border:none;background:transparent;color:var(--nk-text-secondary);padding:4px 8px;border-radius:5px;cursor:pointer}.nk-bubble-menu ::slotted(button){font-family:inherit;font-size:13px;border:none;background:transparent;color:var(--nk-text-secondary);padding:4px 8px!important;border-radius:5px;cursor:pointer}.nk-bubble-menu button:hover,.nk-bubble-menu ::slotted(button:hover){background:var(--nk-bg-hover);color:var(--nk-text)}.nk-bubble-menu button.active,.nk-bubble-menu ::slotted(button.active){color:var(--nk-accent)}@media(max-width:860px){.nk-sidebar{display:none;position:fixed;inset:0 auto 0 0;z-index:60;transform:translate(-100%);transition:background .25s ease,transform .24s cubic-bezier(.2,.8,.25,1),display .24s allow-discrete}.nk-sidebar.open{display:flex;transform:none}@starting-style{.nk-sidebar.open{transform:translate(-100%)}}.nk-sidebar-backdrop{opacity:0;transition:opacity .24s ease,display .24s allow-discrete}.nk-sidebar-backdrop.open{display:block;opacity:1}@starting-style{.nk-sidebar-backdrop.open{opacity:0}}.nk-sidebar-toggle{display:inline-flex}.nk-tab-bar{display:flex}.nk-tab-bar.fixed+.nk-tab-bar-spacer{display:block}.nk-page{padding-left:max(24px,env(safe-area-inset-left,0px));padding-right:max(24px,env(safe-area-inset-right,0px));padding-bottom:80px}.nk-settings-nav{width:60px;min-width:60px}.nk-settings-nav .label,.nk-settings-nav .nk-section-label,.nk-settings-user .u-text{display:none}.nk-settings-content{padding:24px}.nk-cmdk-backdrop{padding-top:max(6vh,env(safe-area-inset-top,0px))}.nk-cmdk{width:min(560px,96vw)}.nk-stats{flex-wrap:wrap}.nk-breadcrumb{min-width:0}.nk-breadcrumb>.crumb:not(:last-child),.nk-breadcrumb ::slotted(.crumb:not(:last-child)),.nk-breadcrumb>.sep,.nk-breadcrumb ::slotted(.sep),.nk-topbar-meta,.nk-topbar-actions ::slotted(.nk-topbar-meta){display:none}.nk-breadcrumb>.crumb:last-child,.nk-breadcrumb ::slotted(.crumb:last-child){display:block;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nk-topbar-actions{flex-shrink:0}.nk-field{flex-wrap:wrap;row-gap:6px}.nk-field .f-control,.nk-field ::slotted(.f-control){max-width:100%;min-width:0}.nk-input,.nk-select,.nk-textarea,.nk-slider{max-width:100%}.nk-prop{flex-direction:column;align-items:stretch}.nk-prop .p-name{flex:none;min-height:26px}.nk-prop .p-value{min-height:30px;padding:3px 6px 7px}.nk-pop.sheet{position:fixed!important;inset:auto 0 0!important;width:auto!important;transform:none!important;z-index:100;--_nk-row: 40px;max-height:85dvh;overflow-y:auto;overscroll-behavior:contain;border-radius:14px 14px 0 0;padding:6px max(8px,env(safe-area-inset-right,0px)) max(12px,env(safe-area-inset-bottom,0px)) max(8px,env(safe-area-inset-left,0px));box-shadow:0 0 0 100vmax var(--nk-scrim-soft),var(--nk-shadow-menu)}.nk-pop.sheet:before{content:\"\";display:block;width:36px;height:4px;margin:4px auto 8px;border-radius:2px;background:var(--nk-border-strong)}.nk-pop.sheet.floating{translate:0 100%;transition:opacity .2s ease,translate .25s cubic-bezier(.2,.8,.2,1),visibility 0s linear .25s}.nk-pop.sheet.floating.open{translate:0 0;transition:opacity .2s ease,translate .25s cubic-bezier(.2,.8,.2,1),visibility 0s}:root:has(.nk-tab-bar:not([hidden])) .nk-toast{bottom:calc(var(--nk-tab-bar-height) + max(6px,env(safe-area-inset-bottom,0px)) + 6px)}:root:has(.nk-tab-bar.floating:not([hidden])) .nk-toast{bottom:calc(var(--nk-tab-bar-height) + 24px + env(safe-area-inset-bottom,0px))}}@media(prefers-reduced-motion:reduce){.nk-skeleton{animation:none;background:var(--nk-bg-callout)}[class*=nk-],[class*=nk-]:before,[class*=nk-]:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}\n/*# sourceMappingURL=notionkit.min.css.map */\n";
|
|
10
10
|
|
|
11
11
|
const componentsCss = componentsHead + componentsTail;
|
|
12
12
|
const css = componentsHead + tokensCss + componentsTail;
|
|
@@ -366,13 +366,16 @@ class NkFormElement extends NkElement {
|
|
|
366
366
|
// <nk-btn variant="primary" small>Save</nk-btn> → <button class="nk-btn primary small">
|
|
367
367
|
// <nk-btn href="/docs" variant="secondary">Docs</nk-btn> → <a class="nk-btn secondary">
|
|
368
368
|
// <nk-btn variant="topbar">⭐</nk-btn> → <button class="nk-topbar-btn">
|
|
369
|
+
// <nk-btn variant="tool" active>Filter</nk-btn> → <button class="nk-db-tool active"> (slot="tools" of nk-database)
|
|
370
|
+
// <nk-btn variant="sidebar" aria-label="Menu">☰</nk-btn> → <button class="nk-topbar-btn nk-sidebar-toggle">:
|
|
371
|
+
// shown on phones only, it opens the page's <nk-sidebar> as a drawer.
|
|
369
372
|
//
|
|
370
373
|
// Modifier classes become attributes. A slotted <svg> is sized by the
|
|
371
374
|
// `.nk-btn ::slotted(svg)` twin; pass the icon itself, never wrapped.
|
|
372
375
|
const VARIANTS$1 = ['primary', 'secondary', 'danger', 'danger-solid', 'topbar', 'share'];
|
|
373
376
|
|
|
374
377
|
class NkBtn extends NkElement {
|
|
375
|
-
static get observedAttributes() { return ['variant', 'small', 'disabled', 'type', 'href', 'title', 'aria-label']; }
|
|
378
|
+
static get observedAttributes() { return ['variant', 'small', 'disabled', 'type', 'href', 'title', 'aria-label', 'aria-haspopup', 'active']; }
|
|
376
379
|
|
|
377
380
|
render() {
|
|
378
381
|
this._build();
|
|
@@ -400,13 +403,22 @@ class NkBtn extends NkElement {
|
|
|
400
403
|
else el.setAttribute('aria-disabled', disabled ? 'true' : 'false');
|
|
401
404
|
const title = this.getAttribute('title');
|
|
402
405
|
title ? el.setAttribute('title', title) : el.removeAttribute('title');
|
|
403
|
-
|
|
404
|
-
|
|
406
|
+
// The accessible name and the popup hint belong on the button itself.
|
|
407
|
+
for (const name of ['aria-label', 'aria-haspopup']) {
|
|
408
|
+
const v = this.getAttribute(name);
|
|
409
|
+
v ? el.setAttribute(name, v) : el.removeAttribute(name);
|
|
410
|
+
}
|
|
411
|
+
if (this.getAttribute('variant') === 'sidebar') el.setAttribute('aria-expanded', this._sidebar()?.open ? 'true' : 'false');
|
|
412
|
+
else el.removeAttribute('aria-expanded');
|
|
405
413
|
}
|
|
406
414
|
|
|
415
|
+
/** The sidebar the ☰ opens: the one in its own app, else the page's. */
|
|
416
|
+
_sidebar() { return this.closest('nk-app')?.querySelector('nk-sidebar') ?? document.querySelector('nk-sidebar'); }
|
|
417
|
+
|
|
407
418
|
setupEvents() {
|
|
408
419
|
this._onClick = (e) => {
|
|
409
420
|
if (this.getBoolAttr('disabled')) { e.preventDefault(); e.stopPropagation(); return; }
|
|
421
|
+
if (this.getAttribute('variant') === 'sidebar') { this._sidebar()?.toggle?.(); return; }
|
|
410
422
|
// A button inside a shadow root is not a submit button of the outer
|
|
411
423
|
// form; forward the intent to the form the host sits in.
|
|
412
424
|
const type = this.getAttribute('type');
|
|
@@ -415,11 +427,17 @@ class NkBtn extends NkElement {
|
|
|
415
427
|
if (form) type === 'submit' ? form.requestSubmit() : form.reset();
|
|
416
428
|
}
|
|
417
429
|
};
|
|
430
|
+
// The ☰ says whether its drawer is open, however the drawer closed.
|
|
431
|
+
this._onToggle = (e) => {
|
|
432
|
+
if (this.getAttribute('variant') === 'sidebar' && e.target === this._sidebar()) this._btn.setAttribute('aria-expanded', e.detail.open ? 'true' : 'false');
|
|
433
|
+
};
|
|
418
434
|
this._btn.addEventListener('click', this._onClick);
|
|
435
|
+
document.addEventListener('nk-toggle', this._onToggle);
|
|
419
436
|
}
|
|
420
437
|
|
|
421
438
|
teardownEvents() {
|
|
422
439
|
this._btn?.removeEventListener('click', this._onClick);
|
|
440
|
+
document.removeEventListener('nk-toggle', this._onToggle);
|
|
423
441
|
}
|
|
424
442
|
|
|
425
443
|
onAttributeChanged(name) {
|
|
@@ -429,7 +447,11 @@ class NkBtn extends NkElement {
|
|
|
429
447
|
this._build();
|
|
430
448
|
break;
|
|
431
449
|
case 'variant':
|
|
450
|
+
this._btn.className = this._computeClasses().join(' ');
|
|
451
|
+
this._applyState(this._btn);
|
|
452
|
+
break;
|
|
432
453
|
case 'small':
|
|
454
|
+
case 'active':
|
|
433
455
|
this._btn.className = this._computeClasses().join(' ');
|
|
434
456
|
break;
|
|
435
457
|
case 'type':
|
|
@@ -444,6 +466,8 @@ class NkBtn extends NkElement {
|
|
|
444
466
|
const variant = this.getAttribute('variant');
|
|
445
467
|
if (variant === 'topbar') return ['nk-topbar-btn'];
|
|
446
468
|
if (variant === 'share') return ['nk-topbar-btn', 'nk-share-btn'];
|
|
469
|
+
if (variant === 'sidebar') return ['nk-topbar-btn', 'nk-sidebar-toggle'];
|
|
470
|
+
if (variant === 'tool') return this.getBoolAttr('active') ? ['nk-db-tool', 'active'] : ['nk-db-tool'];
|
|
447
471
|
const classes = ['nk-btn'];
|
|
448
472
|
if (VARIANTS$1.includes(variant)) classes.push(variant);
|
|
449
473
|
if (this.getBoolAttr('small')) classes.push('small');
|
|
@@ -455,6 +479,8 @@ class NkBtn extends NkElement {
|
|
|
455
479
|
|
|
456
480
|
get variant() { return this.getAttribute('variant'); }
|
|
457
481
|
set variant(v) { v ? this.setAttribute('variant', v) : this.removeAttribute('variant'); }
|
|
482
|
+
get active() { return this.getBoolAttr('active'); }
|
|
483
|
+
set active(v) { this.setBoolAttr('active', v); }
|
|
458
484
|
get small() { return this.getBoolAttr('small'); }
|
|
459
485
|
set small(v) { this.setBoolAttr('small', v); }
|
|
460
486
|
get disabled() { return this.getBoolAttr('disabled'); }
|
|
@@ -1345,9 +1371,10 @@ class NkTag extends NkElement {
|
|
|
1345
1371
|
customElements.define('nk-tag', NkTag);
|
|
1346
1372
|
|
|
1347
1373
|
// <nk-progress value="72" label="72%"></nk-progress>
|
|
1374
|
+
// <nk-progress value="72" label="72 %" wide></nk-progress> → fills its row, the label stays beside it
|
|
1348
1375
|
// The bar is `.nk-progress > i` — a child combinator, so both nodes live here.
|
|
1349
1376
|
class NkProgress extends NkElement {
|
|
1350
|
-
static get observedAttributes() { return ['value', 'max', 'label']; }
|
|
1377
|
+
static get observedAttributes() { return ['value', 'max', 'label', 'wide']; }
|
|
1351
1378
|
|
|
1352
1379
|
render() {
|
|
1353
1380
|
this._bar = this.createElement('span', ['nk-progress'], { role: 'progressbar' });
|
|
@@ -1366,6 +1393,7 @@ class NkProgress extends NkElement {
|
|
|
1366
1393
|
const max = Number(this.getAttribute('max')) || 100;
|
|
1367
1394
|
const value = Math.min(max, Math.max(0, Number(this.getAttribute('value')) || 0));
|
|
1368
1395
|
this._fill.style.width = `${(value / max) * 100}%`;
|
|
1396
|
+
this._bar.classList.toggle('wide', this.getBoolAttr('wide'));
|
|
1369
1397
|
this._bar.setAttribute('aria-valuenow', value);
|
|
1370
1398
|
this._bar.setAttribute('aria-valuemin', 0);
|
|
1371
1399
|
this._bar.setAttribute('aria-valuemax', max);
|
|
@@ -1709,42 +1737,12 @@ customElements.define('nk-app', NkApp);
|
|
|
1709
1737
|
//
|
|
1710
1738
|
// The host is display:contents so the <aside> is a direct flex child of
|
|
1711
1739
|
// .nk-app, exactly like the class markup. Below 860px notionkit.css hides the
|
|
1712
|
-
// aside; `open` brings it back as
|
|
1713
|
-
//
|
|
1714
|
-
//
|
|
1715
|
-
//
|
|
1716
|
-
//
|
|
1717
|
-
// value is held for the whole duration, so closing animates too) and
|
|
1718
|
-
// @starting-style gives the first frame after display: none its start
|
|
1719
|
-
// values. `position: fixed` lives on the plain .nk-sidebar, not on the open
|
|
1720
|
-
// state – while closing, the aside is still displayed and must not fall
|
|
1721
|
-
// back into the flow. Browsers without either feature switch hard, as
|
|
1722
|
-
// before; prefers-reduced-motion switches hard on purpose.
|
|
1723
|
-
const drawerSheet = new CSSStyleSheet();
|
|
1724
|
-
drawerSheet.replaceSync(`
|
|
1725
|
-
.nk-sidebar-backdrop { display: none; position: fixed; inset: 0; z-index: 59; background: var(--nk-scrim-soft); }
|
|
1726
|
-
@media (max-width: 860px) {
|
|
1727
|
-
.nk-sidebar {
|
|
1728
|
-
position: fixed; inset: 0 auto 0 0; z-index: 60;
|
|
1729
|
-
transform: translateX(-100%);
|
|
1730
|
-
transition: background .25s ease, transform .24s cubic-bezier(.2, .8, .25, 1), display .24s;
|
|
1731
|
-
transition-behavior: allow-discrete;
|
|
1732
|
-
}
|
|
1733
|
-
:host([open]) .nk-sidebar { display: flex; transform: none; }
|
|
1734
|
-
@starting-style { :host([open]) .nk-sidebar { transform: translateX(-100%); } }
|
|
1735
|
-
.nk-sidebar-backdrop {
|
|
1736
|
-
opacity: 0;
|
|
1737
|
-
transition: opacity .24s ease, display .24s;
|
|
1738
|
-
transition-behavior: allow-discrete;
|
|
1739
|
-
}
|
|
1740
|
-
:host([open]) .nk-sidebar-backdrop { display: block; opacity: 1; }
|
|
1741
|
-
@starting-style { :host([open]) .nk-sidebar-backdrop { opacity: 0; } }
|
|
1742
|
-
}
|
|
1743
|
-
@media (prefers-reduced-motion: reduce) { .nk-sidebar, .nk-sidebar-backdrop { transition: none; } }
|
|
1744
|
-
`);
|
|
1745
|
-
|
|
1740
|
+
// aside; `open` brings it back as a drawer over the page. The drawer is the
|
|
1741
|
+
// stylesheet's since NotionKit 1.7.0 (.nk-sidebar.open, .nk-sidebar-backdrop
|
|
1742
|
+
// .open) – the sidebar slides and the scrim fades by the same rules as the
|
|
1743
|
+
// class markup; the element toggles the two classes. <nk-btn variant="sidebar">
|
|
1744
|
+
// in the topbar is the ☰ that opens it.
|
|
1746
1745
|
class NkSidebar extends NkElement {
|
|
1747
|
-
static get hostStyles() { return drawerSheet; }
|
|
1748
1746
|
static get observedAttributes() { return ['open']; }
|
|
1749
1747
|
|
|
1750
1748
|
render() {
|
|
@@ -1761,6 +1759,13 @@ class NkSidebar extends NkElement {
|
|
|
1761
1759
|
this._wrapper.appendChild(this._backdrop);
|
|
1762
1760
|
this._wrapper.appendChild(this._aside);
|
|
1763
1761
|
this._syncFooter();
|
|
1762
|
+
this._syncOpen();
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
_syncOpen() {
|
|
1766
|
+
const open = this.getBoolAttr('open');
|
|
1767
|
+
this._aside.classList.toggle('open', open);
|
|
1768
|
+
this._backdrop.classList.toggle('open', open);
|
|
1764
1769
|
}
|
|
1765
1770
|
|
|
1766
1771
|
_syncFooter() {
|
|
@@ -1787,7 +1792,9 @@ class NkSidebar extends NkElement {
|
|
|
1787
1792
|
}
|
|
1788
1793
|
|
|
1789
1794
|
onAttributeChanged(name) {
|
|
1790
|
-
if (name
|
|
1795
|
+
if (name !== 'open') return;
|
|
1796
|
+
this._syncOpen();
|
|
1797
|
+
this.emit('nk-toggle', { open: this.getBoolAttr('open') });
|
|
1791
1798
|
}
|
|
1792
1799
|
|
|
1793
1800
|
show() { this.setBoolAttr('open', true); }
|
|
@@ -2517,7 +2524,7 @@ class NkTabBarItem extends NkElement {
|
|
|
2517
2524
|
|
|
2518
2525
|
customElements.define('nk-tab-bar-item', NkTabBarItem);
|
|
2519
2526
|
|
|
2520
|
-
// <nk-page icon="🚀" cover>
|
|
2527
|
+
// <nk-page icon="🚀" cover full small>
|
|
2521
2528
|
// <nk-page-title>NotionKit MVP</nk-page-title>
|
|
2522
2529
|
// <nk-page-actions>…</nk-page-actions>
|
|
2523
2530
|
// <p class="lead">…</p>
|
|
@@ -2529,9 +2536,10 @@ customElements.define('nk-tab-bar-item', NkTabBarItem);
|
|
|
2529
2536
|
// The host is display:contents, so .nk-page-scroll is the flex child of
|
|
2530
2537
|
// .nk-main that scrolls. `narrow` drops the scroll wrapper for pages that are
|
|
2531
2538
|
// the document itself (landing / docs skeleton). The page icon is rendered
|
|
2532
|
-
// here because its ::slotted twin is keyed on the parent (.nk-page).
|
|
2539
|
+
// here because its ::slotted twin is keyed on the parent (.nk-page). `full` and
|
|
2540
|
+
// `small` are Notion's page options – full width, 14px text – set on the page.
|
|
2533
2541
|
class NkPage extends NkElement {
|
|
2534
|
-
static get observedAttributes() { return ['icon', 'cover', 'narrow']; }
|
|
2542
|
+
static get observedAttributes() { return ['icon', 'cover', 'narrow', 'full', 'small']; }
|
|
2535
2543
|
|
|
2536
2544
|
render() {
|
|
2537
2545
|
this._page = this.createElement('div', ['nk-page']);
|
|
@@ -2568,6 +2576,8 @@ class NkPage extends NkElement {
|
|
|
2568
2576
|
// (attribute or a slotted nk-page-cover) the icon sits in the padding.
|
|
2569
2577
|
const slotted = this._coverSlot.assignedNodes().some(n => n.nodeType === Node.ELEMENT_NODE || n.data.trim());
|
|
2570
2578
|
this._page.classList.toggle('covered', this.getBoolAttr('cover') || slotted);
|
|
2579
|
+
this._page.classList.toggle('full', this.getBoolAttr('full'));
|
|
2580
|
+
this._page.classList.toggle('small', this.getBoolAttr('small'));
|
|
2571
2581
|
}
|
|
2572
2582
|
|
|
2573
2583
|
setupEvents() {
|
|
@@ -2589,17 +2599,25 @@ class NkPage extends NkElement {
|
|
|
2589
2599
|
set icon(v) { v == null ? this.removeAttribute('icon') : this.setAttribute('icon', v); }
|
|
2590
2600
|
get cover() { return this.getBoolAttr('cover'); }
|
|
2591
2601
|
set cover(v) { this.setBoolAttr('cover', v); }
|
|
2602
|
+
get full() { return this.getBoolAttr('full'); }
|
|
2603
|
+
set full(v) { this.setBoolAttr('full', v); }
|
|
2604
|
+
get small() { return this.getBoolAttr('small'); }
|
|
2605
|
+
set small(v) { this.setBoolAttr('small', v); }
|
|
2592
2606
|
}
|
|
2593
2607
|
|
|
2594
2608
|
customElements.define('nk-page', NkPage);
|
|
2595
2609
|
|
|
2596
2610
|
// <nk-page-cover slot="cover"></nk-page-cover> → the token gradient
|
|
2597
|
-
// <nk-page-cover slot="cover" src="cover.jpg"></nk-page-cover> →
|
|
2611
|
+
// <nk-page-cover slot="cover" src="cover.jpg" position="center 30%"></nk-page-cover> → a picture
|
|
2612
|
+
// → <div class="nk-cover"><img src="cover.jpg" alt=""></div>: the picture fills
|
|
2613
|
+
// the band, cropped rather than stretched; `position` moves the crop, as
|
|
2614
|
+
// Notion's "Reposition" does. The gradient stays underneath while it loads.
|
|
2598
2615
|
class NkPageCover extends NkElement {
|
|
2599
|
-
static get observedAttributes() { return ['src']; }
|
|
2616
|
+
static get observedAttributes() { return ['src', 'position']; }
|
|
2600
2617
|
|
|
2601
2618
|
render() {
|
|
2602
2619
|
this._cover = this.createElement('div', ['nk-cover']);
|
|
2620
|
+
this._img = this.createElement('img', [], { alt: '' });
|
|
2603
2621
|
this._wrapper.appendChild(this._cover);
|
|
2604
2622
|
this._sync();
|
|
2605
2623
|
}
|
|
@@ -2607,14 +2625,10 @@ class NkPageCover extends NkElement {
|
|
|
2607
2625
|
_sync() {
|
|
2608
2626
|
const src = this.getAttribute('src');
|
|
2609
2627
|
if (src) {
|
|
2610
|
-
this.
|
|
2611
|
-
this.
|
|
2612
|
-
this._cover.
|
|
2613
|
-
} else
|
|
2614
|
-
this._cover.style.backgroundImage = '';
|
|
2615
|
-
this._cover.style.backgroundSize = '';
|
|
2616
|
-
this._cover.style.backgroundPosition = '';
|
|
2617
|
-
}
|
|
2628
|
+
this._img.src = src;
|
|
2629
|
+
this._img.style.objectPosition = this.getAttribute('position') || '';
|
|
2630
|
+
if (!this._img.isConnected) this._cover.appendChild(this._img);
|
|
2631
|
+
} else this._img.remove();
|
|
2618
2632
|
}
|
|
2619
2633
|
|
|
2620
2634
|
onAttributeChanged() { this._sync(); }
|
|
@@ -2995,6 +3009,9 @@ customElements.define('nk-tab', NkTab);
|
|
|
2995
3009
|
// → <div class="nk-segmented">…</div> with .active on the chosen button.
|
|
2996
3010
|
// The buttons stay in the light DOM (their look comes from the ::slotted
|
|
2997
3011
|
// twins); the element sets type/role, moves .active and submits the value.
|
|
3012
|
+
// With `scroll` the chosen option is kept in view – after the first layout,
|
|
3013
|
+
// on every change and when the row's width changes – by scrolling the row
|
|
3014
|
+
// alone, never the page, by a relative distance, so right-to-left works too.
|
|
2998
3015
|
const KEYS = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 };
|
|
2999
3016
|
|
|
3000
3017
|
class NkSegmented extends NkFormElement {
|
|
@@ -3038,6 +3055,19 @@ class NkSegmented extends NkFormElement {
|
|
|
3038
3055
|
}
|
|
3039
3056
|
this._value = value;
|
|
3040
3057
|
this.setFormValue(value);
|
|
3058
|
+
this._reveal(this._revealed ? 'smooth' : 'instant');
|
|
3059
|
+
}
|
|
3060
|
+
|
|
3061
|
+
/** Scrolls the row the least distance that shows the chosen button whole. */
|
|
3062
|
+
_reveal(behavior) {
|
|
3063
|
+
if (!this.getBoolAttr('scroll') || !this._box?.clientWidth) return;
|
|
3064
|
+
const btn = this.buttons.find(b => b.classList.contains('active'));
|
|
3065
|
+
if (!btn) return;
|
|
3066
|
+
const row = this._box.getBoundingClientRect(), r = btn.getBoundingClientRect(), pad = 8;
|
|
3067
|
+
const delta = r.left < row.left ? r.left - row.left - pad : r.right > row.right ? r.right - row.right + pad : 0;
|
|
3068
|
+
const smooth = behavior === 'smooth' && !matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
3069
|
+
if (delta) this._box.scrollBy({ left: delta, behavior: smooth ? 'smooth' : 'instant' });
|
|
3070
|
+
this._revealed = true;
|
|
3041
3071
|
}
|
|
3042
3072
|
|
|
3043
3073
|
setupEvents() {
|
|
@@ -3061,6 +3091,8 @@ class NkSegmented extends NkFormElement {
|
|
|
3061
3091
|
this._slot.addEventListener('slotchange', this._onSlot);
|
|
3062
3092
|
this.addEventListener('click', this._onClick);
|
|
3063
3093
|
this.addEventListener('keydown', this._onKey);
|
|
3094
|
+
this._resize = new ResizeObserver(() => this._reveal('instant'));
|
|
3095
|
+
this._resize.observe(this._box);
|
|
3064
3096
|
this._sync();
|
|
3065
3097
|
}
|
|
3066
3098
|
|
|
@@ -3068,6 +3100,7 @@ class NkSegmented extends NkFormElement {
|
|
|
3068
3100
|
this._slot?.removeEventListener('slotchange', this._onSlot);
|
|
3069
3101
|
this.removeEventListener('click', this._onClick);
|
|
3070
3102
|
this.removeEventListener('keydown', this._onKey);
|
|
3103
|
+
this._resize?.disconnect();
|
|
3071
3104
|
}
|
|
3072
3105
|
|
|
3073
3106
|
_choose(value) {
|
|
@@ -3179,6 +3212,76 @@ class NkAvatarGroup extends NkElement {
|
|
|
3179
3212
|
|
|
3180
3213
|
customElements.define('nk-avatar-group', NkAvatarGroup);
|
|
3181
3214
|
|
|
3215
|
+
// Shared by every element that draws an avatar: nk-avatar itself, member
|
|
3216
|
+
// rows, comments and the person cells of a database view.
|
|
3217
|
+
const AVATAR_COLORS = ['gray', 'brown', 'orange', 'yellow', 'green', 'blue', 'purple', 'pink', 'red'];
|
|
3218
|
+
|
|
3219
|
+
/**
|
|
3220
|
+
* Paints an .nk-avatar. One of Notion's nine colour names becomes its class,
|
|
3221
|
+
* so the tokens decide the shade in each theme; any other value – a hex, a
|
|
3222
|
+
* gradient, a var() – is taken as an inline background, as before 1.6.0.
|
|
3223
|
+
* Without a colour the avatar keeps the stylesheet's gradient.
|
|
3224
|
+
*/
|
|
3225
|
+
function paintAvatar(el, color) {
|
|
3226
|
+
for (const c of AVATAR_COLORS) el.classList.toggle(c, c === color);
|
|
3227
|
+
el.style.background = color && !AVATAR_COLORS.includes(color) ? color : '';
|
|
3228
|
+
}
|
|
3229
|
+
|
|
3230
|
+
/** "Sara Lindt" → "SL". */
|
|
3231
|
+
const initialsOf = name => String(name || '').split(/\s+/).map(w => w[0]).filter(Boolean).join('').slice(0, 2).toUpperCase();
|
|
3232
|
+
|
|
3233
|
+
// <nk-avatar>MK</nk-avatar> → <span class="nk-avatar">MK</span>
|
|
3234
|
+
// <nk-avatar size="small" color="green">SL</nk-avatar>
|
|
3235
|
+
// <nk-avatar name="Ada Lovelace" size="large"></nk-avatar> → initials "AL"
|
|
3236
|
+
// <nk-avatar src="ada.jpg" name="Ada Lovelace" size="xlarge"></nk-avatar>
|
|
3237
|
+
// <nk-avatar square>A</nk-avatar> → a workspace icon
|
|
3238
|
+
// size: small (20px) · default 24px · large (32px) · xlarge (56px). color: one
|
|
3239
|
+
// of Notion's nine names, or any CSS background. Without content the initials
|
|
3240
|
+
// come from `name`; with `src` a photo fills the circle and `name` is its alt.
|
|
3241
|
+
class NkAvatar extends NkElement {
|
|
3242
|
+
static get observedAttributes() { return ['size', 'color', 'square', 'src', 'name']; }
|
|
3243
|
+
|
|
3244
|
+
render() {
|
|
3245
|
+
this._box = this.createElement('span', ['nk-avatar']);
|
|
3246
|
+
this._slot = document.createElement('slot');
|
|
3247
|
+
this._initials = document.createTextNode('');
|
|
3248
|
+
this._slot.appendChild(this._initials);
|
|
3249
|
+
this._img = this.createElement('img', [], { alt: '' });
|
|
3250
|
+
this._box.appendChild(this._slot);
|
|
3251
|
+
this._wrapper.appendChild(this._box);
|
|
3252
|
+
this._sync();
|
|
3253
|
+
}
|
|
3254
|
+
|
|
3255
|
+
_sync() {
|
|
3256
|
+
const size = this.getAttribute('size');
|
|
3257
|
+
for (const s of ['small', 'large', 'xlarge']) this._box.classList.toggle(s, s === size);
|
|
3258
|
+
this._box.classList.toggle('square', this.getBoolAttr('square'));
|
|
3259
|
+
paintAvatar(this._box, this.getAttribute('color'));
|
|
3260
|
+
const name = this.getAttribute('name');
|
|
3261
|
+
this._initials.data = initialsOf(name);
|
|
3262
|
+
const src = this.getAttribute('src');
|
|
3263
|
+
if (src) {
|
|
3264
|
+
this._img.src = src;
|
|
3265
|
+
this._img.alt = name || '';
|
|
3266
|
+
if (this._slot.isConnected) this._slot.replaceWith(this._img);
|
|
3267
|
+
} else if (this._img.isConnected) this._img.replaceWith(this._slot);
|
|
3268
|
+
// A picture or initials with a name speak for themselves; a bare glyph is decoration.
|
|
3269
|
+
if (name && !src) { this._box.setAttribute('role', 'img'); this._box.setAttribute('aria-label', name); }
|
|
3270
|
+
else { this._box.removeAttribute('role'); this._box.removeAttribute('aria-label'); }
|
|
3271
|
+
}
|
|
3272
|
+
|
|
3273
|
+
onAttributeChanged() { this._sync(); }
|
|
3274
|
+
|
|
3275
|
+
get size() { return this.getAttribute('size'); }
|
|
3276
|
+
set size(v) { v == null ? this.removeAttribute('size') : this.setAttribute('size', v); }
|
|
3277
|
+
get color() { return this.getAttribute('color'); }
|
|
3278
|
+
set color(v) { v == null ? this.removeAttribute('color') : this.setAttribute('color', v); }
|
|
3279
|
+
get src() { return this.getAttribute('src'); }
|
|
3280
|
+
set src(v) { v == null ? this.removeAttribute('src') : this.setAttribute('src', v); }
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3283
|
+
customElements.define('nk-avatar', NkAvatar);
|
|
3284
|
+
|
|
3182
3285
|
// <nk-mention type="person"><span slot="avatar" class="mini-avatar" style="background:#448361">SL</span>Sara Lindt</nk-mention>
|
|
3183
3286
|
// <nk-mention type="page">📄 Onboarding</nk-mention> <nk-mention type="date">📅 May 20</nk-mention>
|
|
3184
3287
|
// → <span class="nk-mention person">…</span>
|
|
@@ -3420,16 +3523,18 @@ class NkMemberList extends NkElement {
|
|
|
3420
3523
|
|
|
3421
3524
|
customElements.define('nk-member-list', NkMemberList);
|
|
3422
3525
|
|
|
3423
|
-
// <nk-member-row name="Sara Lindt" mail="sara@…" avatar="SL" color="
|
|
3526
|
+
// <nk-member-row name="Sara Lindt" mail="sara@…" avatar="SL" color="green">
|
|
3424
3527
|
// <nk-select slot="role" compact>…</nk-select>
|
|
3425
3528
|
// </nk-member-row>
|
|
3426
|
-
// → <div class="nk-member-row"><span class="
|
|
3529
|
+
// → <div class="nk-member-row"><span class="nk-avatar green">SL</span><div>Sara Lindt<div class="m-mail">…</div></div><select …></div>
|
|
3530
|
+
// color: one of Notion's nine names, or any CSS background; without it the
|
|
3531
|
+
// avatar gradient. The row sizes the avatar to 28px.
|
|
3427
3532
|
class NkMemberRow extends NkElement {
|
|
3428
3533
|
static get observedAttributes() { return ['name', 'mail', 'avatar', 'color', 'last']; }
|
|
3429
3534
|
|
|
3430
3535
|
render() {
|
|
3431
3536
|
this._row = this.createElement('div', ['nk-member-row']);
|
|
3432
|
-
this._avatar = this.createElement('span', ['
|
|
3537
|
+
this._avatar = this.createElement('span', ['nk-avatar']);
|
|
3433
3538
|
const avatarSlot = this.createElement('slot', [], { name: 'avatar' });
|
|
3434
3539
|
avatarSlot.appendChild(this._avatar);
|
|
3435
3540
|
const text = document.createElement('div');
|
|
@@ -3453,8 +3558,8 @@ class NkMemberRow extends NkElement {
|
|
|
3453
3558
|
this._mail.textContent = mail || '';
|
|
3454
3559
|
this._mail.style.display = mail ? '' : 'none';
|
|
3455
3560
|
const avatar = this.getAttribute('avatar');
|
|
3456
|
-
this._avatar.textContent = avatar || (this.getAttribute('name')
|
|
3457
|
-
this._avatar
|
|
3561
|
+
this._avatar.textContent = avatar || initialsOf(this.getAttribute('name'));
|
|
3562
|
+
paintAvatar(this._avatar, this.getAttribute('color'));
|
|
3458
3563
|
this._row.classList.toggle('last', this.getBoolAttr('last'));
|
|
3459
3564
|
}
|
|
3460
3565
|
|
|
@@ -3463,9 +3568,148 @@ class NkMemberRow extends NkElement {
|
|
|
3463
3568
|
|
|
3464
3569
|
customElements.define('nk-member-row', NkMemberRow);
|
|
3465
3570
|
|
|
3466
|
-
//
|
|
3467
|
-
//
|
|
3468
|
-
//
|
|
3571
|
+
// <nk-props>
|
|
3572
|
+
// <nk-prop label="Status" icon="◉"><nk-tag color="blue">In progress</nk-tag></nk-prop>
|
|
3573
|
+
// <nk-prop label="Owner" icon="👤"><nk-avatar size="small">MK</nk-avatar>Marcel Karas</nk-prop>
|
|
3574
|
+
// </nk-props>
|
|
3575
|
+
// → <dl class="nk-props">…</dl> – the properties under a page title. The rows
|
|
3576
|
+
// are <nk-prop> hosts with display: contents, so each .nk-prop is a row of
|
|
3577
|
+
// this list.
|
|
3578
|
+
class NkProps extends NkElement {
|
|
3579
|
+
render() {
|
|
3580
|
+
const list = this.createElement('dl', ['nk-props']);
|
|
3581
|
+
list.appendChild(document.createElement('slot'));
|
|
3582
|
+
this._wrapper.appendChild(list);
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
|
|
3586
|
+
customElements.define('nk-props', NkProps);
|
|
3587
|
+
|
|
3588
|
+
// <nk-prop label="Due" icon="📅">2 June 2026</nk-prop>
|
|
3589
|
+
// → <div class="nk-prop"><dt class="p-name"><span class="p-icon">📅</span>Due</dt><dd class="p-value">2 June 2026</dd></div>
|
|
3590
|
+
// The value is the element's content – tags, an avatar and a name, a date, a
|
|
3591
|
+
// <nk-progress wide>. slot="icon" replaces the icon glyph. A click on the
|
|
3592
|
+
// name or the value fires nk-action { action: 'name' | 'value', label }, the
|
|
3593
|
+
// moment Notion opens the property's editor.
|
|
3594
|
+
class NkProp extends NkElement {
|
|
3595
|
+
static get observedAttributes() { return ['label', 'icon']; }
|
|
3596
|
+
|
|
3597
|
+
render() {
|
|
3598
|
+
this._row = this.createElement('div', ['nk-prop']);
|
|
3599
|
+
this._name = this.createElement('dt', ['p-name']);
|
|
3600
|
+
this._icon = this.createElement('span', ['p-icon']);
|
|
3601
|
+
const iconSlot = this.createElement('slot', [], { name: 'icon' });
|
|
3602
|
+
iconSlot.appendChild(this._icon);
|
|
3603
|
+
this._label = document.createTextNode('');
|
|
3604
|
+
this._name.append(iconSlot, this._label);
|
|
3605
|
+
this._value = this.createElement('dd', ['p-value']);
|
|
3606
|
+
this._value.appendChild(document.createElement('slot'));
|
|
3607
|
+
this._row.append(this._name, this._value);
|
|
3608
|
+
this._wrapper.appendChild(this._row);
|
|
3609
|
+
this._sync();
|
|
3610
|
+
}
|
|
3611
|
+
|
|
3612
|
+
_sync() {
|
|
3613
|
+
const icon = this.getAttribute('icon');
|
|
3614
|
+
this._icon.textContent = icon || '';
|
|
3615
|
+
this._icon.style.display = icon ? '' : 'none';
|
|
3616
|
+
this._label.data = this.getAttribute('label') || '';
|
|
3617
|
+
}
|
|
3618
|
+
|
|
3619
|
+
setupEvents() {
|
|
3620
|
+
this._onClick = (e) => {
|
|
3621
|
+
const part = e.composedPath().includes(this._name) ? 'name' : 'value';
|
|
3622
|
+
this.emit('nk-action', { action: part, label: this.label });
|
|
3623
|
+
};
|
|
3624
|
+
this._row.addEventListener('click', this._onClick);
|
|
3625
|
+
}
|
|
3626
|
+
|
|
3627
|
+
teardownEvents() { this._row?.removeEventListener('click', this._onClick); }
|
|
3628
|
+
onAttributeChanged() { this._sync(); }
|
|
3629
|
+
|
|
3630
|
+
get label() { return this.getAttribute('label') || ''; }
|
|
3631
|
+
set label(v) { this.setAttribute('label', v); }
|
|
3632
|
+
get icon() { return this.getAttribute('icon'); }
|
|
3633
|
+
set icon(v) { v == null ? this.removeAttribute('icon') : this.setAttribute('icon', v); }
|
|
3634
|
+
}
|
|
3635
|
+
|
|
3636
|
+
customElements.define('nk-prop', NkProp);
|
|
3637
|
+
|
|
3638
|
+
// <nk-panels><nk-panel …></nk-panel><nk-panel …></nk-panel></nk-panels>
|
|
3639
|
+
// → <div class="nk-panels">…</div>: columns of at least 200px that share the
|
|
3640
|
+
// row and fall to one on a phone. The <nk-panel> hosts are display: contents,
|
|
3641
|
+
// so each .nk-panel is a cell of this grid.
|
|
3642
|
+
class NkPanels extends NkElement {
|
|
3643
|
+
render() {
|
|
3644
|
+
const grid = this.createElement('div', ['nk-panels']);
|
|
3645
|
+
grid.appendChild(document.createElement('slot'));
|
|
3646
|
+
this._wrapper.appendChild(grid);
|
|
3647
|
+
}
|
|
3648
|
+
}
|
|
3649
|
+
|
|
3650
|
+
customElements.define('nk-panels', NkPanels);
|
|
3651
|
+
|
|
3652
|
+
// <nk-panel title="Weekly review"><p>Three pages changed.</p></nk-panel>
|
|
3653
|
+
// <nk-panel href="/roadmap" cover="covers/aurora.svg" icon="🚀" title="Roadmap"><p>2 min ago</p></nk-panel>
|
|
3654
|
+
// → <a class="nk-panel" href="/roadmap"><div class="nk-cover"><img src="…" alt=""></div>
|
|
3655
|
+
// <div class="nk-page-icon">🚀</div><h3>Roadmap</h3>…</a>
|
|
3656
|
+
// `cover` without a value draws the token gradient, with one a picture; `icon`
|
|
3657
|
+
// overlaps the cover as on a page – a page tile, as on Notion's Home. With
|
|
3658
|
+
// `href` the panel is a link. `title` is the heading, never a tooltip.
|
|
3659
|
+
class NkPanel extends NkElement {
|
|
3660
|
+
static get observedAttributes() { return ['title', 'icon', 'cover', 'href', 'target']; }
|
|
3661
|
+
|
|
3662
|
+
render() {
|
|
3663
|
+
this._cover = this.createElement('div', ['nk-cover']);
|
|
3664
|
+
this._img = this.createElement('img', [], { alt: '' });
|
|
3665
|
+
this._icon = this.createElement('div', ['nk-page-icon']);
|
|
3666
|
+
this._heading = document.createElement('h3');
|
|
3667
|
+
this._slot = document.createElement('slot');
|
|
3668
|
+
this.takeTitle();
|
|
3669
|
+
this._build();
|
|
3670
|
+
}
|
|
3671
|
+
|
|
3672
|
+
_build() {
|
|
3673
|
+
const href = this.getAttribute('href');
|
|
3674
|
+
const box = this.createElement(href ? 'a' : 'div', ['nk-panel']);
|
|
3675
|
+
box.append(this._cover, this._icon, this._heading, this._slot);
|
|
3676
|
+
this._wrapper.replaceChildren(box);
|
|
3677
|
+
this._box = box;
|
|
3678
|
+
this._sync();
|
|
3679
|
+
}
|
|
3680
|
+
|
|
3681
|
+
_sync() {
|
|
3682
|
+
const href = this.getAttribute('href');
|
|
3683
|
+
if (href) { this._box.setAttribute('href', href); this._box.target = this.getAttribute('target') || ''; }
|
|
3684
|
+
const cover = this.getAttribute('cover');
|
|
3685
|
+
this._cover.style.display = cover === null ? 'none' : '';
|
|
3686
|
+
if (cover) { this._img.src = cover; if (!this._img.isConnected) this._cover.appendChild(this._img); }
|
|
3687
|
+
else this._img.remove();
|
|
3688
|
+
const icon = this.getAttribute('icon');
|
|
3689
|
+
this._icon.textContent = icon || '';
|
|
3690
|
+
this._icon.style.display = icon ? '' : 'none';
|
|
3691
|
+
this._heading.textContent = this._titleText || '';
|
|
3692
|
+
this._heading.style.display = this._titleText ? '' : 'none';
|
|
3693
|
+
}
|
|
3694
|
+
|
|
3695
|
+
onAttributeChanged(name, _old, value) {
|
|
3696
|
+
if (name === 'title' && !this.takeTitle(value)) return;
|
|
3697
|
+
if (name === 'href' && (value === null) !== (this._box.localName === 'div')) { this._build(); return; }
|
|
3698
|
+
this._sync();
|
|
3699
|
+
}
|
|
3700
|
+
|
|
3701
|
+
get title() { return this._titleText ?? ''; }
|
|
3702
|
+
set title(v) { this._titleText = v == null ? '' : String(v); if (this._initialized) this._sync(); }
|
|
3703
|
+
get href() { return this.getAttribute('href'); }
|
|
3704
|
+
set href(v) { v == null ? this.removeAttribute('href') : this.setAttribute('href', v); }
|
|
3705
|
+
}
|
|
3706
|
+
|
|
3707
|
+
customElements.define('nk-panel', NkPanel);
|
|
3708
|
+
|
|
3709
|
+
// Overlay plumbing shared by nk-modal, nk-sheet, nk-cmdk and nk-menu: body
|
|
3710
|
+
// scroll lock with a refcount, `inert` on everything outside the overlay so
|
|
3711
|
+
// focus and assistive technology stay inside – nested shadow roots included –
|
|
3712
|
+
// and the focused element behind shadow hosts, to return focus to.
|
|
3469
3713
|
let locks = 0, previousOverflow = '';
|
|
3470
3714
|
|
|
3471
3715
|
function lockScroll() {
|
|
@@ -3496,6 +3740,13 @@ function inertOutside(el) {
|
|
|
3496
3740
|
return () => { for (const c of made) c.inert = false; };
|
|
3497
3741
|
}
|
|
3498
3742
|
|
|
3743
|
+
/** The focused element itself, looking into shadow roots (document.activeElement stops at the host). */
|
|
3744
|
+
function deepActiveElement() {
|
|
3745
|
+
let el = document.activeElement;
|
|
3746
|
+
while (el?.shadowRoot?.activeElement) el = el.shadowRoot.activeElement;
|
|
3747
|
+
return el;
|
|
3748
|
+
}
|
|
3749
|
+
|
|
3499
3750
|
/** The first tabbable element inside a light-DOM subtree, looking into shadow roots. */
|
|
3500
3751
|
function firstFocusable(root) {
|
|
3501
3752
|
const SEL = 'a[href], button:not([disabled]), input:not([disabled]):not([type=hidden]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"]), [contenteditable="true"], [contenteditable="plaintext-only"]';
|
|
@@ -3509,6 +3760,155 @@ function firstFocusable(root) {
|
|
|
3509
3760
|
return walk(root);
|
|
3510
3761
|
}
|
|
3511
3762
|
|
|
3763
|
+
// <nk-sheet id="more" title="More">
|
|
3764
|
+
// <nk-tree manual>
|
|
3765
|
+
// <nk-section-label>Favourites</nk-section-label>
|
|
3766
|
+
// <nk-tree-item icon="🚀">NotionKit MVP</nk-tree-item>
|
|
3767
|
+
// </nk-tree>
|
|
3768
|
+
// </nk-sheet>
|
|
3769
|
+
// → <div class="nk-sheet-backdrop open"><div class="nk-sheet" role="dialog">
|
|
3770
|
+
// <div class="sh-grabber"></div><div class="sh-title">More</div>…</div></div>
|
|
3771
|
+
//
|
|
3772
|
+
// A bottom sheet (NotionKit 1.7.0) with nk-modal's contract: show(), close()
|
|
3773
|
+
// and toggle(), Escape and the backdrop close it, focus moves in and back
|
|
3774
|
+
// out, the page behind is scroll-locked and inert. It lies above the tab
|
|
3775
|
+
// bar; rows inside are 40px high. `title` is the heading shown under the
|
|
3776
|
+
// grabber and the dialog's name, never a tooltip – see NkElement.takeTitle().
|
|
3777
|
+
// Choosing a row does not close the sheet – the app decides (nk-select
|
|
3778
|
+
// bubbles out). Put the element directly under <body>: a transformed
|
|
3779
|
+
// ancestor would trap the fixed backdrop.
|
|
3780
|
+
class NkSheet extends NkElement {
|
|
3781
|
+
static get observedAttributes() { return ['open', 'title']; }
|
|
3782
|
+
|
|
3783
|
+
render() {
|
|
3784
|
+
this.takeTitle();
|
|
3785
|
+
this._backdrop = this.createElement('div', ['nk-sheet-backdrop']);
|
|
3786
|
+
this._backdrop.inert = true;
|
|
3787
|
+
this._box = this.createElement('div', ['nk-sheet'], { role: 'dialog', 'aria-modal': 'true', tabindex: '-1' });
|
|
3788
|
+
this._heading = this.createElement('div', ['sh-title'], { id: 'title' });
|
|
3789
|
+
this._box.append(this.createElement('div', ['sh-grabber']), this._heading, document.createElement('slot'));
|
|
3790
|
+
this._backdrop.appendChild(this._box);
|
|
3791
|
+
this._wrapper.appendChild(this._backdrop);
|
|
3792
|
+
this._syncTitle();
|
|
3793
|
+
this._syncOpen();
|
|
3794
|
+
}
|
|
3795
|
+
|
|
3796
|
+
_syncTitle() {
|
|
3797
|
+
const text = this._titleText || '';
|
|
3798
|
+
this._heading.textContent = text;
|
|
3799
|
+
this._heading.hidden = !text;
|
|
3800
|
+
if (text) this._box.setAttribute('aria-labelledby', 'title');
|
|
3801
|
+
else this._box.removeAttribute('aria-labelledby');
|
|
3802
|
+
}
|
|
3803
|
+
|
|
3804
|
+
_syncOpen() {
|
|
3805
|
+
const open = this.getBoolAttr('open');
|
|
3806
|
+
this._backdrop.classList.toggle('open', open);
|
|
3807
|
+
this._backdrop.inert = !open;
|
|
3808
|
+
if (open === this._wasOpen) return;
|
|
3809
|
+
this._wasOpen = open;
|
|
3810
|
+
if (open) {
|
|
3811
|
+
this._returnFocus = deepActiveElement();
|
|
3812
|
+
lockScroll();
|
|
3813
|
+
this._undoInert = inertOutside(this);
|
|
3814
|
+
requestAnimationFrame(() => (firstFocusable(this) || this._box).focus({ preventScroll: true }));
|
|
3815
|
+
} else {
|
|
3816
|
+
unlockScroll();
|
|
3817
|
+
this._undoInert?.(); this._undoInert = null;
|
|
3818
|
+
const back = this._returnFocus;
|
|
3819
|
+
if (back && typeof back.focus === 'function' && back.isConnected) back.focus({ preventScroll: true });
|
|
3820
|
+
this._returnFocus = null;
|
|
3821
|
+
}
|
|
3822
|
+
}
|
|
3823
|
+
|
|
3824
|
+
setupEvents() {
|
|
3825
|
+
this._onBackdrop = (e) => { if (e.target === this._backdrop) this.close(); };
|
|
3826
|
+
this._onKey = (e) => { if (e.key === 'Escape' && this.getBoolAttr('open')) { e.stopPropagation(); this.close(); } };
|
|
3827
|
+
this._backdrop.addEventListener('click', this._onBackdrop);
|
|
3828
|
+
document.addEventListener('keydown', this._onKey);
|
|
3829
|
+
}
|
|
3830
|
+
|
|
3831
|
+
teardownEvents() {
|
|
3832
|
+
this._backdrop?.removeEventListener('click', this._onBackdrop);
|
|
3833
|
+
document.removeEventListener('keydown', this._onKey);
|
|
3834
|
+
if (this._wasOpen) { unlockScroll(); this._undoInert?.(); this._undoInert = null; this._wasOpen = false; }
|
|
3835
|
+
}
|
|
3836
|
+
|
|
3837
|
+
onAttributeChanged(name, oldValue, value) {
|
|
3838
|
+
if (name === 'title') { if (this.takeTitle(value)) this._syncTitle(); return; }
|
|
3839
|
+
this._syncOpen();
|
|
3840
|
+
this.emit('nk-toggle', { open: this.getBoolAttr('open') });
|
|
3841
|
+
}
|
|
3842
|
+
|
|
3843
|
+
show() { this.setBoolAttr('open', true); }
|
|
3844
|
+
close() { this.setBoolAttr('open', false); }
|
|
3845
|
+
toggle() { this.setBoolAttr('open', !this.getBoolAttr('open')); }
|
|
3846
|
+
|
|
3847
|
+
get open() { return this.getBoolAttr('open'); }
|
|
3848
|
+
set open(v) { this.setBoolAttr('open', v); }
|
|
3849
|
+
get title() { return this._titleText ?? ''; }
|
|
3850
|
+
set title(v) { this._titleText = v == null ? '' : String(v); if (this._initialized) this._syncTitle(); }
|
|
3851
|
+
}
|
|
3852
|
+
|
|
3853
|
+
customElements.define('nk-sheet', NkSheet);
|
|
3854
|
+
|
|
3855
|
+
// <nk-steps label="Connect your own model" current="2"
|
|
3856
|
+
// steps="Choose a provider, Enter the API key, Test the connection"></nk-steps>
|
|
3857
|
+
// steps.steps = [{ label: 'Choose a provider', desc: 'Anthropic' }, 'Enter the API key', …];
|
|
3858
|
+
// → <ol class="nk-steps" aria-label="…">
|
|
3859
|
+
// <li class="nk-step done"><span class="st-mark">✓</span><span>Choose a provider<span class="st-desc">Anthropic</span></span></li>
|
|
3860
|
+
// <li class="nk-step current" aria-current="step"><span class="st-mark">2</span><span>Enter the API key</span></li>
|
|
3861
|
+
// <li class="nk-step"><span class="st-mark">3</span><span>Test the connection</span></li></ol>
|
|
3862
|
+
// A setup in a few steps (NotionKit 1.7.0). `current` counts from 1; the
|
|
3863
|
+
// steps before it are done, one past the last marks all of them done. The
|
|
3864
|
+
// `steps` attribute is a comma-separated list; the property also takes
|
|
3865
|
+
// { label, desc } objects for a line under the label.
|
|
3866
|
+
class NkSteps extends NkElement {
|
|
3867
|
+
static get observedAttributes() { return ['steps', 'current', 'label']; }
|
|
3868
|
+
|
|
3869
|
+
render() {
|
|
3870
|
+
this._list = this.createElement('ol', ['nk-steps']);
|
|
3871
|
+
this._wrapper.appendChild(this._list);
|
|
3872
|
+
this._sync();
|
|
3873
|
+
}
|
|
3874
|
+
|
|
3875
|
+
_items() {
|
|
3876
|
+
if (this._steps) return this._steps;
|
|
3877
|
+
return (this.getAttribute('steps') || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
3878
|
+
}
|
|
3879
|
+
|
|
3880
|
+
_sync() {
|
|
3881
|
+
const label = this.getAttribute('label');
|
|
3882
|
+
if (label) this._list.setAttribute('aria-label', label); else this._list.removeAttribute('aria-label');
|
|
3883
|
+
const current = this.current;
|
|
3884
|
+
this._list.replaceChildren(...this._items().map((step, i) => {
|
|
3885
|
+
const n = i + 1, { label: text, desc } = typeof step === 'object' && step ? step : { label: String(step) };
|
|
3886
|
+
const li = this.createElement('li', ['nk-step']);
|
|
3887
|
+
li.classList.toggle('done', n < current);
|
|
3888
|
+
li.classList.toggle('current', n === current);
|
|
3889
|
+
if (n === current) li.setAttribute('aria-current', 'step');
|
|
3890
|
+
const mark = this.createElement('span', ['st-mark'], { 'aria-hidden': 'true' });
|
|
3891
|
+
mark.textContent = n < current ? '✓' : String(n);
|
|
3892
|
+
const body = document.createElement('span');
|
|
3893
|
+
body.textContent = text ?? '';
|
|
3894
|
+
if (desc) { const d = this.createElement('span', ['st-desc']); d.textContent = desc; body.appendChild(d); }
|
|
3895
|
+
li.append(mark, body);
|
|
3896
|
+
return li;
|
|
3897
|
+
}));
|
|
3898
|
+
}
|
|
3899
|
+
|
|
3900
|
+
onAttributeChanged() { this._sync(); }
|
|
3901
|
+
|
|
3902
|
+
get steps() { return this._items(); }
|
|
3903
|
+
set steps(v) { this._steps = Array.isArray(v) ? v : null; if (this._list) this._sync(); }
|
|
3904
|
+
get current() { const n = parseInt(this.getAttribute('current'), 10); return Number.isFinite(n) ? n : 1; }
|
|
3905
|
+
set current(v) { this.setAttribute('current', String(v)); }
|
|
3906
|
+
/** Moves on to the next step; returns the new current step. */
|
|
3907
|
+
next() { this.current = Math.min(this.current + 1, this._items().length + 1); return this.current; }
|
|
3908
|
+
}
|
|
3909
|
+
|
|
3910
|
+
customElements.define('nk-steps', NkSteps);
|
|
3911
|
+
|
|
3512
3912
|
// <nk-modal id="settings">
|
|
3513
3913
|
// <nk-settings-user slot="user" name="…" mail="…"></nk-settings-user>
|
|
3514
3914
|
// <nk-settings-pane name="profile" group="Account" icon="👤" label="My profile" title="My profile" active>…</nk-settings-pane>
|
|
@@ -3971,12 +4371,78 @@ customElements.define('nk-cmdk', NkCmdk);
|
|
|
3971
4371
|
// </nk-menu>
|
|
3972
4372
|
// → <div class="nk-pop nk-menu" role="menu">…</div>
|
|
3973
4373
|
// ↑↓ move between items, Enter selects, nk-select bubbles from the item.
|
|
4374
|
+
//
|
|
4375
|
+
// <nk-menu floating sheet> is a menu over the page (NotionKit 1.7.0): it
|
|
4376
|
+
// fades in like the palette when `open` is set and is a bottom sheet on a
|
|
4377
|
+
// phone. The host becomes the fixed box you position – show(anchor) puts it
|
|
4378
|
+
// under the anchor, right edges aligned (align="start": left edges). A tap
|
|
4379
|
+
// outside closes it and reaches nothing else; Escape and a chosen item
|
|
4380
|
+
// close it too, a switch row does not. Opened from the keyboard, focus moves
|
|
4381
|
+
// to the first item; closing returns it to where it was.
|
|
4382
|
+
const floatSheet = new CSSStyleSheet();
|
|
4383
|
+
floatSheet.replaceSync(`:host([floating]) { display: block; position: fixed; z-index: 60; pointer-events: none; }`);
|
|
4384
|
+
|
|
4385
|
+
/** The border box of an element, or of the first descendant with one (display: contents hosts). */
|
|
4386
|
+
function boxOf(el) {
|
|
4387
|
+
if (el.getClientRects().length) return el.getBoundingClientRect();
|
|
4388
|
+
for (const child of [...(el.shadowRoot?.children ?? []), ...el.children]) {
|
|
4389
|
+
const r = boxOf(child);
|
|
4390
|
+
if (r.width || r.height) return r;
|
|
4391
|
+
}
|
|
4392
|
+
return el.getBoundingClientRect();
|
|
4393
|
+
}
|
|
4394
|
+
|
|
3974
4395
|
class NkMenu extends NkElement {
|
|
4396
|
+
static get hostStyles() { return floatSheet; }
|
|
4397
|
+
static get observedAttributes() { return ['floating', 'sheet', 'open', 'align']; }
|
|
4398
|
+
|
|
3975
4399
|
render() {
|
|
3976
4400
|
this._box = this.createElement('div', ['nk-pop', 'nk-menu'], { role: 'menu' });
|
|
3977
4401
|
this._box.appendChild(document.createElement('slot'));
|
|
3978
4402
|
this._wrapper.appendChild(this._box);
|
|
4403
|
+
this._syncMode();
|
|
4404
|
+
}
|
|
4405
|
+
|
|
4406
|
+
_syncMode() {
|
|
4407
|
+
this._box.classList.toggle('floating', this.getBoolAttr('floating'));
|
|
4408
|
+
this._box.classList.toggle('sheet', this.getBoolAttr('sheet'));
|
|
4409
|
+
this._box.classList.toggle('open', this.getBoolAttr('open'));
|
|
4410
|
+
}
|
|
4411
|
+
|
|
4412
|
+
onAttributeChanged(name) {
|
|
4413
|
+
this._syncMode();
|
|
4414
|
+
if (name !== 'open') return;
|
|
4415
|
+
const open = this.getBoolAttr('open');
|
|
4416
|
+
// aria-expanded belongs on the control itself, inside a host such as <nk-btn>.
|
|
4417
|
+
if (this._anchor) (this._anchor.shadowRoot?.querySelector('button, a[href]') ?? this._anchor).setAttribute('aria-expanded', String(open));
|
|
4418
|
+
if (open) {
|
|
4419
|
+
this._returnFocus = deepActiveElement();
|
|
4420
|
+
if (this._returnFocus?.matches(':focus-visible')) requestAnimationFrame(() => this.focusFirst());
|
|
4421
|
+
document.addEventListener('click', this._onOutside, true);
|
|
4422
|
+
} else {
|
|
4423
|
+
document.removeEventListener('click', this._onOutside, true);
|
|
4424
|
+
const back = this._returnFocus;
|
|
4425
|
+
this._returnFocus = null;
|
|
4426
|
+
if (back?.isConnected && this.contains(document.activeElement)) back.focus({ preventScroll: true });
|
|
4427
|
+
}
|
|
4428
|
+
this.emit('nk-toggle', { open });
|
|
4429
|
+
}
|
|
4430
|
+
|
|
4431
|
+
/** Opens under `anchor` (any element, display: contents hosts included). */
|
|
4432
|
+
show(anchor) {
|
|
4433
|
+
if (anchor) {
|
|
4434
|
+
this._anchor = anchor;
|
|
4435
|
+
const r = boxOf(anchor);
|
|
4436
|
+
this.style.top = `${r.bottom + 6}px`;
|
|
4437
|
+
if (this.getAttribute('align') === 'start') { this.style.left = `${r.left}px`; this.style.right = ''; }
|
|
4438
|
+
else { this.style.right = `${Math.max(8, innerWidth - r.right)}px`; this.style.left = ''; }
|
|
4439
|
+
}
|
|
4440
|
+
this.setBoolAttr('open', true);
|
|
3979
4441
|
}
|
|
4442
|
+
close() { this.setBoolAttr('open', false); }
|
|
4443
|
+
toggle(anchor) { this.getBoolAttr('open') ? this.close() : this.show(anchor); }
|
|
4444
|
+
get open() { return this.getBoolAttr('open'); }
|
|
4445
|
+
set open(v) { this.setBoolAttr('open', v); }
|
|
3980
4446
|
|
|
3981
4447
|
get items() { return [...this.querySelectorAll(':scope > nk-menu-item')].filter(i => i.selectable); }
|
|
3982
4448
|
|
|
@@ -3995,9 +4461,27 @@ class NkMenu extends NkElement {
|
|
|
3995
4461
|
}
|
|
3996
4462
|
};
|
|
3997
4463
|
this.addEventListener('keydown', this._onKey);
|
|
4464
|
+
// Floating: outside taps close and go nowhere else; Escape and a chosen item close.
|
|
4465
|
+
this._onOutside = (e) => {
|
|
4466
|
+
const path = e.composedPath();
|
|
4467
|
+
if (path.includes(this) || (this._anchor && path.includes(this._anchor))) return;
|
|
4468
|
+
e.preventDefault(); e.stopPropagation();
|
|
4469
|
+
this.close();
|
|
4470
|
+
};
|
|
4471
|
+
// Captured, so a menu inside a modal or sheet closes before they do.
|
|
4472
|
+
this._onEscape = (e) => { if (e.key === 'Escape' && this.getBoolAttr('floating') && this.getBoolAttr('open')) { e.stopPropagation(); this.close(); } };
|
|
4473
|
+
this._onSelect = () => { if (this.getBoolAttr('floating')) this.close(); };
|
|
4474
|
+
document.addEventListener('keydown', this._onEscape, true);
|
|
4475
|
+
this.addEventListener('nk-select', this._onSelect);
|
|
4476
|
+
if (this.getBoolAttr('open')) document.addEventListener('click', this._onOutside, true);
|
|
3998
4477
|
}
|
|
3999
4478
|
|
|
4000
|
-
teardownEvents() {
|
|
4479
|
+
teardownEvents() {
|
|
4480
|
+
this.removeEventListener('keydown', this._onKey);
|
|
4481
|
+
document.removeEventListener('keydown', this._onEscape, true);
|
|
4482
|
+
this.removeEventListener('nk-select', this._onSelect);
|
|
4483
|
+
document.removeEventListener('click', this._onOutside, true);
|
|
4484
|
+
}
|
|
4001
4485
|
|
|
4002
4486
|
/** Focuses the first item (called by a popover when it opens). */
|
|
4003
4487
|
focusFirst() { this.items[0]?.focus(); }
|
|
@@ -4008,9 +4492,15 @@ customElements.define('nk-menu', NkMenu);
|
|
|
4008
4492
|
// <nk-menu-item icon="✏️" shortcut="⌘E" value="rename">Rename</nk-menu-item>
|
|
4009
4493
|
// <nk-menu-item type="separator"></nk-menu-item> <nk-menu-item type="label">Danger</nk-menu-item>
|
|
4010
4494
|
// <nk-menu-item icon="🗑️" danger value="delete">Delete</nk-menu-item>
|
|
4495
|
+
// <nk-menu-item type="switch" icon="🔡" value="small" checked>Small text</nk-menu-item>
|
|
4496
|
+
// <nk-menu-item type="check" icon="◉" value="open" checked>Status: Open</nk-menu-item>
|
|
4011
4497
|
// → <div class="nk-menu-item danger"><span class="m-icon">🗑️</span>Delete<span class="m-shortcut">…</span></div>
|
|
4498
|
+
// A switch item carries a .nk-switch on the right, as "Small text" does in
|
|
4499
|
+
// Notion's page menu; a check item a ✓ where the shortcut stands, as in a
|
|
4500
|
+
// filter menu. A click on either flips `checked` and fires nk-change
|
|
4501
|
+
// { value, checked } instead of nk-select, so the menu around it stays open.
|
|
4012
4502
|
class NkMenuItem extends NkElement {
|
|
4013
|
-
static get observedAttributes() { return ['icon', 'shortcut', 'danger', 'value', 'type', 'disabled']; }
|
|
4503
|
+
static get observedAttributes() { return ['icon', 'shortcut', 'danger', 'value', 'type', 'disabled', 'checked']; }
|
|
4014
4504
|
|
|
4015
4505
|
render() { this._build(); }
|
|
4016
4506
|
|
|
@@ -4023,12 +4513,16 @@ class NkMenuItem extends NkElement {
|
|
|
4023
4513
|
el = this.createElement('div', ['nk-menu-label']);
|
|
4024
4514
|
el.appendChild(document.createElement('slot'));
|
|
4025
4515
|
} else {
|
|
4026
|
-
|
|
4516
|
+
const isSwitch = type === 'switch';
|
|
4517
|
+
this._check = type === 'check';
|
|
4518
|
+
el = this.createElement('div', ['nk-menu-item'], { role: isSwitch || this._check ? 'menuitemcheckbox' : 'menuitem', tabindex: '-1' });
|
|
4027
4519
|
this._icon = this.createElement('span', ['m-icon']);
|
|
4028
4520
|
const iconSlot = this.createElement('slot', [], { name: 'icon' });
|
|
4029
4521
|
iconSlot.appendChild(this._icon);
|
|
4030
4522
|
this._shortcut = this.createElement('span', ['m-shortcut']);
|
|
4031
4523
|
el.append(iconSlot, document.createElement('slot'), this._shortcut);
|
|
4524
|
+
this._switch = isSwitch ? this.createElement('span', ['nk-switch'], { 'aria-hidden': 'true' }) : null;
|
|
4525
|
+
if (this._switch) el.appendChild(this._switch);
|
|
4032
4526
|
}
|
|
4033
4527
|
if (this._el) { this._el.removeEventListener('click', this._onClick); this._el.replaceWith(el); } else this._wrapper.appendChild(el);
|
|
4034
4528
|
this._el = el;
|
|
@@ -4046,6 +4540,12 @@ class NkMenuItem extends NkElement {
|
|
|
4046
4540
|
this._shortcut.style.display = sc ? '' : 'none';
|
|
4047
4541
|
this._el.classList.toggle('danger', this.getBoolAttr('danger'));
|
|
4048
4542
|
this._el.setAttribute('aria-disabled', this.getBoolAttr('disabled') ? 'true' : 'false');
|
|
4543
|
+
if (this._switch || this._check) {
|
|
4544
|
+
const on = this.getBoolAttr('checked') ? 'true' : 'false';
|
|
4545
|
+
this._el.setAttribute('aria-checked', on);
|
|
4546
|
+
if (this._switch) this._switch.setAttribute('aria-checked', on);
|
|
4547
|
+
if (this._check) { this._shortcut.textContent = on === 'true' ? '✓' : ''; this._shortcut.style.display = ''; }
|
|
4548
|
+
}
|
|
4049
4549
|
}
|
|
4050
4550
|
|
|
4051
4551
|
setupEvents() {
|
|
@@ -4057,6 +4557,11 @@ class NkMenuItem extends NkElement {
|
|
|
4057
4557
|
|
|
4058
4558
|
select() {
|
|
4059
4559
|
if (!this._el.classList.contains('nk-menu-item') || this.getBoolAttr('disabled')) return;
|
|
4560
|
+
if (this._switch || this._check) {
|
|
4561
|
+
this.checked = !this.checked;
|
|
4562
|
+
this.emit('nk-change', { value: this.value, checked: this.checked, item: this });
|
|
4563
|
+
return;
|
|
4564
|
+
}
|
|
4060
4565
|
this.emit('nk-select', { value: this.value, label: this.textContent.trim(), item: this });
|
|
4061
4566
|
}
|
|
4062
4567
|
|
|
@@ -4064,6 +4569,8 @@ class NkMenuItem extends NkElement {
|
|
|
4064
4569
|
focus(o) { this._el?.focus(o); }
|
|
4065
4570
|
get selectable() { return this._el?.classList.contains('nk-menu-item') && !this.getBoolAttr('disabled'); }
|
|
4066
4571
|
|
|
4572
|
+
get checked() { return this.getBoolAttr('checked'); }
|
|
4573
|
+
set checked(v) { this.setBoolAttr('checked', v); }
|
|
4067
4574
|
get value() { return this.getAttribute('value') ?? this.textContent.trim(); }
|
|
4068
4575
|
set value(v) { this.setAttribute('value', v); }
|
|
4069
4576
|
}
|
|
@@ -4338,16 +4845,24 @@ customElements.define('nk-toast', NkToast);
|
|
|
4338
4845
|
// </nk-database>
|
|
4339
4846
|
// db.columns = [{ key: 'name', label: 'Name', type: 'text', icon: '📄', title: true }, { key: 'status', type: 'select', options: [...] }, …];
|
|
4340
4847
|
// db.rows = [{ id: 1, icon: '🧭', name: '…', status: 'done', … }];
|
|
4341
|
-
//
|
|
4848
|
+
// <nk-btn slot="tools" variant="tool">Filter</nk-btn> … sit right of the tabs,
|
|
4849
|
+
// <nk-filter-bar slot="filters"> under them (NotionKit 1.7.0's toolbar).
|
|
4850
|
+
// → <div class="nk-database"><div class="nk-db-toolbar"><div class="nk-db-tabs">…</div>
|
|
4851
|
+
// <div class="tools">…</div></div>…filters…active view…</div>
|
|
4342
4852
|
// The tabs come from the child views; data is pushed into every view.
|
|
4343
4853
|
class NkDatabase extends NkElement {
|
|
4344
4854
|
static get observedAttributes() { return ['view', 'add-view']; }
|
|
4345
4855
|
|
|
4346
4856
|
render() {
|
|
4347
4857
|
this._box = this.createElement('div', ['nk-database']);
|
|
4858
|
+
this._toolbar = this.createElement('div', ['nk-db-toolbar']);
|
|
4348
4859
|
this._tabs = this.createElement('div', ['nk-db-tabs'], { role: 'tablist' });
|
|
4860
|
+
const tools = this.createElement('div', ['tools']);
|
|
4861
|
+
this._toolsSlot = this.createElement('slot', [], { name: 'tools' });
|
|
4862
|
+
tools.appendChild(this._toolsSlot);
|
|
4863
|
+
this._toolbar.append(this._tabs, tools);
|
|
4349
4864
|
this._slot = document.createElement('slot');
|
|
4350
|
-
this._box.append(this.
|
|
4865
|
+
this._box.append(this._toolbar, this.createElement('slot', [], { name: 'filters' }), this._slot);
|
|
4351
4866
|
this._wrapper.appendChild(this._box);
|
|
4352
4867
|
this._columns = []; this._rows = [];
|
|
4353
4868
|
this._sync();
|
|
@@ -4375,12 +4890,11 @@ class NkDatabase extends NkElement {
|
|
|
4375
4890
|
v.setData?.(this._columns, this._rows);
|
|
4376
4891
|
}
|
|
4377
4892
|
if (this.getBoolAttr('add-view')) {
|
|
4378
|
-
const add = this.createElement('span', ['nk-db-tab'], { role: 'button', 'data-add': '', tabindex: '0' });
|
|
4379
|
-
add.style.color = 'var(--nk-text-tertiary)';
|
|
4893
|
+
const add = this.createElement('span', ['nk-db-tab', 'add'], { role: 'button', 'data-add': '', tabindex: '0' });
|
|
4380
4894
|
add.textContent = '+';
|
|
4381
4895
|
this._tabs.appendChild(add);
|
|
4382
4896
|
}
|
|
4383
|
-
this.
|
|
4897
|
+
this._toolbar.hidden = !views.length && !this._toolsSlot.assignedElements().length;
|
|
4384
4898
|
this._current = current;
|
|
4385
4899
|
}
|
|
4386
4900
|
|
|
@@ -4402,6 +4916,7 @@ class NkDatabase extends NkElement {
|
|
|
4402
4916
|
this._tabs.addEventListener('click', this._onClick);
|
|
4403
4917
|
this._tabs.addEventListener('keydown', this._onKey);
|
|
4404
4918
|
this._slot.addEventListener('slotchange', this._onSlot);
|
|
4919
|
+
this._toolsSlot.addEventListener('slotchange', this._onSlot);
|
|
4405
4920
|
this._sync();
|
|
4406
4921
|
}
|
|
4407
4922
|
|
|
@@ -4409,6 +4924,7 @@ class NkDatabase extends NkElement {
|
|
|
4409
4924
|
this._tabs?.removeEventListener('click', this._onClick);
|
|
4410
4925
|
this._tabs?.removeEventListener('keydown', this._onKey);
|
|
4411
4926
|
this._slot?.removeEventListener('slotchange', this._onSlot);
|
|
4927
|
+
this._toolsSlot?.removeEventListener('slotchange', this._onSlot);
|
|
4412
4928
|
}
|
|
4413
4929
|
|
|
4414
4930
|
onAttributeChanged(name) {
|
|
@@ -4436,6 +4952,7 @@ customElements.define('nk-database', NkDatabase);
|
|
|
4436
4952
|
//
|
|
4437
4953
|
// column: { key, label, type, icon, options: [{ value, label, color }], title }
|
|
4438
4954
|
// types: text | select | multi-select | date | person | checkbox | url | number | progress
|
|
4955
|
+
|
|
4439
4956
|
const el = (tag, cls, text) => { const n = document.createElement(tag); if (cls) n.className = cls; if (text != null) n.textContent = text; return n; };
|
|
4440
4957
|
const COLORS = ['gray', 'brown', 'orange', 'yellow', 'green', 'blue', 'purple', 'pink', 'red'];
|
|
4441
4958
|
|
|
@@ -4469,14 +4986,16 @@ function renderPropertyCell(column, value, row = {}) {
|
|
|
4469
4986
|
case 'person': {
|
|
4470
4987
|
const cell = el('span', 'person-cell');
|
|
4471
4988
|
const p = typeof value === 'string' ? { name: value } : value;
|
|
4472
|
-
|
|
4473
|
-
avatar
|
|
4989
|
+
// color: one of Notion's nine names, or any CSS background; none – the avatar gradient.
|
|
4990
|
+
const avatar = el('span', 'nk-avatar small', p.initials || p.avatar || initialsOf(p.name));
|
|
4991
|
+
paintAvatar(avatar, p.color);
|
|
4474
4992
|
cell.append(avatar, document.createTextNode(' ' + (p.name || '')));
|
|
4475
4993
|
return cell;
|
|
4476
4994
|
}
|
|
4477
4995
|
case 'checkbox': return checkbox(column, !!value, row);
|
|
4478
4996
|
case 'url': { const a = el('a', null, String(value).replace(/^https?:\/\//, '')); a.href = String(value); a.target = '_blank'; a.rel = 'noopener'; return a; }
|
|
4479
|
-
|
|
4997
|
+
// column.locale / column.format: Intl.NumberFormat locale and options, e.g. { minimumFractionDigits: 1 }.
|
|
4998
|
+
case 'number': return el('span', null, typeof value === 'number' ? value.toLocaleString(column.locale, column.format) : String(value));
|
|
4480
4999
|
case 'progress': return progress(Number(value) || 0);
|
|
4481
5000
|
default: {
|
|
4482
5001
|
if (column.title) {
|
|
@@ -4569,6 +5088,8 @@ class NkTableView extends NkElement {
|
|
|
4569
5088
|
const r = this.createElement('tr', [], { 'data-id': row.id ?? '' });
|
|
4570
5089
|
for (const col of this._columns) {
|
|
4571
5090
|
const td = document.createElement('td');
|
|
5091
|
+
// Numbers right-aligned in figures of equal width, as Notion sets them.
|
|
5092
|
+
if (col.type === 'number') td.className = 'num';
|
|
4572
5093
|
td.appendChild(renderPropertyCell(col, row[col.key], row));
|
|
4573
5094
|
r.appendChild(td);
|
|
4574
5095
|
}
|
|
@@ -4752,61 +5273,167 @@ class NkBoardView extends NkElement {
|
|
|
4752
5273
|
|
|
4753
5274
|
customElements.define('nk-board-view', NkBoardView);
|
|
4754
5275
|
|
|
4755
|
-
// <nk-
|
|
4756
|
-
//
|
|
4757
|
-
//
|
|
4758
|
-
//
|
|
4759
|
-
//
|
|
5276
|
+
// <nk-list-view name="list" label="☰ List" meta-keys="due,status" new-row></nk-list-view>
|
|
5277
|
+
// The third database view: one line per row – icon and title, the `meta-keys`
|
|
5278
|
+
// on the right (default: the select and date columns, in column order). Dates
|
|
5279
|
+
// and text stand as text, selects as tags, a person as avatar and name.
|
|
5280
|
+
// Standalone: view.columns = […]; view.rows = […]. Inside <nk-database> the
|
|
5281
|
+
// database pushes the data. Rows fire nk-select, the add row nk-action
|
|
5282
|
+
// { action: 'new-row' }.
|
|
5283
|
+
// → <div class="nk-list"><div class="nk-list-item"><span class="l-icon">…</span><span class="l-title">…</span><span class="l-meta">…</span></div>…</div>
|
|
5284
|
+
class NkListView extends NkElement {
|
|
5285
|
+
static get observedAttributes() { return ['name', 'label', 'badge', 'count', 'title-key', 'meta-keys', 'new-row', 'new-row-label']; }
|
|
5286
|
+
|
|
5287
|
+
render() {
|
|
5288
|
+
this._box = document.createElement('div');
|
|
5289
|
+
this._list = this.createElement('div', ['nk-list'], { role: 'list' });
|
|
5290
|
+
this._newRow = this.createElement('div', ['nk-new-row'], { role: 'button', tabindex: '0' });
|
|
5291
|
+
this._box.append(this._list, this._newRow);
|
|
5292
|
+
this._wrapper.appendChild(this._box);
|
|
5293
|
+
this._columns ??= []; this._rows ??= [];
|
|
5294
|
+
this._render();
|
|
5295
|
+
this.closest('nk-database')?.requestSync?.();
|
|
5296
|
+
}
|
|
5297
|
+
|
|
5298
|
+
_titleColumn() {
|
|
5299
|
+
const key = this.getAttribute('title-key');
|
|
5300
|
+
return this._columns.find(c => c.key === key) || this._columns.find(c => c.title) || this._columns[0] || null;
|
|
5301
|
+
}
|
|
5302
|
+
_metaColumns() {
|
|
5303
|
+
const keys = (this.getAttribute('meta-keys') || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
5304
|
+
if (keys.length) return keys.map(k => this._columns.find(c => c.key === k)).filter(Boolean);
|
|
5305
|
+
return this._columns.filter(c => c.type === 'select' || c.type === 'date');
|
|
5306
|
+
}
|
|
5307
|
+
|
|
5308
|
+
_render() {
|
|
5309
|
+
if (!this._list) return;
|
|
5310
|
+
const title = this._titleColumn(), meta = this._metaColumns();
|
|
5311
|
+
this._list.replaceChildren();
|
|
5312
|
+
for (const row of this._rows) {
|
|
5313
|
+
const item = this.createElement('div', ['nk-list-item'], { role: 'listitem', tabindex: '0', 'data-id': row.id ?? '' });
|
|
5314
|
+
const icon = this.createElement('span', ['l-icon']);
|
|
5315
|
+
icon.textContent = row.icon || '';
|
|
5316
|
+
if (!row.icon) icon.style.display = 'none';
|
|
5317
|
+
const t = this.createElement('span', ['l-title']);
|
|
5318
|
+
t.textContent = title ? String(row[title.key] ?? '') : '';
|
|
5319
|
+
const m = this.createElement('span', ['l-meta']);
|
|
5320
|
+
for (const c of meta) {
|
|
5321
|
+
const v = row[c.key];
|
|
5322
|
+
if (v === undefined || v === null || v === '') continue;
|
|
5323
|
+
m.appendChild(c.type === 'date' || c.type === 'text' || !c.type ? document.createTextNode(String(v)) : renderPropertyCell(c, v, row));
|
|
5324
|
+
}
|
|
5325
|
+
item.append(icon, t, m);
|
|
5326
|
+
this._list.appendChild(item);
|
|
5327
|
+
}
|
|
5328
|
+
this._newRow.textContent = this.getAttribute('new-row-label') || '+ New page';
|
|
5329
|
+
this._newRow.style.display = this.getBoolAttr('new-row') ? '' : 'none';
|
|
5330
|
+
}
|
|
5331
|
+
|
|
5332
|
+
setupEvents() {
|
|
5333
|
+
this._onClick = (e) => {
|
|
5334
|
+
if (this._newRow.contains(e.target)) { this.emit('nk-action', { action: 'new-row' }); return; }
|
|
5335
|
+
const item = e.target.closest('.nk-list-item');
|
|
5336
|
+
if (item) { const row = this._rowById(item.dataset.id); this.emit('nk-select', { row, id: row?.id, value: row?.id }); }
|
|
5337
|
+
};
|
|
5338
|
+
this._onKey = (e) => {
|
|
5339
|
+
if (e.key !== 'Enter' && e.key !== ' ') return;
|
|
5340
|
+
if (e.target === this._newRow || e.target.classList?.contains('nk-list-item')) { e.preventDefault(); e.target.click(); }
|
|
5341
|
+
};
|
|
5342
|
+
this._box.addEventListener('click', this._onClick);
|
|
5343
|
+
this._box.addEventListener('keydown', this._onKey);
|
|
5344
|
+
}
|
|
5345
|
+
|
|
5346
|
+
teardownEvents() {
|
|
5347
|
+
this._box?.removeEventListener('click', this._onClick);
|
|
5348
|
+
this._box?.removeEventListener('keydown', this._onKey);
|
|
5349
|
+
}
|
|
5350
|
+
|
|
5351
|
+
_rowById(id) { return this._rows.find(r => String(r.id) === String(id)); }
|
|
5352
|
+
onAttributeChanged() { this._render(); }
|
|
5353
|
+
|
|
5354
|
+
get name() { return this.getAttribute('name') || 'list'; }
|
|
5355
|
+
get columns() { return this._columns; }
|
|
5356
|
+
set columns(v) { this._columns = Array.isArray(v) ? v : []; this._render(); }
|
|
5357
|
+
get rows() { return this._rows; }
|
|
5358
|
+
set rows(v) { this._rows = Array.isArray(v) ? v : []; this._render(); }
|
|
5359
|
+
set data({ columns, rows }) { this.setData(columns, rows); }
|
|
5360
|
+
setData(columns, rows) { this._columns = columns || []; this._rows = rows || []; this._render(); }
|
|
5361
|
+
refresh() { this._render(); }
|
|
5362
|
+
}
|
|
5363
|
+
|
|
5364
|
+
customElements.define('nk-list-view', NkListView);
|
|
5365
|
+
|
|
5366
|
+
// <nk-filter-bar add no-filter no-sort></nk-filter-bar>
|
|
5367
|
+
// bar.filters = [{ key: 'status', value: 'done', op: 'is-not', label: 'Status: Open' }];
|
|
5368
|
+
// The filters in effect as NotionKit's filter pills (1.7.0), no inline style:
|
|
5369
|
+
// → <div class="nk-filter-row">[Filter][Sort]
|
|
5370
|
+
// <span class="nk-filter-pill active"><button>Status: Open</button><button class="fp-remove">×</button></span>…
|
|
5371
|
+
// <button class="nk-filter-pill add">+ Filter</button> …slot… [search]</div>
|
|
5372
|
+
// Filter and Sort are .nk-db-tool buttons (hide them with no-filter / no-sort
|
|
5373
|
+
// when the database toolbar carries its own); they fire nk-action. A pill's
|
|
5374
|
+
// label fires nk-action { action: 'edit', index, filter }, the add pill
|
|
5375
|
+
// nk-action { action: 'add' } – each with the clicked button as `anchor`, to
|
|
5376
|
+
// open a menu under it. × removes the filter; every change to filters or
|
|
5377
|
+
// search fires nk-change { filters, search }. In slot="filters" of
|
|
5378
|
+
// <nk-database> the row sits right under the view tabs. The texts are
|
|
5379
|
+
// attributes, for other languages: filter-label, sort-label, add-label,
|
|
5380
|
+
// remove-label (the × reads "<remove-label>: <pill>") and placeholder.
|
|
4760
5381
|
class NkFilterBar extends NkElement {
|
|
4761
|
-
static get observedAttributes() { return ['search', 'placeholder', 'no-filter', 'no-sort', 'value']; }
|
|
5382
|
+
static get observedAttributes() { return ['search', 'placeholder', 'no-filter', 'no-sort', 'value', 'add', 'add-label', 'filter-label', 'sort-label', 'remove-label']; }
|
|
4762
5383
|
|
|
4763
5384
|
render() {
|
|
4764
|
-
this.
|
|
4765
|
-
this.
|
|
4766
|
-
this.
|
|
4767
|
-
this.
|
|
4768
|
-
this.
|
|
4769
|
-
this._sortBtn.textContent = '↕ Sort';
|
|
4770
|
-
this._chips = document.createElement('span');
|
|
4771
|
-
this._chips.style.cssText = 'display:inline-flex;gap:4px;flex-wrap:wrap';
|
|
5385
|
+
this._row = this.createElement('div', ['nk-filter-row']);
|
|
5386
|
+
this._filterBtn = this.createElement('button', ['nk-db-tool'], { type: 'button', 'data-action': 'filter' });
|
|
5387
|
+
this._sortBtn = this.createElement('button', ['nk-db-tool'], { type: 'button', 'data-action': 'sort' });
|
|
5388
|
+
this._pillStart = document.createComment('pills');
|
|
5389
|
+
this._addBtn = this.createElement('button', ['nk-filter-pill', 'add'], { type: 'button', 'data-action': 'add' });
|
|
4772
5390
|
this._input = this.createElement('input', ['nk-input'], { type: 'search', autocomplete: 'off' });
|
|
4773
|
-
this.
|
|
4774
|
-
this.
|
|
4775
|
-
this._wrapper.appendChild(this._bar);
|
|
5391
|
+
this._row.append(this._filterBtn, this._sortBtn, this._pillStart, this._addBtn, document.createElement('slot'), this._input);
|
|
5392
|
+
this._wrapper.appendChild(this._row);
|
|
4776
5393
|
this._filters = [];
|
|
4777
5394
|
this._sync();
|
|
4778
5395
|
}
|
|
4779
5396
|
|
|
4780
5397
|
_sync() {
|
|
4781
|
-
this._filterBtn.
|
|
4782
|
-
this.
|
|
4783
|
-
this.
|
|
5398
|
+
this._filterBtn.textContent = this.getAttribute('filter-label') || 'Filter';
|
|
5399
|
+
this._filterBtn.hidden = this.getBoolAttr('no-filter');
|
|
5400
|
+
this._filterBtn.classList.toggle('active', this._filters.length > 0);
|
|
5401
|
+
this._sortBtn.textContent = this.getAttribute('sort-label') || 'Sort';
|
|
5402
|
+
this._sortBtn.hidden = this.getBoolAttr('no-sort');
|
|
5403
|
+
this._addBtn.textContent = this.getAttribute('add-label') || '+ Filter';
|
|
5404
|
+
this._addBtn.hidden = !this.getBoolAttr('add');
|
|
5405
|
+
this._input.hidden = !this.getBoolAttr('search');
|
|
4784
5406
|
this._input.placeholder = this.getAttribute('placeholder') || 'Search …';
|
|
4785
5407
|
if (this.hasAttribute('value') && this._input.value !== this.getAttribute('value')) this._input.value = this.getAttribute('value');
|
|
4786
|
-
this.
|
|
4787
|
-
this.
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4792
|
-
this.
|
|
4793
|
-
|
|
5408
|
+
for (const old of this._row.querySelectorAll('[data-pill]')) old.remove();
|
|
5409
|
+
const removeLabel = this.getAttribute('remove-label') || 'Remove filter';
|
|
5410
|
+
this._pillStart.after(...this._filters.map((f, i) => {
|
|
5411
|
+
const pill = this.createElement('span', ['nk-filter-pill', 'active'], { 'data-pill': i });
|
|
5412
|
+
const label = this.createElement('button', [], { type: 'button', 'data-edit': i });
|
|
5413
|
+
label.textContent = f.label ?? `${f.key}: ${f.value}`;
|
|
5414
|
+
const remove = this.createElement('button', ['fp-remove'], { type: 'button', 'data-remove': i, 'aria-label': `${removeLabel}: ${label.textContent}` });
|
|
5415
|
+
remove.textContent = '×';
|
|
5416
|
+
pill.append(label, remove);
|
|
5417
|
+
return pill;
|
|
5418
|
+
}));
|
|
4794
5419
|
}
|
|
4795
5420
|
|
|
4796
5421
|
setupEvents() {
|
|
4797
5422
|
this._onClick = (e) => {
|
|
5423
|
+
const remove = e.target.closest('[data-remove]');
|
|
5424
|
+
if (remove) { this._filters.splice(Number(remove.dataset.remove), 1); this._sync(); this._emitChange(); return; }
|
|
5425
|
+
const edit = e.target.closest('[data-edit]');
|
|
5426
|
+
if (edit) { const index = Number(edit.dataset.edit); this.emit('nk-action', { action: 'edit', index, filter: this._filters[index], anchor: edit }); return; }
|
|
4798
5427
|
const btn = e.target.closest('[data-action]');
|
|
4799
|
-
if (btn)
|
|
4800
|
-
const chip = e.target.closest('[data-index]');
|
|
4801
|
-
if (chip) { this._filters.splice(Number(chip.dataset.index), 1); this._sync(); this._emitChange(); }
|
|
5428
|
+
if (btn) this.emit('nk-action', { action: btn.dataset.action, anchor: btn });
|
|
4802
5429
|
};
|
|
4803
5430
|
this._onInput = () => { clearTimeout(this._debounce); this._debounce = setTimeout(() => this._emitChange(), 150); };
|
|
4804
|
-
this.
|
|
5431
|
+
this._row.addEventListener('click', this._onClick);
|
|
4805
5432
|
this._input.addEventListener('input', this._onInput);
|
|
4806
5433
|
}
|
|
4807
5434
|
|
|
4808
5435
|
teardownEvents() {
|
|
4809
|
-
this.
|
|
5436
|
+
this._row?.removeEventListener('click', this._onClick);
|
|
4810
5437
|
this._input?.removeEventListener('input', this._onInput);
|
|
4811
5438
|
clearTimeout(this._debounce);
|
|
4812
5439
|
}
|
|
@@ -4815,13 +5442,18 @@ class NkFilterBar extends NkElement {
|
|
|
4815
5442
|
onAttributeChanged() { this._sync(); }
|
|
4816
5443
|
|
|
4817
5444
|
get filters() { return this._filters; }
|
|
4818
|
-
set filters(v) { this._filters = Array.isArray(v) ? v : []; this._sync(); }
|
|
5445
|
+
set filters(v) { this._filters = Array.isArray(v) ? v : []; if (this._row) this._sync(); }
|
|
4819
5446
|
get value() { return this._input?.value ?? ''; }
|
|
4820
5447
|
set value(v) { if (this._input) this._input.value = v ?? ''; }
|
|
4821
|
-
/**
|
|
5448
|
+
/**
|
|
5449
|
+
* Applies filters and search to rows: a filter keeps rows where row[key]
|
|
5450
|
+
* equals value – or differs from it with op: 'is-not'; the search looks
|
|
5451
|
+
* for the text in every string field (a person's name).
|
|
5452
|
+
*/
|
|
4822
5453
|
apply(rows) {
|
|
4823
5454
|
const q = this.value.trim().toLowerCase();
|
|
4824
|
-
return rows.filter(r => this._filters.every(f => r[f.key]
|
|
5455
|
+
return rows.filter(r => this._filters.every(f => (f.op === 'is-not' ? r[f.key] !== f.value : r[f.key] === f.value))
|
|
5456
|
+
&& (!q || Object.values(r).some(v => String(typeof v === 'object' && v ? v.name ?? '' : v ?? '').toLowerCase().includes(q))));
|
|
4825
5457
|
}
|
|
4826
5458
|
}
|
|
4827
5459
|
|
|
@@ -4881,15 +5513,16 @@ class NkComments extends NkElement {
|
|
|
4881
5513
|
|
|
4882
5514
|
customElements.define('nk-comments', NkComments);
|
|
4883
5515
|
|
|
4884
|
-
// <nk-comment author="Sara Lindt" time="1 hr ago" avatar="SL" color="
|
|
4885
|
-
// → <div class="nk-comment"><span class="
|
|
5516
|
+
// <nk-comment author="Sara Lindt" time="1 hr ago" avatar="SL" color="green">The board view feels close.</nk-comment>
|
|
5517
|
+
// → <div class="nk-comment"><span class="nk-avatar green">SL</span><div><div class="c-head"><b>Sara Lindt</b> · 1 hr ago</div><div class="c-body">…</div></div></div>
|
|
5518
|
+
// color: one of Notion's nine names, or any CSS background; without it the avatar gradient.
|
|
4886
5519
|
// slot="head" adds content after the name (e.g. an <nk-tag>).
|
|
4887
5520
|
class NkComment extends NkElement {
|
|
4888
5521
|
static get observedAttributes() { return ['author', 'time', 'avatar', 'color']; }
|
|
4889
5522
|
|
|
4890
5523
|
render() {
|
|
4891
5524
|
const box = this.createElement('div', ['nk-comment']);
|
|
4892
|
-
this._avatar = this.createElement('span', ['
|
|
5525
|
+
this._avatar = this.createElement('span', ['nk-avatar']);
|
|
4893
5526
|
const avatarSlot = this.createElement('slot', [], { name: 'avatar' });
|
|
4894
5527
|
avatarSlot.appendChild(this._avatar);
|
|
4895
5528
|
const text = document.createElement('div');
|
|
@@ -4910,8 +5543,8 @@ class NkComment extends NkElement {
|
|
|
4910
5543
|
this._author.textContent = author;
|
|
4911
5544
|
const time = this.getAttribute('time');
|
|
4912
5545
|
this._time.data = time ? ` · ${time}` : '';
|
|
4913
|
-
this._avatar.textContent = this.getAttribute('avatar') || author
|
|
4914
|
-
this._avatar
|
|
5546
|
+
this._avatar.textContent = this.getAttribute('avatar') || initialsOf(author);
|
|
5547
|
+
paintAvatar(this._avatar, this.getAttribute('color'));
|
|
4915
5548
|
}
|
|
4916
5549
|
|
|
4917
5550
|
onAttributeChanged() { this._sync(); }
|
|
@@ -4935,16 +5568,18 @@ customElements.define('nk-ai-thread', NkAiThread);
|
|
|
4935
5568
|
// Two tasks are open …
|
|
4936
5569
|
// <button slot="actions" value="copy">📋 Copy</button><button slot="actions" value="retry">↻ Rephrase</button>
|
|
4937
5570
|
// </nk-ai-msg>
|
|
5571
|
+
// <nk-ai-msg role="user" bubble>What is still open?</nk-ai-msg> → a grey bubble on the right, as in Notion's AI chat
|
|
4938
5572
|
// → <div class="nk-ai-msg user"><span class="mini-avatar">MK</span><div class="a-body"><div class="a-name">You</div>…<div class="nk-ai-actions">…</div></div></div>
|
|
4939
5573
|
// Action buttons stay in the light DOM (slotted twins) and fire nk-action { action: value }.
|
|
4940
5574
|
class NkAiMsg extends NkElement {
|
|
4941
|
-
static get observedAttributes() { return ['role', 'name', 'badge', 'avatar', 'color']; }
|
|
5575
|
+
static get observedAttributes() { return ['role', 'name', 'badge', 'avatar', 'color', 'bubble']; }
|
|
4942
5576
|
|
|
4943
5577
|
render() {
|
|
4944
5578
|
this._box = this.createElement('div', ['nk-ai-msg']);
|
|
4945
5579
|
this._avatar = this.createElement('span', ['mini-avatar']);
|
|
4946
5580
|
const avatarSlot = this.createElement('slot', [], { name: 'avatar' });
|
|
4947
5581
|
avatarSlot.appendChild(this._avatar);
|
|
5582
|
+
this._avatarSlot = avatarSlot;
|
|
4948
5583
|
const body = this.createElement('div', ['a-body']);
|
|
4949
5584
|
this._name = this.createElement('div', ['a-name']);
|
|
4950
5585
|
this._nameText = document.createTextNode('');
|
|
@@ -4961,12 +5596,16 @@ class NkAiMsg extends NkElement {
|
|
|
4961
5596
|
|
|
4962
5597
|
_sync() {
|
|
4963
5598
|
const user = this.getAttribute('role') === 'user';
|
|
5599
|
+
const bubble = this.getBoolAttr('bubble');
|
|
4964
5600
|
this._box.classList.toggle('user', user);
|
|
5601
|
+
this._box.classList.toggle('bubble', bubble);
|
|
4965
5602
|
const name = this.getAttribute('name');
|
|
4966
5603
|
this._nameText.data = name || '';
|
|
4967
5604
|
const badge = this.getAttribute('badge');
|
|
4968
5605
|
this._badge.textContent = badge ? ` ${badge}` : '';
|
|
4969
|
-
|
|
5606
|
+
// A bubble stands without avatar and name; the text says who asked.
|
|
5607
|
+
this._name.style.display = name && !bubble ? '' : 'none';
|
|
5608
|
+
this._avatarSlot.style.display = bubble ? 'none' : '';
|
|
4970
5609
|
this._avatar.textContent = this.getAttribute('avatar') || (user ? (name || 'U').slice(0, 2).toUpperCase() : '✨');
|
|
4971
5610
|
const color = this.getAttribute('color');
|
|
4972
5611
|
this._avatar.style.background = color || '';
|
|
@@ -5048,4 +5687,4 @@ class NkAiInputRow extends NkElement {
|
|
|
5048
5687
|
|
|
5049
5688
|
customElements.define('nk-ai-input-row', NkAiInputRow);
|
|
5050
5689
|
|
|
5051
|
-
export { NkAiInputRow, NkAiMsg, NkAiThread, NkApp, NkAvatarGroup, NkBanner, NkBlockHost, NkBoardView, NkBreadcrumb, NkBtn, NkCallout, NkCheck, NkCmdk, NkCode, NkComment, NkComments, NkDangerZone, NkDatabase, NkDivider, NkElement, NkEmojiPicker, NkEmpty, NkField, NkFields, NkFilterBar, NkFormElement, NkHeading, NkInput, NkKbd, NkMemberList, NkMemberRow, NkMention, NkMenu, NkMenuItem, NkModal, NkModelCard, NkPage, NkPageActions, NkPageCover, NkPageTitle, NkPop, NkProfileRow, NkProgress, NkQuote, NkRadio, NkSectionLabel, NkSegmented, NkSelect, NkSettingsPane, NkSettingsUser, NkSidebar, NkSkeleton, NkSlider, NkStat, NkStats, NkSwitch, NkSynced, NkTab, NkTabBar, NkTabBarItem, NkTableView, NkTabs, NkTag, NkTemplateBtn, NkTextarea, NkThemeToggle, NkToast, NkTodo, NkToggle, NkTopbar, NkTree, NkTreeItem, NkWorkspaceSwitcher, compareBy, renderPropertyCell, tagFor };
|
|
5690
|
+
export { NkAiInputRow, NkAiMsg, NkAiThread, NkApp, NkAvatar, NkAvatarGroup, NkBanner, NkBlockHost, NkBoardView, NkBreadcrumb, NkBtn, NkCallout, NkCheck, NkCmdk, NkCode, NkComment, NkComments, NkDangerZone, NkDatabase, NkDivider, NkElement, NkEmojiPicker, NkEmpty, NkField, NkFields, NkFilterBar, NkFormElement, NkHeading, NkInput, NkKbd, NkListView, NkMemberList, NkMemberRow, NkMention, NkMenu, NkMenuItem, NkModal, NkModelCard, NkPage, NkPageActions, NkPageCover, NkPageTitle, NkPanel, NkPanels, NkPop, NkProfileRow, NkProgress, NkProp, NkProps, NkQuote, NkRadio, NkSectionLabel, NkSegmented, NkSelect, NkSettingsPane, NkSettingsUser, NkSheet, NkSidebar, NkSkeleton, NkSlider, NkStat, NkStats, NkSteps, NkSwitch, NkSynced, NkTab, NkTabBar, NkTabBarItem, NkTableView, NkTabs, NkTag, NkTemplateBtn, NkTextarea, NkThemeToggle, NkToast, NkTodo, NkToggle, NkTopbar, NkTree, NkTreeItem, NkWorkspaceSwitcher, compareBy, componentsSheet, renderPropertyCell, tagFor };
|