@aryacode/dsh-aryacode-polish 0.16.0 → 0.17.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 +8 -0
- package/client/workspace.js +70 -3
- package/docs/better-workspace.md +15 -0
- package/lib/client.js +71 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.17.0] - 2026-10-28
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **Drop a workspace on a folder header to file it there.** The title is rewritten to
|
|
7
|
+
Folder/Name (any previous prefix is replaced, not stacked) through the Host rename.
|
|
8
|
+
- **A workspace note shows as a card on hover**, not just as a tooltip title.
|
|
9
|
+
|
|
10
|
+
|
|
3
11
|
## [0.16.0] - 2026-10-28
|
|
4
12
|
|
|
5
13
|
### Added
|
package/client/workspace.js
CHANGED
|
@@ -475,6 +475,22 @@ const WS_MENU_HINT = {
|
|
|
475
475
|
color: 'var(--dsw-alias-label-quaternary, #8a8a8a)',
|
|
476
476
|
}
|
|
477
477
|
|
|
478
|
+
const WS_NOTE_CARD = {
|
|
479
|
+
position: 'fixed',
|
|
480
|
+
zIndex: 1250,
|
|
481
|
+
maxWidth: '260px',
|
|
482
|
+
padding: '6px 9px',
|
|
483
|
+
borderRadius: 'var(--dsw-radius-md, 8px)',
|
|
484
|
+
border: '0.5px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.12))',
|
|
485
|
+
background: 'Canvas',
|
|
486
|
+
color: 'var(--dsw-alias-label-secondary, #61666b)',
|
|
487
|
+
fontSize: 'calc(var(--dsh-content-font-size-secondary, 13px) - 1px)',
|
|
488
|
+
lineHeight: 1.35,
|
|
489
|
+
boxShadow: 'var(--dsw-elevation-prominent, 0 2px 8px rgba(0, 0, 0, 0.08))',
|
|
490
|
+
pointerEvents: 'none',
|
|
491
|
+
whiteSpace: 'pre-wrap',
|
|
492
|
+
}
|
|
493
|
+
|
|
478
494
|
const WS_GLYPH = {
|
|
479
495
|
flex: 'none',
|
|
480
496
|
width: '16px',
|
|
@@ -616,6 +632,19 @@ const SWITCHER_HINT = {
|
|
|
616
632
|
* written to the Host and renaming a workspace is enough to move it between
|
|
617
633
|
* folders — the same idea as the reference plugin, without its "/" toggle.
|
|
618
634
|
*/
|
|
635
|
+
/**
|
|
636
|
+
* The title a workspace needs to sit under `folder`: its own name moved behind the
|
|
637
|
+
* folder prefix, with any previous prefix replaced rather than stacked.
|
|
638
|
+
*/
|
|
639
|
+
export function fileUnder(label, folder) {
|
|
640
|
+
const name = String(label || '').trim()
|
|
641
|
+
const target = String(folder || '').trim()
|
|
642
|
+
if (!name || !target) return name
|
|
643
|
+
const cut = name.lastIndexOf('/')
|
|
644
|
+
const bare = (cut >= 0 ? name.slice(cut + 1) : name).trim()
|
|
645
|
+
return bare ? target + '/' + bare : target
|
|
646
|
+
}
|
|
647
|
+
|
|
619
648
|
export function folderKey(workspace) {
|
|
620
649
|
const label = workspaceLabel(workspace)
|
|
621
650
|
const cut = label.lastIndexOf('/')
|
|
@@ -833,6 +862,7 @@ export function BetterWorkspace(props) {
|
|
|
833
862
|
const [dropping, setDropping] = React.useState(null)
|
|
834
863
|
const [look, setLook] = React.useState(() => readAppearance())
|
|
835
864
|
const [noteDraft, setNoteDraft] = React.useState('')
|
|
865
|
+
const [card, setCard] = React.useState(null)
|
|
836
866
|
const folded = React.useMemo(() => readFolded(), [])
|
|
837
867
|
const [folders, setFolders] = React.useState(folded.folders)
|
|
838
868
|
const [switcher, setSwitcher] = React.useState(null)
|
|
@@ -1215,6 +1245,13 @@ export function BetterWorkspace(props) {
|
|
|
1215
1245
|
React.createElement('div', { style: WS_MENU_HINT }, 'Enter saves, Escape cancels'))
|
|
1216
1246
|
: null
|
|
1217
1247
|
|
|
1248
|
+
const noteCard = card
|
|
1249
|
+
? ReactDOM.createPortal(React.createElement('div', {
|
|
1250
|
+
'data-polish-note-card': 'true',
|
|
1251
|
+
style: Object.assign({}, WS_NOTE_CARD, { top: card.top, left: card.left }),
|
|
1252
|
+
}, card.text), document.body)
|
|
1253
|
+
: null
|
|
1254
|
+
|
|
1218
1255
|
const paintMenu = menu && menu.kind === 'paint'
|
|
1219
1256
|
? (() => {
|
|
1220
1257
|
const workspace = menu.workspace
|
|
@@ -1477,8 +1514,31 @@ export function BetterWorkspace(props) {
|
|
|
1477
1514
|
role: 'group',
|
|
1478
1515
|
'aria-label': folder,
|
|
1479
1516
|
title: folded ? 'Expand ' + folder : 'Collapse ' + folder,
|
|
1480
|
-
style: WS_FOLDER_ROW,
|
|
1517
|
+
style: Object.assign({}, WS_FOLDER_ROW, {
|
|
1518
|
+
background: dropping === 'folder:' + folder
|
|
1519
|
+
? 'var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.05))'
|
|
1520
|
+
: undefined,
|
|
1521
|
+
}),
|
|
1481
1522
|
onClick: () => setFolders((prev) => Object.assign({}, prev, { [folder]: prev[folder] !== true })),
|
|
1523
|
+
onDragOver: (event) => {
|
|
1524
|
+
if (!drag || drag.kind !== 'workspace') return
|
|
1525
|
+
if (folderOf(rows.find((entry) => entry.workspace.workspaceId === drag.id)?.workspace) === folder) return
|
|
1526
|
+
event.preventDefault()
|
|
1527
|
+
setDropping('folder:' + folder)
|
|
1528
|
+
},
|
|
1529
|
+
onDragLeave: () => setDropping(null),
|
|
1530
|
+
onDrop: (event) => {
|
|
1531
|
+
event.preventDefault()
|
|
1532
|
+
setDropping(null)
|
|
1533
|
+
if (!drag || drag.kind !== 'workspace') return
|
|
1534
|
+
const moving = rows.find((entry) => entry.workspace.workspaceId === drag.id)
|
|
1535
|
+
if (!moving || folderOf(moving.workspace) === folder) return
|
|
1536
|
+
const title = fileUnder(workspaceLabel(moving.workspace), folder)
|
|
1537
|
+
Promise.resolve()
|
|
1538
|
+
.then(() => services.renameWorkspace(moving.workspace.workspaceId, title))
|
|
1539
|
+
.then(() => setNotice('Filed under ' + folder + '.'))
|
|
1540
|
+
.catch(() => setNotice('Could not file that workspace.'))
|
|
1541
|
+
},
|
|
1482
1542
|
},
|
|
1483
1543
|
React.createElement('span', { 'aria-hidden': 'true' }, folded ? '›' : '⌄'),
|
|
1484
1544
|
React.createElement('span', { style: WS_TITLE }, folder),
|
|
@@ -1512,8 +1572,14 @@ export function BetterWorkspace(props) {
|
|
|
1512
1572
|
onClick: () => toggleWorkspace(workspace.workspaceId),
|
|
1513
1573
|
onContextMenu: (event) => openWorkspaceMenu(event, workspace),
|
|
1514
1574
|
title: looks.note || undefined,
|
|
1515
|
-
onMouseEnter: () =>
|
|
1516
|
-
|
|
1575
|
+
onMouseEnter: (event) => {
|
|
1576
|
+
setHover('workspace:' + workspace.workspaceId)
|
|
1577
|
+
const note = appearanceOf(look, workspace.workspaceId).note
|
|
1578
|
+
if (!note) return
|
|
1579
|
+
const box = event.currentTarget.getBoundingClientRect()
|
|
1580
|
+
setCard({ text: note, top: box.bottom + 6, left: Math.max(8, box.left) })
|
|
1581
|
+
},
|
|
1582
|
+
onMouseLeave: () => { setHover(null); setCard(null) },
|
|
1517
1583
|
onDragStart: () => setDrag({ kind: 'workspace', id: workspace.workspaceId }),
|
|
1518
1584
|
onDragOver: (event) => {
|
|
1519
1585
|
if (!drag || drag.kind !== 'workspace' || drag.id === workspace.workspaceId) return
|
|
@@ -1609,6 +1675,7 @@ export function BetterWorkspace(props) {
|
|
|
1609
1675
|
sessionMenu,
|
|
1610
1676
|
glyphMenu,
|
|
1611
1677
|
noteMenu,
|
|
1678
|
+
noteCard,
|
|
1612
1679
|
archivedMenu,
|
|
1613
1680
|
paintMenu,
|
|
1614
1681
|
workspaceMenu)
|
package/docs/better-workspace.md
CHANGED
|
@@ -186,3 +186,18 @@ and the note surfaces as the row's tooltip, so it costs no vertical space in the
|
|
|
186
186
|
|
|
187
187
|
Glyph validation is deliberately narrow (one to four characters): the field is a badge in a
|
|
188
188
|
16 px slot, not a place to paste a sentence.
|
|
189
|
+
|
|
190
|
+
## Filing by drag
|
|
191
|
+
|
|
192
|
+
Dropping a workspace on a folder header files it there: the title is rewritten to
|
|
193
|
+
`Folder/Name` through the Host's own rename, so the move is durable and the shipped
|
|
194
|
+
browser (when this switch is off) sees exactly the same structure. `fileUnder(label, folder)`
|
|
195
|
+
replaces any previous prefix instead of stacking it — dragging `A/B/Gamma` onto `C` gives
|
|
196
|
+
`C/Gamma`, not `C/A/B/Gamma` — and a workspace already inside the target folder is not a
|
|
197
|
+
drop target, so the gesture cannot rename something onto itself.
|
|
198
|
+
|
|
199
|
+
## The note card
|
|
200
|
+
|
|
201
|
+
A workspace note shows as a small card under the row on hover rather than as a browser
|
|
202
|
+
tooltip: tooltips are slow to appear, unstyleable, and vanish when the pointer leaves. The
|
|
203
|
+
card is portalled, `pointer-events: none`, and only exists while a note does.
|
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.
|
|
56
|
+
const CLIENT_VERSION = "0.17.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. */
|
|
@@ -676,6 +676,22 @@ window.__ModuleLoader__.load({
|
|
|
676
676
|
color: 'var(--dsw-alias-label-quaternary, #8a8a8a)',
|
|
677
677
|
}
|
|
678
678
|
|
|
679
|
+
const WS_NOTE_CARD = {
|
|
680
|
+
position: 'fixed',
|
|
681
|
+
zIndex: 1250,
|
|
682
|
+
maxWidth: '260px',
|
|
683
|
+
padding: '6px 9px',
|
|
684
|
+
borderRadius: 'var(--dsw-radius-md, 8px)',
|
|
685
|
+
border: '0.5px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.12))',
|
|
686
|
+
background: 'Canvas',
|
|
687
|
+
color: 'var(--dsw-alias-label-secondary, #61666b)',
|
|
688
|
+
fontSize: 'calc(var(--dsh-content-font-size-secondary, 13px) - 1px)',
|
|
689
|
+
lineHeight: 1.35,
|
|
690
|
+
boxShadow: 'var(--dsw-elevation-prominent, 0 2px 8px rgba(0, 0, 0, 0.08))',
|
|
691
|
+
pointerEvents: 'none',
|
|
692
|
+
whiteSpace: 'pre-wrap',
|
|
693
|
+
}
|
|
694
|
+
|
|
679
695
|
const WS_GLYPH = {
|
|
680
696
|
flex: 'none',
|
|
681
697
|
width: '16px',
|
|
@@ -817,6 +833,19 @@ window.__ModuleLoader__.load({
|
|
|
817
833
|
* written to the Host and renaming a workspace is enough to move it between
|
|
818
834
|
* folders — the same idea as the reference plugin, without its "/" toggle.
|
|
819
835
|
*/
|
|
836
|
+
/**
|
|
837
|
+
* The title a workspace needs to sit under `folder`: its own name moved behind the
|
|
838
|
+
* folder prefix, with any previous prefix replaced rather than stacked.
|
|
839
|
+
*/
|
|
840
|
+
function fileUnder(label, folder) {
|
|
841
|
+
const name = String(label || '').trim()
|
|
842
|
+
const target = String(folder || '').trim()
|
|
843
|
+
if (!name || !target) return name
|
|
844
|
+
const cut = name.lastIndexOf('/')
|
|
845
|
+
const bare = (cut >= 0 ? name.slice(cut + 1) : name).trim()
|
|
846
|
+
return bare ? target + '/' + bare : target
|
|
847
|
+
}
|
|
848
|
+
|
|
820
849
|
function folderKey(workspace) {
|
|
821
850
|
const label = workspaceLabel(workspace)
|
|
822
851
|
const cut = label.lastIndexOf('/')
|
|
@@ -1034,6 +1063,7 @@ window.__ModuleLoader__.load({
|
|
|
1034
1063
|
const [dropping, setDropping] = React.useState(null)
|
|
1035
1064
|
const [look, setLook] = React.useState(() => readAppearance())
|
|
1036
1065
|
const [noteDraft, setNoteDraft] = React.useState('')
|
|
1066
|
+
const [card, setCard] = React.useState(null)
|
|
1037
1067
|
const folded = React.useMemo(() => readFolded(), [])
|
|
1038
1068
|
const [folders, setFolders] = React.useState(folded.folders)
|
|
1039
1069
|
const [switcher, setSwitcher] = React.useState(null)
|
|
@@ -1416,6 +1446,13 @@ window.__ModuleLoader__.load({
|
|
|
1416
1446
|
React.createElement('div', { style: WS_MENU_HINT }, 'Enter saves, Escape cancels'))
|
|
1417
1447
|
: null
|
|
1418
1448
|
|
|
1449
|
+
const noteCard = card
|
|
1450
|
+
? ReactDOM.createPortal(React.createElement('div', {
|
|
1451
|
+
'data-polish-note-card': 'true',
|
|
1452
|
+
style: Object.assign({}, WS_NOTE_CARD, { top: card.top, left: card.left }),
|
|
1453
|
+
}, card.text), document.body)
|
|
1454
|
+
: null
|
|
1455
|
+
|
|
1419
1456
|
const paintMenu = menu && menu.kind === 'paint'
|
|
1420
1457
|
? (() => {
|
|
1421
1458
|
const workspace = menu.workspace
|
|
@@ -1678,8 +1715,31 @@ window.__ModuleLoader__.load({
|
|
|
1678
1715
|
role: 'group',
|
|
1679
1716
|
'aria-label': folder,
|
|
1680
1717
|
title: folded ? 'Expand ' + folder : 'Collapse ' + folder,
|
|
1681
|
-
style: WS_FOLDER_ROW,
|
|
1718
|
+
style: Object.assign({}, WS_FOLDER_ROW, {
|
|
1719
|
+
background: dropping === 'folder:' + folder
|
|
1720
|
+
? 'var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.05))'
|
|
1721
|
+
: undefined,
|
|
1722
|
+
}),
|
|
1682
1723
|
onClick: () => setFolders((prev) => Object.assign({}, prev, { [folder]: prev[folder] !== true })),
|
|
1724
|
+
onDragOver: (event) => {
|
|
1725
|
+
if (!drag || drag.kind !== 'workspace') return
|
|
1726
|
+
if (folderOf(rows.find((entry) => entry.workspace.workspaceId === drag.id)?.workspace) === folder) return
|
|
1727
|
+
event.preventDefault()
|
|
1728
|
+
setDropping('folder:' + folder)
|
|
1729
|
+
},
|
|
1730
|
+
onDragLeave: () => setDropping(null),
|
|
1731
|
+
onDrop: (event) => {
|
|
1732
|
+
event.preventDefault()
|
|
1733
|
+
setDropping(null)
|
|
1734
|
+
if (!drag || drag.kind !== 'workspace') return
|
|
1735
|
+
const moving = rows.find((entry) => entry.workspace.workspaceId === drag.id)
|
|
1736
|
+
if (!moving || folderOf(moving.workspace) === folder) return
|
|
1737
|
+
const title = fileUnder(workspaceLabel(moving.workspace), folder)
|
|
1738
|
+
Promise.resolve()
|
|
1739
|
+
.then(() => services.renameWorkspace(moving.workspace.workspaceId, title))
|
|
1740
|
+
.then(() => setNotice('Filed under ' + folder + '.'))
|
|
1741
|
+
.catch(() => setNotice('Could not file that workspace.'))
|
|
1742
|
+
},
|
|
1683
1743
|
},
|
|
1684
1744
|
React.createElement('span', { 'aria-hidden': 'true' }, folded ? '›' : '⌄'),
|
|
1685
1745
|
React.createElement('span', { style: WS_TITLE }, folder),
|
|
@@ -1713,8 +1773,14 @@ window.__ModuleLoader__.load({
|
|
|
1713
1773
|
onClick: () => toggleWorkspace(workspace.workspaceId),
|
|
1714
1774
|
onContextMenu: (event) => openWorkspaceMenu(event, workspace),
|
|
1715
1775
|
title: looks.note || undefined,
|
|
1716
|
-
onMouseEnter: () =>
|
|
1717
|
-
|
|
1776
|
+
onMouseEnter: (event) => {
|
|
1777
|
+
setHover('workspace:' + workspace.workspaceId)
|
|
1778
|
+
const note = appearanceOf(look, workspace.workspaceId).note
|
|
1779
|
+
if (!note) return
|
|
1780
|
+
const box = event.currentTarget.getBoundingClientRect()
|
|
1781
|
+
setCard({ text: note, top: box.bottom + 6, left: Math.max(8, box.left) })
|
|
1782
|
+
},
|
|
1783
|
+
onMouseLeave: () => { setHover(null); setCard(null) },
|
|
1718
1784
|
onDragStart: () => setDrag({ kind: 'workspace', id: workspace.workspaceId }),
|
|
1719
1785
|
onDragOver: (event) => {
|
|
1720
1786
|
if (!drag || drag.kind !== 'workspace' || drag.id === workspace.workspaceId) return
|
|
@@ -1810,6 +1876,7 @@ window.__ModuleLoader__.load({
|
|
|
1810
1876
|
sessionMenu,
|
|
1811
1877
|
glyphMenu,
|
|
1812
1878
|
noteMenu,
|
|
1879
|
+
noteCard,
|
|
1813
1880
|
archivedMenu,
|
|
1814
1881
|
paintMenu,
|
|
1815
1882
|
workspaceMenu)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aryacode/dsh-aryacode-polish",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.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",
|