0.14.0: multi-folder media drawer
- Clipart store holds an array of root folders instead of a single handle, plus an activeHandleIndex for the in-folder view. Getters: activeHandle, inOverview, hasAnyFolder, canGoBack, folderName. - Actions: addFolder (appends a root), enterFolder, exitFolder, removeFolder. Single-folder installs auto-drill into the sole root and behave exactly like the pre-refactor drawer; adding a 2nd+ folder pops back to the root overview. - IDB persistence migrated from the 'clipartDir' single-handle key to a 'clipartDirs' array. Legacy records are migrated on first load. saveClipartFolders unwraps Pinia proxies (toRaw per element) so IDB's structured clone accepts the payload. - ClipartItem union gained a 'folder' kind so root tiles render as first-class media items. listClipart emits nested directories too, but the drawer keeps drill-down one level deep for now. - ClipartDrawer header: three equally-sized .header-btn chips — back (only when canGoBack), refresh (when viewing a folder), and a new `+` (when any folder is attached). No more big 'Choose folder' button — empty state is a centred 96px dashed + with a wrapped hint. - Folder tiles carry a hover `×` to remove a root from the library. - DocumentSettings media tab lists all configured folders with a per- folder remove action; primary button is now 'Add folder'. - Pinia store now calls acceptHMRUpdate so Vite HMR actually swaps the store definition between reloads instead of leaving the first- load state shape behind. - Tests: store actions (addFolder / enterFolder / exitFolder / remove / IDB round-trip), drawer UI (centred + empty state, overview with folder tiles + click-to-enter, back visibility, single-root hides back, header + button triggers addFolder). Tests isolated with try/finally so a failing store assertion can't leak error state into subsequent drawer tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
8aa91fc27b
commit
9fe86b62b9
9 files changed
+698
-142
No files matched your search
@@ -93,28 +93,35 @@ function applyTheme(t: Theme) {
|
||||
<h3>{{ t('settings.tab.clipart') }}</h3>
|
||||
<div class="clipart-row">
|
||||
<div class="clipart-label">{{ t('clipart.folderLabel') }}</div>
|
||||
<div class="clipart-value">
|
||||
<ul v-if="clipart.hasAnyFolder" class="clipart-folder-list">
|
||||
<li
|
||||
v-for="(h, i) in clipart.handles"
|
||||
:key="h.name + i"
|
||||
class="clipart-value"
|
||||
>
|
||||
<PhFolder :size="13" />
|
||||
<span class="clipart-folder-name">{{ h.name }}</span>
|
||||
<button
|
||||
class="ghost-btn small"
|
||||
v-tooltip="t('clipart.removeFolder')"
|
||||
@click="clipart.removeFolder(i)"
|
||||
>
|
||||
{{ t('clipart.clearFolder') }}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
<div v-else class="clipart-value">
|
||||
<PhFolder :size="13" />
|
||||
<span v-if="clipart.folderName" class="clipart-folder-name">
|
||||
{{ clipart.folderName }}
|
||||
</span>
|
||||
<span v-else class="clipart-folder-empty">{{ t('clipart.noFolder') }}</span>
|
||||
<span class="clipart-folder-empty">{{ t('clipart.noFolder') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clipart-actions">
|
||||
<button
|
||||
class="primary-btn"
|
||||
:disabled="!clipart.supported"
|
||||
@click="clipart.pickFolder()"
|
||||
@click="clipart.addFolder()"
|
||||
>
|
||||
{{ t('clipart.chooseFolder') }}
|
||||
</button>
|
||||
<button
|
||||
v-if="clipart.handle"
|
||||
class="ghost-btn"
|
||||
@click="clipart.clearFolder()"
|
||||
>
|
||||
{{ t('clipart.clearFolder') }}
|
||||
{{ t('clipart.addFolder') }}
|
||||
</button>
|
||||
</div>
|
||||
<p v-if="!clipart.supported" class="error-line">
|
||||
@@ -551,6 +558,7 @@ input[type='number'] {
|
||||
}
|
||||
|
||||
.clipart-folder-name {
|
||||
flex: 1 1 auto;
|
||||
font-variant-numeric: tabular-nums;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
@@ -562,6 +570,20 @@ input[type='number'] {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.clipart-folder-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.ghost-btn.small {
|
||||
padding: 2px 8px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.clipart-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
Reference in new issue
Block a user