@aryacode/dsh-aryacode-polish 0.13.1 → 0.14.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/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.14.0] - 2026-10-28
4
+
5
+ ### Added
6
+
7
+ - **Quick switcher.** Ctrl/⌘-K (or Cmd-K) opens a palette over everything: every session
8
+ in every workspace, ranked so a prefix beats a mention, arrows to walk, Enter to open,
9
+ Escape to dismiss. Rows show the session title and the workspace it lives in.
10
+ - **Folded state persists.** Which workspaces and which folders are collapsed is kept
11
+ under `aryacode-polish:folded.v1`, so reopening the app looks like it did on the way
12
+ out. A storage that refuses costs the memory and nothing else.
13
+
3
14
  ## [0.13.1] - 2026-10-28
4
15
 
5
16
  ### Added
@@ -384,6 +384,121 @@ export function moveBefore(list, movingId, beforeId) {
384
384
 
385
385
  const LOOK_KEY = 'aryacode-polish:workspace-appearance.v1'
386
386
  const ORDER_KEY = 'aryacode-polish:workspace-order.v1'
387
+ const FOLD_KEY = 'aryacode-polish:folded.v1'
388
+
389
+ /** Which workspaces and folders are folded, kept so a restart looks like yesterday. */
390
+ export function readFolded(storage) {
391
+ try {
392
+ const store = storage || (typeof localStorage === 'undefined' ? undefined : localStorage)
393
+ if (!store) return { workspaces: {}, folders: {} }
394
+ const raw = store.getItem(FOLD_KEY)
395
+ if (!raw) return { workspaces: {}, folders: {} }
396
+ const parsed = JSON.parse(raw)
397
+ return {
398
+ workspaces: (parsed && parsed.workspaces) || {},
399
+ folders: (parsed && parsed.folders) || {},
400
+ }
401
+ } catch {
402
+ return { workspaces: {}, folders: {} }
403
+ }
404
+ }
405
+
406
+ export function writeFolded(state, storage) {
407
+ try {
408
+ const store = storage || (typeof localStorage === 'undefined' ? undefined : localStorage)
409
+ if (!store) return
410
+ const clean = {
411
+ workspaces: (state && state.workspaces) || {},
412
+ folders: (state && state.folders) || {},
413
+ }
414
+ store.setItem(FOLD_KEY, JSON.stringify(clean))
415
+ } catch {
416
+ /* folding is a convenience; a store that refuses must not break the tree */
417
+ }
418
+ }
419
+
420
+ /**
421
+ * Rank the quick switcher's rows. A title that starts with the query wins over one
422
+ * that merely contains it, and equal kinds keep the order they arrived in — so
423
+ * typing "gre" puts Greeting above anything that mentions greeting later on.
424
+ */
425
+ export function rankMatches(items, query, text = (item) => String(item.title || item.id || '')) {
426
+ const list = Array.isArray(items) ? items : []
427
+ const needle = String(query || '').trim().toLowerCase()
428
+ if (!needle) return list.slice(0, 40)
429
+ const scored = []
430
+ list.forEach((item, order) => {
431
+ const hay = text(item).toLowerCase()
432
+ const at = hay.indexOf(needle)
433
+ if (at === -1) return
434
+ scored.push({ item, rank: at === 0 ? 0 : 1, order })
435
+ })
436
+ scored.sort((a, b) => (a.rank - b.rank) || (a.order - b.order))
437
+ return scored.slice(0, 40).map((entry) => entry.item)
438
+ }
439
+
440
+ const SWITCHER_BACKDROP = {
441
+ position: 'fixed',
442
+ inset: 0,
443
+ zIndex: 1300,
444
+ display: 'flex',
445
+ alignItems: 'flex-start',
446
+ justifyContent: 'center',
447
+ paddingTop: '12vh',
448
+ background: 'rgba(16, 18, 22, 0.28)',
449
+ }
450
+
451
+ const SWITCHER_CARD = {
452
+ width: 'min(560px, calc(100vw - 32px))',
453
+ maxHeight: '60vh',
454
+ overflow: 'hidden',
455
+ display: 'flex',
456
+ flexDirection: 'column',
457
+ borderRadius: 'var(--dsw-radius-lg, 10px)',
458
+ border: '0.5px solid var(--dsw-alias-border-l2, rgba(0,0,0,0.12))',
459
+ background: 'Canvas',
460
+ boxShadow: 'var(--dsw-elevation-prominent, 0 8px 24px rgba(0,0,0,0.18))',
461
+ color: 'var(--dsw-alias-label-primary, #1b1d21)',
462
+ }
463
+
464
+ const SWITCHER_INPUT = {
465
+ border: 'none',
466
+ borderBottom: '0.5px solid var(--dsw-alias-border-l2, rgba(0,0,0,0.12))',
467
+ background: 'transparent',
468
+ color: 'inherit',
469
+ fontSize: '14px',
470
+ padding: '12px 14px',
471
+ outline: 'none',
472
+ }
473
+
474
+ const SWITCHER_LIST = {
475
+ overflowY: 'auto',
476
+ padding: '4px',
477
+ display: 'flex',
478
+ flexDirection: 'column',
479
+ gap: '1px',
480
+ }
481
+
482
+ const SWITCHER_ROW = {
483
+ display: 'flex',
484
+ alignItems: 'center',
485
+ gap: '8px',
486
+ padding: '7px 10px',
487
+ border: 'none',
488
+ borderRadius: 'var(--dsw-radius-sm, 6px)',
489
+ background: 'transparent',
490
+ color: 'inherit',
491
+ fontSize: '13px',
492
+ textAlign: 'left',
493
+ cursor: 'pointer',
494
+ }
495
+
496
+ const SWITCHER_HINT = {
497
+ flex: 'none',
498
+ color: 'var(--dsw-alias-label-quaternary, #8a8a8a)',
499
+ fontSize: '11px',
500
+ fontVariantNumeric: 'tabular-nums',
501
+ }
387
502
 
388
503
  /**
389
504
  * A workspace whose label carries a path ("Work/Client A") files itself under
@@ -586,7 +701,7 @@ export function BetterWorkspace(props) {
586
701
  const services = props.services || {}
587
702
  const { ctx, slots } = services
588
703
  const standard = { wide: props.wide === true, expandSidebar: props.expandSidebar }
589
- const [expanded, setExpanded] = React.useState({})
704
+ const [expanded, setExpanded] = React.useState(() => readFolded().workspaces)
590
705
  const [menu, setMenu] = React.useState(null)
591
706
  const [armed, setArmed] = React.useState(null)
592
707
  const [adding, setAdding] = React.useState(false)
@@ -597,7 +712,10 @@ export function BetterWorkspace(props) {
597
712
  const [drag, setDrag] = React.useState(null)
598
713
  const [dropping, setDropping] = React.useState(null)
599
714
  const [look, setLook] = React.useState(() => readAppearance())
600
- const [folders, setFolders] = React.useState({})
715
+ const folded = React.useMemo(() => readFolded(), [])
716
+ const [folders, setFolders] = React.useState(folded.folders)
717
+ const [switcher, setSwitcher] = React.useState(null)
718
+ React.useEffect(() => { writeFolded({ workspaces: expanded, folders }) }, [expanded, folders])
601
719
  const [renaming, setRenaming] = React.useState(null)
602
720
  const commitRename = async () => {
603
721
  const draft = renaming
@@ -664,6 +782,36 @@ export function BetterWorkspace(props) {
664
782
  return () => document.removeEventListener('keydown', onShortcut)
665
783
  }, [])
666
784
 
785
+ React.useEffect(() => {
786
+ const onOpen = (event) => {
787
+ const key = (event.key || '').toLowerCase()
788
+ if (!(event.ctrlKey || event.metaKey) || key !== 'k') return
789
+ event.preventDefault()
790
+ setSwitcher((prev) => (prev ? null : { query: '', index: 0 }))
791
+ }
792
+ const onEscape = (event) => {
793
+ if (event.key === 'Escape') setSwitcher(null)
794
+ }
795
+ document.addEventListener('keydown', onOpen)
796
+ document.addEventListener('keydown', onEscape)
797
+ return () => {
798
+ document.removeEventListener('keydown', onOpen)
799
+ document.removeEventListener('keydown', onEscape)
800
+ }
801
+ }, [])
802
+
803
+ const switchItems = React.useMemo(() => {
804
+ const items = []
805
+ allRows.forEach((group) => {
806
+ const workspace = workspaceLabel(group.workspace)
807
+ group.sessions.forEach((row) => {
808
+ items.push({ id: row.id, title: row.displayTitle || row.id, workspace })
809
+ })
810
+ })
811
+ return items
812
+ }, [allRows])
813
+ const switchHits = switcher ? rankMatches(switchItems, switcher.query) : []
814
+
667
815
  const openMenu = (event, row, workspace) => {
668
816
  event.preventDefault()
669
817
  event.stopPropagation()
@@ -882,6 +1030,56 @@ export function BetterWorkspace(props) {
882
1030
  null)
883
1031
  : null
884
1032
 
1033
+ const switcherCard = switcher
1034
+ ? ReactDOM.createPortal(React.createElement('div', {
1035
+ 'data-polish-switcher': 'open',
1036
+ style: SWITCHER_BACKDROP,
1037
+ onPointerDown: (event) => { if (event.target === event.currentTarget) setSwitcher(null) },
1038
+ },
1039
+ React.createElement('div', { style: SWITCHER_CARD },
1040
+ React.createElement('input', {
1041
+ 'data-polish-switcher-input': 'true',
1042
+ autoFocus: true,
1043
+ value: switcher.query,
1044
+ placeholder: 'Jump to a session…',
1045
+ 'aria-label': 'Jump to a session',
1046
+ style: SWITCHER_INPUT,
1047
+ onChange: (event) => setSwitcher(Object.assign({}, switcher, { query: event.target.value, index: 0 })),
1048
+ onKeyDown: (event) => {
1049
+ if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
1050
+ if (switchHits.length === 0) return
1051
+ event.preventDefault()
1052
+ const step = event.key === 'ArrowDown' ? 1 : -1
1053
+ const next = (switcher.index + step + switchHits.length) % switchHits.length
1054
+ setSwitcher(Object.assign({}, switcher, { index: next }))
1055
+ return
1056
+ }
1057
+ if (event.key === 'Enter') {
1058
+ const hit = switchHits[switcher.index]
1059
+ if (!hit) return
1060
+ event.preventDefault()
1061
+ setSwitcher(null)
1062
+ services.openSession(hit.id)
1063
+ }
1064
+ },
1065
+ }),
1066
+ React.createElement('div', { 'data-polish-switcher-list': 'true', style: SWITCHER_LIST },
1067
+ switchHits.length === 0
1068
+ ? React.createElement('div', { style: Object.assign({}, SWITCHER_ROW, { cursor: 'default' }) }, 'No session matches that.')
1069
+ : switchHits.map((hit, at) => React.createElement('button', {
1070
+ key: hit.id,
1071
+ type: 'button',
1072
+ 'data-polish-switcher-row': hit.id,
1073
+ style: Object.assign({}, SWITCHER_ROW, {
1074
+ background: at === switcher.index ? 'var(--dsw-alias-interactive-bg-hover, rgba(0,0,0,0.06))' : 'transparent',
1075
+ }),
1076
+ onPointerDown: (event) => event.preventDefault(),
1077
+ onClick: () => { setSwitcher(null); services.openSession(hit.id) },
1078
+ },
1079
+ React.createElement('span', { style: WS_TITLE }, hit.title),
1080
+ React.createElement('span', { style: SWITCHER_HINT }, hit.workspace)))))), document.body)
1081
+ : null
1082
+
885
1083
  const children = []
886
1084
 
887
1085
  children.push(React.createElement('div', { key: 'header', 'data-polish-ws': 'header', style: WS_HEADER },
@@ -1125,6 +1323,7 @@ export function BetterWorkspace(props) {
1125
1323
  shownCount < totalCount
1126
1324
  ? React.createElement('div', { key: 'count', style: WS_COUNT_NOTE }, String(shownCount) + ' of ' + String(totalCount) + ' sessions')
1127
1325
  : null,
1326
+ switcherCard,
1128
1327
  sessionMenu,
1129
1328
  paintMenu,
1130
1329
  workspaceMenu)
@@ -134,3 +134,21 @@ offers exactly one reorder verb (`insertBefore(movingId, beforeId)`), so restori
134
134
  one move per workspace that sits in the wrong slot. Ids the Host no longer has are
135
135
  filtered out first, so a preset that names a deleted workspace cannot shuffle the
136
136
  survivors into the wrong places.
137
+
138
+ ## Quick switcher
139
+
140
+ Ctrl/⌘-K opens a palette over every session in every workspace: the list is
141
+ `rankMatches(allSessions, query)`, which scores a title that *starts* with the query
142
+ above one that merely mentions it and keeps arrival order inside a rank (so "gre" puts
143
+ Greeting above later mentions). Arrows walk, Enter opens the session through
144
+ `uiWorkspace.openSession`, Escape or a backdrop click dismisses. It is portalled to
145
+ `document.body` with its own backdrop, so neither the sidebar's scroll container nor a
146
+ panel's stacking context can clip it.
147
+
148
+ ## Folded state
149
+
150
+ `expanded` (workspaces) and `folders` (title folders) are seeded from
151
+ `aryacode-polish:folded.v1` and written back whenever either changes, so a restart looks
152
+ like the way out. Verified across a real restart: folding `WORK` left
153
+ `{"workspaces":{},"folders":{"Work":true}}` in storage and the folder still read `› WORK 2`
154
+ with its workspace hidden.
package/lib/client.js CHANGED
@@ -53,7 +53,7 @@ window.__ModuleLoader__.load({
53
53
  ]
54
54
  const ROW_ID = "polish"
55
55
  const ROW_KEY = "@aryacode/dsh-aryacode-polish" + '#' + ROW_ID
56
- const CLIENT_VERSION = "0.13.1"
56
+ const CLIENT_VERSION = "0.14.0"
57
57
 
58
58
  /* html2canvas 1.4.1 — MIT, vendored from vendor/html2canvas.min.js.
59
59
  * A UMD build, so it assigns itself to globalThis; face.js reads it lazily. */
@@ -585,6 +585,121 @@ window.__ModuleLoader__.load({
585
585
 
586
586
  const LOOK_KEY = 'aryacode-polish:workspace-appearance.v1'
587
587
  const ORDER_KEY = 'aryacode-polish:workspace-order.v1'
588
+ const FOLD_KEY = 'aryacode-polish:folded.v1'
589
+
590
+ /** Which workspaces and folders are folded, kept so a restart looks like yesterday. */
591
+ function readFolded(storage) {
592
+ try {
593
+ const store = storage || (typeof localStorage === 'undefined' ? undefined : localStorage)
594
+ if (!store) return { workspaces: {}, folders: {} }
595
+ const raw = store.getItem(FOLD_KEY)
596
+ if (!raw) return { workspaces: {}, folders: {} }
597
+ const parsed = JSON.parse(raw)
598
+ return {
599
+ workspaces: (parsed && parsed.workspaces) || {},
600
+ folders: (parsed && parsed.folders) || {},
601
+ }
602
+ } catch {
603
+ return { workspaces: {}, folders: {} }
604
+ }
605
+ }
606
+
607
+ function writeFolded(state, storage) {
608
+ try {
609
+ const store = storage || (typeof localStorage === 'undefined' ? undefined : localStorage)
610
+ if (!store) return
611
+ const clean = {
612
+ workspaces: (state && state.workspaces) || {},
613
+ folders: (state && state.folders) || {},
614
+ }
615
+ store.setItem(FOLD_KEY, JSON.stringify(clean))
616
+ } catch {
617
+ /* folding is a convenience; a store that refuses must not break the tree */
618
+ }
619
+ }
620
+
621
+ /**
622
+ * Rank the quick switcher's rows. A title that starts with the query wins over one
623
+ * that merely contains it, and equal kinds keep the order they arrived in — so
624
+ * typing "gre" puts Greeting above anything that mentions greeting later on.
625
+ */
626
+ function rankMatches(items, query, text = (item) => String(item.title || item.id || '')) {
627
+ const list = Array.isArray(items) ? items : []
628
+ const needle = String(query || '').trim().toLowerCase()
629
+ if (!needle) return list.slice(0, 40)
630
+ const scored = []
631
+ list.forEach((item, order) => {
632
+ const hay = text(item).toLowerCase()
633
+ const at = hay.indexOf(needle)
634
+ if (at === -1) return
635
+ scored.push({ item, rank: at === 0 ? 0 : 1, order })
636
+ })
637
+ scored.sort((a, b) => (a.rank - b.rank) || (a.order - b.order))
638
+ return scored.slice(0, 40).map((entry) => entry.item)
639
+ }
640
+
641
+ const SWITCHER_BACKDROP = {
642
+ position: 'fixed',
643
+ inset: 0,
644
+ zIndex: 1300,
645
+ display: 'flex',
646
+ alignItems: 'flex-start',
647
+ justifyContent: 'center',
648
+ paddingTop: '12vh',
649
+ background: 'rgba(16, 18, 22, 0.28)',
650
+ }
651
+
652
+ const SWITCHER_CARD = {
653
+ width: 'min(560px, calc(100vw - 32px))',
654
+ maxHeight: '60vh',
655
+ overflow: 'hidden',
656
+ display: 'flex',
657
+ flexDirection: 'column',
658
+ borderRadius: 'var(--dsw-radius-lg, 10px)',
659
+ border: '0.5px solid var(--dsw-alias-border-l2, rgba(0,0,0,0.12))',
660
+ background: 'Canvas',
661
+ boxShadow: 'var(--dsw-elevation-prominent, 0 8px 24px rgba(0,0,0,0.18))',
662
+ color: 'var(--dsw-alias-label-primary, #1b1d21)',
663
+ }
664
+
665
+ const SWITCHER_INPUT = {
666
+ border: 'none',
667
+ borderBottom: '0.5px solid var(--dsw-alias-border-l2, rgba(0,0,0,0.12))',
668
+ background: 'transparent',
669
+ color: 'inherit',
670
+ fontSize: '14px',
671
+ padding: '12px 14px',
672
+ outline: 'none',
673
+ }
674
+
675
+ const SWITCHER_LIST = {
676
+ overflowY: 'auto',
677
+ padding: '4px',
678
+ display: 'flex',
679
+ flexDirection: 'column',
680
+ gap: '1px',
681
+ }
682
+
683
+ const SWITCHER_ROW = {
684
+ display: 'flex',
685
+ alignItems: 'center',
686
+ gap: '8px',
687
+ padding: '7px 10px',
688
+ border: 'none',
689
+ borderRadius: 'var(--dsw-radius-sm, 6px)',
690
+ background: 'transparent',
691
+ color: 'inherit',
692
+ fontSize: '13px',
693
+ textAlign: 'left',
694
+ cursor: 'pointer',
695
+ }
696
+
697
+ const SWITCHER_HINT = {
698
+ flex: 'none',
699
+ color: 'var(--dsw-alias-label-quaternary, #8a8a8a)',
700
+ fontSize: '11px',
701
+ fontVariantNumeric: 'tabular-nums',
702
+ }
588
703
 
589
704
  /**
590
705
  * A workspace whose label carries a path ("Work/Client A") files itself under
@@ -787,7 +902,7 @@ window.__ModuleLoader__.load({
787
902
  const services = props.services || {}
788
903
  const { ctx, slots } = services
789
904
  const standard = { wide: props.wide === true, expandSidebar: props.expandSidebar }
790
- const [expanded, setExpanded] = React.useState({})
905
+ const [expanded, setExpanded] = React.useState(() => readFolded().workspaces)
791
906
  const [menu, setMenu] = React.useState(null)
792
907
  const [armed, setArmed] = React.useState(null)
793
908
  const [adding, setAdding] = React.useState(false)
@@ -798,7 +913,10 @@ window.__ModuleLoader__.load({
798
913
  const [drag, setDrag] = React.useState(null)
799
914
  const [dropping, setDropping] = React.useState(null)
800
915
  const [look, setLook] = React.useState(() => readAppearance())
801
- const [folders, setFolders] = React.useState({})
916
+ const folded = React.useMemo(() => readFolded(), [])
917
+ const [folders, setFolders] = React.useState(folded.folders)
918
+ const [switcher, setSwitcher] = React.useState(null)
919
+ React.useEffect(() => { writeFolded({ workspaces: expanded, folders }) }, [expanded, folders])
802
920
  const [renaming, setRenaming] = React.useState(null)
803
921
  const commitRename = async () => {
804
922
  const draft = renaming
@@ -865,6 +983,36 @@ window.__ModuleLoader__.load({
865
983
  return () => document.removeEventListener('keydown', onShortcut)
866
984
  }, [])
867
985
 
986
+ React.useEffect(() => {
987
+ const onOpen = (event) => {
988
+ const key = (event.key || '').toLowerCase()
989
+ if (!(event.ctrlKey || event.metaKey) || key !== 'k') return
990
+ event.preventDefault()
991
+ setSwitcher((prev) => (prev ? null : { query: '', index: 0 }))
992
+ }
993
+ const onEscape = (event) => {
994
+ if (event.key === 'Escape') setSwitcher(null)
995
+ }
996
+ document.addEventListener('keydown', onOpen)
997
+ document.addEventListener('keydown', onEscape)
998
+ return () => {
999
+ document.removeEventListener('keydown', onOpen)
1000
+ document.removeEventListener('keydown', onEscape)
1001
+ }
1002
+ }, [])
1003
+
1004
+ const switchItems = React.useMemo(() => {
1005
+ const items = []
1006
+ allRows.forEach((group) => {
1007
+ const workspace = workspaceLabel(group.workspace)
1008
+ group.sessions.forEach((row) => {
1009
+ items.push({ id: row.id, title: row.displayTitle || row.id, workspace })
1010
+ })
1011
+ })
1012
+ return items
1013
+ }, [allRows])
1014
+ const switchHits = switcher ? rankMatches(switchItems, switcher.query) : []
1015
+
868
1016
  const openMenu = (event, row, workspace) => {
869
1017
  event.preventDefault()
870
1018
  event.stopPropagation()
@@ -1083,6 +1231,56 @@ window.__ModuleLoader__.load({
1083
1231
  null)
1084
1232
  : null
1085
1233
 
1234
+ const switcherCard = switcher
1235
+ ? ReactDOM.createPortal(React.createElement('div', {
1236
+ 'data-polish-switcher': 'open',
1237
+ style: SWITCHER_BACKDROP,
1238
+ onPointerDown: (event) => { if (event.target === event.currentTarget) setSwitcher(null) },
1239
+ },
1240
+ React.createElement('div', { style: SWITCHER_CARD },
1241
+ React.createElement('input', {
1242
+ 'data-polish-switcher-input': 'true',
1243
+ autoFocus: true,
1244
+ value: switcher.query,
1245
+ placeholder: 'Jump to a session…',
1246
+ 'aria-label': 'Jump to a session',
1247
+ style: SWITCHER_INPUT,
1248
+ onChange: (event) => setSwitcher(Object.assign({}, switcher, { query: event.target.value, index: 0 })),
1249
+ onKeyDown: (event) => {
1250
+ if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
1251
+ if (switchHits.length === 0) return
1252
+ event.preventDefault()
1253
+ const step = event.key === 'ArrowDown' ? 1 : -1
1254
+ const next = (switcher.index + step + switchHits.length) % switchHits.length
1255
+ setSwitcher(Object.assign({}, switcher, { index: next }))
1256
+ return
1257
+ }
1258
+ if (event.key === 'Enter') {
1259
+ const hit = switchHits[switcher.index]
1260
+ if (!hit) return
1261
+ event.preventDefault()
1262
+ setSwitcher(null)
1263
+ services.openSession(hit.id)
1264
+ }
1265
+ },
1266
+ }),
1267
+ React.createElement('div', { 'data-polish-switcher-list': 'true', style: SWITCHER_LIST },
1268
+ switchHits.length === 0
1269
+ ? React.createElement('div', { style: Object.assign({}, SWITCHER_ROW, { cursor: 'default' }) }, 'No session matches that.')
1270
+ : switchHits.map((hit, at) => React.createElement('button', {
1271
+ key: hit.id,
1272
+ type: 'button',
1273
+ 'data-polish-switcher-row': hit.id,
1274
+ style: Object.assign({}, SWITCHER_ROW, {
1275
+ background: at === switcher.index ? 'var(--dsw-alias-interactive-bg-hover, rgba(0,0,0,0.06))' : 'transparent',
1276
+ }),
1277
+ onPointerDown: (event) => event.preventDefault(),
1278
+ onClick: () => { setSwitcher(null); services.openSession(hit.id) },
1279
+ },
1280
+ React.createElement('span', { style: WS_TITLE }, hit.title),
1281
+ React.createElement('span', { style: SWITCHER_HINT }, hit.workspace)))))), document.body)
1282
+ : null
1283
+
1086
1284
  const children = []
1087
1285
 
1088
1286
  children.push(React.createElement('div', { key: 'header', 'data-polish-ws': 'header', style: WS_HEADER },
@@ -1326,6 +1524,7 @@ window.__ModuleLoader__.load({
1326
1524
  shownCount < totalCount
1327
1525
  ? React.createElement('div', { key: 'count', style: WS_COUNT_NOTE }, String(shownCount) + ' of ' + String(totalCount) + ' sessions')
1328
1526
  : null,
1527
+ switcherCard,
1329
1528
  sessionMenu,
1330
1529
  paintMenu,
1331
1530
  workspaceMenu)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aryacode/dsh-aryacode-polish",
3
- "version": "0.13.1",
3
+ "version": "0.14.0",
4
4
  "description": "AryaCode Polish: one install for the small things that make AryaCode feel finished. One Plugins row, one switch per quality-of-life feature.",
5
5
  "keywords": [
6
6
  "dsh",