rimecms 1.0.1 → 1.1.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/dist/core/i18n/en/fields.d.ts +1 -1
- package/dist/core/i18n/en/fields.js +1 -1
- package/dist/core/i18n/fr/fields.d.ts +1 -1
- package/dist/core/i18n/fr/fields.js +1 -1
- package/dist/fields/blocks/component/AddBlockButton.svelte +1 -1
- package/dist/fields/blocks/component/Block.svelte +4 -5
- package/dist/fields/blocks/component/Blocks.svelte +17 -13
- package/dist/fields/blocks/component/focus/BlocksFocus.svelte +52 -64
- package/dist/fields/blocks/component/focus/DefaultRender.svelte +108 -0
- package/dist/fields/blocks/component/focus/{RenderPlaceholder.svelte.d.ts → DefaultRender.svelte.d.ts} +3 -3
- package/dist/fields/blocks/component/focus/Inspector.svelte +160 -0
- package/dist/fields/blocks/component/focus/Inspector.svelte.d.ts +7 -0
- package/dist/fields/blocks/component/focus/Layers.svelte +16 -3
- package/dist/fields/blocks/component/focus/LayersList.svelte +28 -11
- package/dist/fields/blocks/component/focus/LayersList.svelte.d.ts +2 -0
- package/dist/fields/blocks/component/focus/Palette.svelte +3 -3
- package/dist/fields/blocks/component/focus/Renders.svelte +66 -15
- package/dist/fields/blocks/component/focus/Renders.svelte.d.ts +5 -1
- package/dist/fields/blocks/component/focus/StagePlaceholder.svelte +1 -4
- package/dist/fields/blocks/component/focus/focus.svelte.d.ts +26 -12
- package/dist/fields/blocks/component/focus/focus.svelte.js +114 -57
- package/dist/fields/blocks/component/picker/BlockTile.svelte +3 -5
- package/dist/fields/combobox/component/ComboBox.svelte +1 -1
- package/dist/fields/combobox/component/combobox.css +1 -1
- package/dist/fields/date/component/Date.svelte +1 -1
- package/dist/fields/group/component/Group.svelte +4 -4
- package/dist/fields/link/component/Link.svelte +1 -1
- package/dist/fields/link/component/RessourceInput.svelte +2 -2
- package/dist/fields/number/component/Number.svelte +1 -1
- package/dist/fields/relation/component/Cell.svelte +3 -1
- package/dist/fields/relation/component/RelationInline.svelte +50 -19
- package/dist/fields/relation/component/default/Default.svelte +3 -3
- package/dist/fields/relation/component/upload/Browse.svelte +2 -2
- package/dist/fields/relation/component/upload/Upload.svelte +2 -2
- package/dist/fields/rich-text/component/bubble-menu/bubble-menu.css +1 -1
- package/dist/fields/rich-text/component/bubble-menu/node-selector/node-selector.css +1 -1
- package/dist/fields/rich-text/core/features/link/component/link-selector.svelte +2 -2
- package/dist/fields/rich-text/core/features/resource/resource.svelte +1 -1
- package/dist/fields/rich-text/core/features/upload/upload.svelte +1 -1
- package/dist/fields/select/component/Select.svelte +2 -2
- package/dist/fields/text/component/TextInline.svelte +113 -0
- package/dist/fields/text/component/TextInline.svelte.d.ts +14 -0
- package/dist/fields/textarea/component/TextArea.svelte +1 -1
- package/dist/fields/tree/component/TreeBlock.svelte +4 -4
- package/dist/panel/components/fields/Error.svelte +1 -1
- package/dist/panel/components/fields/FieldsPreview.svelte +1 -1
- package/dist/panel/components/fields/FieldsPreviewTrigger.svelte +1 -1
- package/dist/panel/components/fields/Hint.svelte +1 -1
- package/dist/panel/components/fields/setting.css +6 -6
- package/dist/panel/components/sections/auth/AuthForm.svelte +2 -2
- package/dist/panel/components/sections/collection/Avatar.svelte +1 -1
- package/dist/panel/components/sections/collection/bulk-upload/FileDrop.svelte +1 -1
- package/dist/panel/components/sections/collection/bulk-upload/PageDrop.svelte +3 -3
- package/dist/panel/components/sections/collection/bulk-upload/UploadProgress.svelte +1 -1
- package/dist/panel/components/sections/collection/folder/Folder.svelte +1 -1
- package/dist/panel/components/sections/collection/folder/FolderWithActions.svelte +2 -2
- package/dist/panel/components/sections/collection/grid/grid-item/GridItem.svelte +1 -1
- package/dist/panel/components/sections/collection/header/DisplayMode.svelte +1 -2
- package/dist/panel/components/sections/collection/list/CollectionList.svelte +2 -2
- package/dist/panel/components/sections/collection/list/header/Header.svelte +1 -1
- package/dist/panel/components/sections/collection/list/row/Row.svelte +1 -1
- package/dist/panel/components/sections/collection/tree/CollectionTree.svelte +1 -1
- package/dist/panel/components/sections/collection/tree/CollectionTreeNode.svelte +1 -1
- package/dist/panel/components/sections/collection/upload-thumb-cell/UploadThumbCell.svelte +1 -1
- package/dist/panel/components/sections/commands/CommandButton.svelte +1 -1
- package/dist/panel/components/sections/document/AuthAPIKeyDialog.svelte +1 -1
- package/dist/panel/components/sections/document/AuthFooter.svelte +2 -2
- package/dist/panel/components/sections/document/AutoSaveBanner.svelte +2 -2
- package/dist/panel/components/sections/document/ButtonStatus.svelte +1 -1
- package/dist/panel/components/sections/document/ChangeSlugDialog.svelte +1 -1
- package/dist/panel/components/sections/document/DocumentChildren.svelte +2 -2
- package/dist/panel/components/sections/document/upload-header/UploadHeader.svelte +2 -2
- package/dist/panel/components/sections/document/upload-header/drop-zone/DropZone.svelte +1 -1
- package/dist/panel/components/sections/live/LiveFloatingUI.svelte +2 -2
- package/dist/panel/components/ui/breadcrumb/BreadCrumb.svelte +1 -1
- package/dist/panel/components/ui/button/button.svelte +3 -4
- package/dist/panel/components/ui/card/card.svelte +2 -2
- package/dist/panel/components/ui/card-document/card-document.svelte +2 -2
- package/dist/panel/components/ui/card-resource/card-resource.svelte +2 -2
- package/dist/panel/components/ui/command/command-input.svelte +1 -1
- package/dist/panel/components/ui/context-menu/context-menu.css +1 -1
- package/dist/panel/components/ui/dialog/dialog-content.css +1 -1
- package/dist/panel/components/ui/dropdown-menu/dropdown-menu-checkbox-item.svelte +1 -1
- package/dist/panel/components/ui/dropdown-menu/dropdown-menu-content.css +1 -1
- package/dist/panel/components/ui/input/input.svelte +1 -1
- package/dist/panel/components/ui/nav/Nav.svelte +2 -3
- package/dist/panel/components/ui/nav/NavGroup.svelte +1 -1
- package/dist/panel/components/ui/nav/NavItemButton.svelte +1 -1
- package/dist/panel/components/ui/nav/UserButton.svelte +1 -1
- package/dist/panel/components/ui/page-header/PageHeader.svelte +1 -1
- package/dist/panel/components/ui/popover/popover-content.css +1 -1
- package/dist/panel/components/ui/radio-row-group/radio-row-group.css +0 -1
- package/dist/panel/components/ui/sheet/sheet.css +1 -1
- package/dist/panel/components/ui/sonner/sonner.css +1 -1
- package/dist/panel/components/ui/switch/switch.css +0 -2
- package/dist/panel/components/ui/tabs/tabs.css +2 -1
- package/dist/panel/components/ui/tag/tag.svelte +1 -1
- package/dist/panel/components/ui/tree/tree-rows.css +3 -3
- package/dist/panel/index.d.ts +2 -1
- package/dist/panel/index.js +2 -1
- package/dist/panel/pages/auth/forgot-password/ForgotPassword.svelte +1 -1
- package/dist/panel/pages/dashboard/Dashboard.svelte +1 -1
- package/dist/panel/pages/dashboard/DashboardCard.svelte +2 -2
- package/dist/panel/pages/dashboard/DashboardCollection.svelte +1 -1
- package/dist/panel/pages/dashboard/DashboardRow.svelte +1 -1
- package/dist/panel/style/index.css +13 -37
- package/dist/panel/style/mixins/index.css +1 -1
- package/dist/panel/style/palette.css +3 -3
- package/dist/panel/style/scheme.css +10 -34
- package/package.json +1 -1
- package/dist/fields/blocks/component/focus/RenderPlaceholder.svelte +0 -77
- package/dist/fields/blocks/component/focus/Stage.svelte +0 -190
- package/dist/fields/blocks/component/focus/Stage.svelte.d.ts +0 -8
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { getFieldListAtPath } from '../../../../core/fields/util.js';
|
|
3
|
+
import { t__ } from '../../../../core/i18n/index.js';
|
|
4
|
+
import RenderFields from '../../../../panel/components/fields/RenderFields.svelte';
|
|
5
|
+
import { Button } from '../../../../panel/components/ui/button/index.js';
|
|
6
|
+
import { withBlockTypes } from '../../../../panel/context/blocks-ops.js';
|
|
7
|
+
import type { DocumentFormContext } from '../../../../panel/context/documentForm.svelte.js';
|
|
8
|
+
import { Focus, ToyBrick } from '@lucide/svelte';
|
|
9
|
+
import { getBlocksFocusContext } from './focus.svelte.js';
|
|
10
|
+
|
|
11
|
+
type Props = { form: DocumentFormContext };
|
|
12
|
+
const { form }: Props = $props();
|
|
13
|
+
|
|
14
|
+
const focus = getBlocksFocusContext()!;
|
|
15
|
+
const row = $derived(focus.currentRow);
|
|
16
|
+
|
|
17
|
+
/** The selected block's fields, but its lists of blocks: those are on the stage already. */
|
|
18
|
+
const rendered = $derived.by(() => {
|
|
19
|
+
if (!row) return null;
|
|
20
|
+
const { fields, path } = getFieldListAtPath(
|
|
21
|
+
withBlockTypes(row.path, form.values),
|
|
22
|
+
form.config.fields
|
|
23
|
+
);
|
|
24
|
+
return { fields: fields.filter((field) => field.type !== 'blocks'), path };
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const countOf = (list: string) => {
|
|
28
|
+
const count = form.blocks.list(list).length;
|
|
29
|
+
return count === 1
|
|
30
|
+
? t__('fields.blocks_count', '1')
|
|
31
|
+
: t__('fields.blocks_count|m|p', String(count));
|
|
32
|
+
};
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
{#if row && rendered}
|
|
36
|
+
{@const Icon = row.config?.icon ?? ToyBrick}
|
|
37
|
+
<!-- The selected block: its head, its fields, then how many blocks each of its lists holds. -->
|
|
38
|
+
<article class="rz-inspector" data-block-path={row.path}>
|
|
39
|
+
<header class="rz-inspector__header">
|
|
40
|
+
<span class="rz-inspector__icon"><Icon size={14} /></span>
|
|
41
|
+
<h3>{row.title}</h3>
|
|
42
|
+
<span class="rz-inspector__path">{row.path}</span>
|
|
43
|
+
{#if row.children.length && !focus.isNarrowedBlock(row.path)}
|
|
44
|
+
<Button
|
|
45
|
+
class="rz-inspector__focus"
|
|
46
|
+
variant="ghost"
|
|
47
|
+
size="sm"
|
|
48
|
+
icon={Focus}
|
|
49
|
+
title={t__('fields.focus_block')}
|
|
50
|
+
aria-label={t__('fields.focus_block')}
|
|
51
|
+
onclick={() => focus.open(row.path)}
|
|
52
|
+
>
|
|
53
|
+
{t__('fields.focus')}
|
|
54
|
+
</Button>
|
|
55
|
+
{/if}
|
|
56
|
+
</header>
|
|
57
|
+
<div class="rz-inspector__fields">
|
|
58
|
+
<RenderFields fields={rendered.fields} path={rendered.path} {form} />
|
|
59
|
+
</div>
|
|
60
|
+
{#if row.children.length}
|
|
61
|
+
<ul class="rz-inspector__lists">
|
|
62
|
+
{#each row.children as child (child.list)}
|
|
63
|
+
<li class="rz-inspector__list">
|
|
64
|
+
<span>{child.label}</span>
|
|
65
|
+
<span class="rz-inspector__count">{countOf(child.list)}</span>
|
|
66
|
+
</li>
|
|
67
|
+
{/each}
|
|
68
|
+
</ul>
|
|
69
|
+
{/if}
|
|
70
|
+
</article>
|
|
71
|
+
{/if}
|
|
72
|
+
|
|
73
|
+
<style>/* A level: its fill, a hairline, and its shadow when it has one. raised has none, float does. */
|
|
74
|
+
|
|
75
|
+
/* A well: an input, a track, a dropzone. Its edge shows on hover. */
|
|
76
|
+
|
|
77
|
+
/* The hover tint, laid over the element's own fill. */
|
|
78
|
+
|
|
79
|
+
/* The picked item of a segmented control. */
|
|
80
|
+
|
|
81
|
+
/* The primary button's face: black on light, white on dark. */
|
|
82
|
+
|
|
83
|
+
/* Keyboard focus on a button, a tab, a link. */
|
|
84
|
+
|
|
85
|
+
/* A focused input: an accent edge and a soft halo. */
|
|
86
|
+
|
|
87
|
+
/* An input with an error. */
|
|
88
|
+
/* The head stays on top of the fields, on the page's own fill. */
|
|
89
|
+
.rz-inspector__header {
|
|
90
|
+
position: sticky;
|
|
91
|
+
top: 0;
|
|
92
|
+
z-index: 1;
|
|
93
|
+
display: flex;
|
|
94
|
+
align-items: center;
|
|
95
|
+
gap: var(--rz-size-2);
|
|
96
|
+
height: calc(11.5 * var(--rz-unit));
|
|
97
|
+
padding-inline: var(--rz-size-3);
|
|
98
|
+
border-bottom: 1px solid var(--rz-border);
|
|
99
|
+
background-color: var(--rz-bg-page);
|
|
100
|
+
|
|
101
|
+
h3 {
|
|
102
|
+
font-variation-settings: 'wght' 500;
|
|
103
|
+
font-weight: 500;
|
|
104
|
+
font-size: var(--rz-text-md);
|
|
105
|
+
white-space: nowrap;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.rz-inspector__icon {
|
|
110
|
+
display: grid;
|
|
111
|
+
place-items: center;
|
|
112
|
+
width: var(--rz-size-6);
|
|
113
|
+
height: var(--rz-size-6);
|
|
114
|
+
flex-shrink: 0;
|
|
115
|
+
border-radius: var(--rz-radius-sm);
|
|
116
|
+
background-color: var(--rz-bg-well);
|
|
117
|
+
color: var(--rz-fg-muted);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.rz-inspector__path {
|
|
121
|
+
min-width: 0;
|
|
122
|
+
font-family: var(--rz-font-mono);
|
|
123
|
+
font-size: var(--rz-text-xs);
|
|
124
|
+
color: var(--rz-fg-subtle);
|
|
125
|
+
overflow: hidden;
|
|
126
|
+
text-overflow: ellipsis;
|
|
127
|
+
white-space: nowrap;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* On the right end of the head. */
|
|
131
|
+
.rz-inspector__header :global(.rz-inspector__focus) {
|
|
132
|
+
flex-shrink: 0;
|
|
133
|
+
margin-left: auto;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.rz-inspector__fields {
|
|
137
|
+
padding-block: var(--rz-size-6);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/* Under the fields, past a hairline: each list and its count, in quiet text. */
|
|
141
|
+
.rz-inspector__lists {
|
|
142
|
+
display: grid;
|
|
143
|
+
gap: var(--rz-size-1-5);
|
|
144
|
+
margin: 0 var(--rz-fields-padding) var(--rz-size-16);
|
|
145
|
+
padding-top: var(--rz-size-4);
|
|
146
|
+
border-top: 1px solid var(--rz-border);
|
|
147
|
+
font-size: var(--rz-text-sm);
|
|
148
|
+
color: var(--rz-fg-muted);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.rz-inspector__list {
|
|
152
|
+
display: flex;
|
|
153
|
+
justify-content: space-between;
|
|
154
|
+
gap: var(--rz-size-2);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.rz-inspector__count {
|
|
158
|
+
color: var(--rz-fg-subtle);
|
|
159
|
+
}
|
|
160
|
+
</style>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DocumentFormContext } from '../../../../panel/context/documentForm.svelte.js';
|
|
2
|
+
type Props = {
|
|
3
|
+
form: DocumentFormContext;
|
|
4
|
+
};
|
|
5
|
+
declare const Inspector: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type Inspector = ReturnType<typeof Inspector>;
|
|
7
|
+
export default Inspector;
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
</header>
|
|
34
34
|
{/if}
|
|
35
35
|
{#if focus.path}
|
|
36
|
-
<!-- The root node: the list
|
|
36
|
+
<!-- The root node: the open list, or the narrowed block. Selected, nothing is. -->
|
|
37
37
|
<button
|
|
38
38
|
type="button"
|
|
39
39
|
class="rz-layers__root"
|
|
@@ -43,11 +43,24 @@
|
|
|
43
43
|
<span class="rz-layers__root-icon"><LayoutList size={13} /></span>
|
|
44
44
|
<span class="rz-layers__root-title">{focus.rootLabel()}</span>
|
|
45
45
|
</button>
|
|
46
|
-
|
|
46
|
+
{#if focus.narrowedRow}
|
|
47
|
+
<!-- Narrowed to a block: the lists it holds, each under its name when there are several. -->
|
|
48
|
+
{@const lists = focus.narrowedRow.children}
|
|
49
|
+
{#each lists as child (child.list)}
|
|
50
|
+
<LayersList
|
|
51
|
+
{form}
|
|
52
|
+
list={child.list}
|
|
53
|
+
depth={1}
|
|
54
|
+
label={lists.length > 1 ? child.label : undefined}
|
|
55
|
+
/>
|
|
56
|
+
{/each}
|
|
57
|
+
{:else}
|
|
58
|
+
<LayersList {form} list={focus.path} depth={1} />
|
|
59
|
+
{/if}
|
|
47
60
|
{/if}
|
|
48
61
|
</div>
|
|
49
62
|
|
|
50
|
-
<style>/* A level: its fill, a hairline, its shadow. raised, float. */
|
|
63
|
+
<style>/* A level: its fill, a hairline, and its shadow when it has one. raised has none, float does. */
|
|
51
64
|
|
|
52
65
|
/* A well: an input, a track, a dropzone. Its edge shows on hover. */
|
|
53
66
|
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
import { getBlocksFocusContext } from './focus.svelte.js';
|
|
9
9
|
import LayersList from './LayersList.svelte';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
/** `label` names the list above it, for a block that holds several. */
|
|
12
|
+
type Props = { form: DocumentFormContext; list: string; depth: number; label?: string };
|
|
13
|
+
const { form, list, depth, label }: Props = $props();
|
|
13
14
|
|
|
14
15
|
const focus = getBlocksFocusContext()!;
|
|
15
16
|
const rows = $derived(focus.rowsOf(list, depth));
|
|
@@ -59,6 +60,9 @@
|
|
|
59
60
|
}
|
|
60
61
|
</script>
|
|
61
62
|
|
|
63
|
+
{#if label}
|
|
64
|
+
<span class="rz-layers__child-label" style:--rz-layers-depth={depth}>{label}</span>
|
|
65
|
+
{/if}
|
|
62
66
|
<ul
|
|
63
67
|
class="rz-layers__list"
|
|
64
68
|
data-list={list}
|
|
@@ -103,8 +107,8 @@
|
|
|
103
107
|
{#if hasError(row.path)}
|
|
104
108
|
<span class="rz-layers__error" aria-label="error"></span>
|
|
105
109
|
{/if}
|
|
106
|
-
{#if
|
|
107
|
-
<!--
|
|
110
|
+
{#if !focus.locked && focus.isSelected(row.path)}
|
|
111
|
+
<!-- The fields are a tab away: this opens it. -->
|
|
108
112
|
<button
|
|
109
113
|
type="button"
|
|
110
114
|
class="rz-layers__edit"
|
|
@@ -123,12 +127,12 @@
|
|
|
123
127
|
{#if row.children.length && !folded}
|
|
124
128
|
{#each row.children as child (child.builder.name)}
|
|
125
129
|
<div class="rz-layers__child">
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
<LayersList
|
|
131
|
+
{form}
|
|
132
|
+
list={child.list}
|
|
133
|
+
depth={depth + 1}
|
|
134
|
+
label={row.children.length > 1 ? child.label : undefined}
|
|
135
|
+
/>
|
|
132
136
|
</div>
|
|
133
137
|
{/each}
|
|
134
138
|
{/if}
|
|
@@ -136,7 +140,7 @@
|
|
|
136
140
|
{/each}
|
|
137
141
|
</ul>
|
|
138
142
|
|
|
139
|
-
<style>/* A level: its fill, a hairline, its shadow. raised, float. */
|
|
143
|
+
<style>/* A level: its fill, a hairline, and its shadow when it has one. raised has none, float does. */
|
|
140
144
|
|
|
141
145
|
/* A well: an input, a track, a dropzone. Its edge shows on hover. */
|
|
142
146
|
|
|
@@ -301,4 +305,17 @@
|
|
|
301
305
|
:global(.rz-layers__item.sortable-ghost > .rz-layers__row) {
|
|
302
306
|
opacity: 0.4;
|
|
303
307
|
}
|
|
308
|
+
|
|
309
|
+
/* A type dragged in from the palette: a row of the layers, its name alone. */
|
|
310
|
+
:global(.rz-layers__list > .rz-palette__item.rz-block-tile) {
|
|
311
|
+
height: var(--rz-size-7);
|
|
312
|
+
padding: 0 0 0 var(--rz-layers-start);
|
|
313
|
+
border-radius: var(--rz-radius-sm);
|
|
314
|
+
justify-content: center;
|
|
315
|
+
}
|
|
316
|
+
:global(
|
|
317
|
+
.rz-layers__list > .rz-palette__item :is(.rz-block-tile__frame, .rz-block-tile__description)
|
|
318
|
+
) {
|
|
319
|
+
display: none;
|
|
320
|
+
}
|
|
304
321
|
</style>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import type { DocumentFormContext } from '../../../../panel/context/documentForm.svelte.js';
|
|
2
2
|
import LayersList from './LayersList.svelte';
|
|
3
|
+
/** `label` names the list above it, for a block that holds several. */
|
|
3
4
|
type Props = {
|
|
4
5
|
form: DocumentFormContext;
|
|
5
6
|
list: string;
|
|
6
7
|
depth: number;
|
|
8
|
+
label?: string;
|
|
7
9
|
};
|
|
8
10
|
declare const LayersList: import("svelte").Component<Props, {}, "">;
|
|
9
11
|
type LayersList = ReturnType<typeof LayersList>;
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
const { form, heading = true }: Props = $props();
|
|
15
15
|
|
|
16
16
|
const focus = getBlocksFocusContext()!;
|
|
17
|
-
/** The block types of the list the next insert goes to
|
|
18
|
-
const list = $derived(focus.
|
|
17
|
+
/** The block types of the list the next insert goes to. */
|
|
18
|
+
const list = $derived(focus.insertList() ?? '');
|
|
19
19
|
const types = $derived(list ? (form.blocks.builder(list)?.get.blocks ?? []) : []);
|
|
20
20
|
|
|
21
21
|
/** Past this many types, a search sits above them. */
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
</div>
|
|
86
86
|
</div>
|
|
87
87
|
|
|
88
|
-
<style>/* A level: its fill, a hairline, its shadow. raised, float. */
|
|
88
|
+
<style>/* A level: its fill, a hairline, and its shadow when it has one. raised has none, float does. */
|
|
89
89
|
|
|
90
90
|
/* A well: an input, a track, a dropzone. Its edge shows on hover. */
|
|
91
91
|
|
|
@@ -3,18 +3,23 @@
|
|
|
3
3
|
import type { DocumentFormContext } from '../../../../panel/context/documentForm.svelte.js';
|
|
4
4
|
import { shiftListPath } from '../../../../panel/context/blocks-ops.js';
|
|
5
5
|
import { useSortable } from '../../../../panel/util/Sortable.js';
|
|
6
|
-
import { ArrowDown, ArrowUp, CopyPlus, Trash2 } from '@lucide/svelte';
|
|
6
|
+
import { ArrowDown, ArrowUp, CopyPlus, Focus, Trash2 } from '@lucide/svelte';
|
|
7
7
|
import type Sortable from 'sortablejs';
|
|
8
|
+
import DefaultRender from './DefaultRender.svelte';
|
|
8
9
|
import { getBlocksFocusContext } from './focus.svelte.js';
|
|
9
|
-
import RenderPlaceholder from './RenderPlaceholder.svelte';
|
|
10
10
|
import Renders from './Renders.svelte';
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
/**
|
|
13
|
+
* `only` narrows the list to the block at that index, focus on one block: it does not move
|
|
14
|
+
* then, its own lists do. `onRemove` asks first when the block holds blocks of its own.
|
|
15
|
+
*/
|
|
16
|
+
type Props = { form: DocumentFormContext; list: string; only?: number; onRemove: () => void };
|
|
17
|
+
const { form, list, only, onRemove }: Props = $props();
|
|
15
18
|
|
|
16
19
|
const focus = getBlocksFocusContext()!;
|
|
17
|
-
const rows = $derived(
|
|
20
|
+
const rows = $derived(
|
|
21
|
+
only === undefined ? focus.rowsOf(list) : focus.rowsOf(list).filter((row) => row.index === only)
|
|
22
|
+
);
|
|
18
23
|
|
|
19
24
|
/**
|
|
20
25
|
* A click selects the block, shows its fields, and stops there; a link inside a render does not
|
|
@@ -46,8 +51,10 @@
|
|
|
46
51
|
|
|
47
52
|
/**
|
|
48
53
|
* The stage is in the same group as the layers: a block drags from one to the other, a type
|
|
49
|
-
* drags in from the palette, and a nested list is a target like any other.
|
|
54
|
+
* drags in from the palette, and a nested list is a target like any other. The stage mounts a
|
|
55
|
+
* list anew when focus moves, so `only` is read once.
|
|
50
56
|
*/
|
|
57
|
+
// svelte-ignore state_referenced_locally
|
|
51
58
|
const { sortable } = useSortable({
|
|
52
59
|
group: {
|
|
53
60
|
name: 'rz-blocks-layers',
|
|
@@ -61,7 +68,7 @@
|
|
|
61
68
|
animation: 150,
|
|
62
69
|
fallbackOnBody: true,
|
|
63
70
|
swapThreshold: 0.65,
|
|
64
|
-
disabled: focus.locked,
|
|
71
|
+
disabled: focus.locked || only !== undefined,
|
|
65
72
|
/** A type dropped from the palette: a new block at the drop index. */
|
|
66
73
|
onAdd: (event: Sortable.SortableEvent) => {
|
|
67
74
|
if (!event.from.classList.contains('rz-palette__list')) return;
|
|
@@ -90,7 +97,7 @@
|
|
|
90
97
|
|
|
91
98
|
<!--
|
|
92
99
|
One list of blocks, one wrapper per block. A block's nested lists are the `nested` snippet its
|
|
93
|
-
render puts where they go; a block without a render is a
|
|
100
|
+
render puts where they go; a block without a render is a row with them under it.
|
|
94
101
|
-->
|
|
95
102
|
<div class="rz-renders" data-list={list} data-empty={rows.length ? undefined : ''} use:sortableList>
|
|
96
103
|
{#each rows as row (row.block.id)}
|
|
@@ -98,12 +105,15 @@
|
|
|
98
105
|
{@const Render = config?.render}
|
|
99
106
|
{#snippet nested(name?: string)}
|
|
100
107
|
{#each row.children.filter((child) => !name || child.builder.name === name) as child (child.builder.name)}
|
|
108
|
+
<!-- All of them at once, and more than one: each under its name. -->
|
|
109
|
+
{#if !name && row.children.length > 1}
|
|
110
|
+
<p class="rz-renders__list-label">{child.label}</p>
|
|
111
|
+
{/if}
|
|
101
112
|
<Renders {form} list={child.list} {onRemove} />
|
|
102
113
|
{/each}
|
|
103
114
|
{/snippet}
|
|
104
115
|
<div
|
|
105
116
|
class="rz-renders__item"
|
|
106
|
-
data-placeholder={config?.render ? null : ''}
|
|
107
117
|
data-path={row.path}
|
|
108
118
|
data-type={row.block.type}
|
|
109
119
|
data-selected={focus.isSelected(row.path) ? '' : undefined}
|
|
@@ -117,7 +127,7 @@
|
|
|
117
127
|
}
|
|
118
128
|
}}
|
|
119
129
|
>
|
|
120
|
-
{#if controlled(row.path)}
|
|
130
|
+
{#if controlled(row.path) && !focus.isNarrowedBlock(row.path)}
|
|
121
131
|
<!-- Above it: move, duplicate, remove. A click on the block already opens its fields. -->
|
|
122
132
|
<div class="rz-renders__toolbar">
|
|
123
133
|
<button
|
|
@@ -139,6 +149,17 @@
|
|
|
139
149
|
<ArrowDown size={14} />
|
|
140
150
|
</button>
|
|
141
151
|
<span class="rz-renders__toolbar-separator" aria-hidden="true"></span>
|
|
152
|
+
{#if row.children.length && focus.path !== row.path}
|
|
153
|
+
<!-- The stage narrowed to this block and what it holds. -->
|
|
154
|
+
<button
|
|
155
|
+
type="button"
|
|
156
|
+
title={t__('fields.focus_block')}
|
|
157
|
+
aria-label={t__('fields.focus_block')}
|
|
158
|
+
onclick={(event) => control(event, () => focus.open(row.path))}
|
|
159
|
+
>
|
|
160
|
+
<Focus size={14} />
|
|
161
|
+
</button>
|
|
162
|
+
{/if}
|
|
142
163
|
<button
|
|
143
164
|
type="button"
|
|
144
165
|
title={t__('common.duplicate')}
|
|
@@ -167,21 +188,21 @@
|
|
|
167
188
|
children={nested}
|
|
168
189
|
/>
|
|
169
190
|
{#snippet failed(error)}
|
|
170
|
-
<
|
|
191
|
+
<DefaultRender {row} {error} children={nested} />
|
|
171
192
|
{/snippet}
|
|
172
193
|
</svelte:boundary>
|
|
173
194
|
{:else}
|
|
174
|
-
<
|
|
195
|
+
<DefaultRender {row} children={nested} />
|
|
175
196
|
{/if}
|
|
176
197
|
</div>
|
|
177
198
|
{:else}
|
|
178
199
|
{#if list === focus.path}
|
|
179
|
-
<p class="rz-renders__empty">{t__('fields.
|
|
200
|
+
<p class="rz-renders__empty">{t__('fields.no_blocks_yet')}</p>
|
|
180
201
|
{/if}
|
|
181
202
|
{/each}
|
|
182
203
|
</div>
|
|
183
204
|
|
|
184
|
-
<style>/* A level: its fill, a hairline, its shadow. raised, float. */
|
|
205
|
+
<style>/* A level: its fill, a hairline, and its shadow when it has one. raised has none, float does. */
|
|
185
206
|
|
|
186
207
|
/* A well: an input, a track, a dropzone. Its edge shows on hover. */
|
|
187
208
|
|
|
@@ -236,6 +257,36 @@
|
|
|
236
257
|
opacity: 0.4;
|
|
237
258
|
}
|
|
238
259
|
|
|
260
|
+
/* A type dragged in from the palette: the row the block will be, not the palette's tile. */
|
|
261
|
+
:global(.rz-renders > .rz-palette__item.rz-block-tile) {
|
|
262
|
+
flex-direction: row;
|
|
263
|
+
align-items: center;
|
|
264
|
+
gap: var(--rz-size-2);
|
|
265
|
+
height: calc(11 * var(--rz-unit));
|
|
266
|
+
padding: 0 var(--rz-size-3);
|
|
267
|
+
border-radius: var(--rz-radius-md);
|
|
268
|
+
color: var(--rz-fg);
|
|
269
|
+
}
|
|
270
|
+
:global(.rz-renders > .rz-palette__item .rz-block-tile__frame) {
|
|
271
|
+
width: var(--rz-size-6);
|
|
272
|
+
flex-shrink: 0;
|
|
273
|
+
aspect-ratio: 1;
|
|
274
|
+
border-radius: var(--rz-radius-sm);
|
|
275
|
+
}
|
|
276
|
+
:global(.rz-renders > .rz-palette__item .rz-block-tile__title) {
|
|
277
|
+
padding-inline: 0;
|
|
278
|
+
}
|
|
279
|
+
:global(.rz-renders > .rz-palette__item .rz-block-tile__description) {
|
|
280
|
+
display: none;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/* The name of a nested list, when a block holds several. */
|
|
284
|
+
.rz-renders__list-label {
|
|
285
|
+
margin-bottom: calc(-1.5 * var(--rz-unit));
|
|
286
|
+
font-size: var(--rz-text-xs);
|
|
287
|
+
color: var(--rz-fg-subtle);
|
|
288
|
+
}
|
|
289
|
+
|
|
239
290
|
/*
|
|
240
291
|
* The selected block's bar: dark, on its top edge at the right, half over the gap above, so it
|
|
241
292
|
* covers little of the block before.
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import type { DocumentFormContext } from '../../../../panel/context/documentForm.svelte.js';
|
|
2
2
|
import Renders from './Renders.svelte';
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* `only` narrows the list to the block at that index, focus on one block: it does not move
|
|
5
|
+
* then, its own lists do. `onRemove` asks first when the block holds blocks of its own.
|
|
6
|
+
*/
|
|
4
7
|
type Props = {
|
|
5
8
|
form: DocumentFormContext;
|
|
6
9
|
list: string;
|
|
10
|
+
only?: number;
|
|
7
11
|
onRemove: () => void;
|
|
8
12
|
};
|
|
9
13
|
declare const Renders: import("svelte").Component<Props, {}, "">;
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
{before}<Kbd keys="/" />{after}
|
|
23
23
|
</button>
|
|
24
24
|
|
|
25
|
-
<style>/* A level: its fill, a hairline, its shadow. raised, float. */
|
|
25
|
+
<style>/* A level: its fill, a hairline, and its shadow when it has one. raised has none, float does. */
|
|
26
26
|
|
|
27
27
|
/* A well: an input, a track, a dropzone. Its edge shows on hover. */
|
|
28
28
|
|
|
@@ -62,8 +62,5 @@
|
|
|
62
62
|
font-size: var(--rz-text-sm);
|
|
63
63
|
vertical-align: text-bottom;
|
|
64
64
|
}
|
|
65
|
-
:global(.rz-kbd__key) {
|
|
66
|
-
background-color: var(--rz-bg-raised);
|
|
67
|
-
}
|
|
68
65
|
}
|
|
69
66
|
</style>
|
|
@@ -2,7 +2,10 @@ import type { GenericBlock } from '../../../../core/prototype/types.js';
|
|
|
2
2
|
import type { BlocksBuilder, BlocksFieldBlock } from '../../index.js';
|
|
3
3
|
import { type BlockAt } from '../../../../panel/context/blocks-ops.js';
|
|
4
4
|
import type { DocumentFormContext } from '../../../../panel/context/documentForm.svelte.js';
|
|
5
|
-
/**
|
|
5
|
+
/**
|
|
6
|
+
* The query parameter that names what focus is open on: a list, `?focus=layout.sections`, or one
|
|
7
|
+
* block and what it holds, `?focus=layout.sections.1`.
|
|
8
|
+
*/
|
|
6
9
|
export declare const FOCUS_PARAM = "focus";
|
|
7
10
|
export type SidebarTab = 'layers' | 'inspector' | 'add';
|
|
8
11
|
/** One step of the way down to the open list: a blocks field, or the block an index names. */
|
|
@@ -33,12 +36,13 @@ export type LayerRow = {
|
|
|
33
36
|
* rows are folded. The document form is the only state it writes to; a page reload with
|
|
34
37
|
* `?focus=` in the address reopens it.
|
|
35
38
|
*
|
|
36
|
-
* The
|
|
37
|
-
*
|
|
39
|
+
* The stage shows the open list, or the one block the path ends on and the lists it holds. The
|
|
40
|
+
* selection is a block, or nothing, which is the root node of the layers.
|
|
38
41
|
*
|
|
39
|
-
* A focus opened from the field rides in `page.state`,
|
|
40
|
-
* button
|
|
41
|
-
* router is not ready for one while the page mounts, and
|
|
42
|
+
* A focus opened from the field rides in `page.state`, one history entry per `open`, so Escape
|
|
43
|
+
* and the back button go up the same levels. One opened by the address has no history entry of
|
|
44
|
+
* its own: the router is not ready for one while the page mounts, and going up rewrites the
|
|
45
|
+
* address instead.
|
|
42
46
|
*/
|
|
43
47
|
export declare function setBlocksFocusContext(form: DocumentFormContext): {
|
|
44
48
|
readonly path: string | null;
|
|
@@ -53,18 +57,23 @@ export declare function setBlocksFocusContext(form: DocumentFormContext): {
|
|
|
53
57
|
picking: boolean;
|
|
54
58
|
/** Opens the picker of types to add; the one picked goes after the selection. */
|
|
55
59
|
pick(): void;
|
|
56
|
-
/** The
|
|
57
|
-
readonly
|
|
60
|
+
/** The block the stage is narrowed to, when the path ends on one. */
|
|
61
|
+
readonly narrowedRow: LayerRow | null;
|
|
58
62
|
/** Nothing selected: the root node, and the whole list on the stage. */
|
|
59
63
|
readonly rootSelected: boolean;
|
|
60
64
|
rootLabel: () => string;
|
|
61
65
|
selectRoot: () => void;
|
|
62
66
|
breadcrumb: () => Crumb[];
|
|
63
67
|
isSelected: (rowPath: string) => boolean;
|
|
68
|
+
isNarrowedBlock: (rowPath: string) => boolean;
|
|
69
|
+
insertList: () => string | null;
|
|
64
70
|
isCollapsed: (rowPath: string) => boolean;
|
|
65
|
-
open: (
|
|
71
|
+
open: (target: string, selected?: string) => void;
|
|
66
72
|
close: () => void;
|
|
73
|
+
up: () => void;
|
|
67
74
|
rowsOf: (list: string, depth?: number) => LayerRow[];
|
|
75
|
+
rootRows: () => LayerRow[];
|
|
76
|
+
homeList: () => string | null;
|
|
68
77
|
allRows: () => LayerRow[];
|
|
69
78
|
visibleRows: () => LayerRow[];
|
|
70
79
|
moveTargets: () => {
|
|
@@ -103,18 +112,23 @@ export declare const getBlocksFocusContext: () => {
|
|
|
103
112
|
picking: boolean;
|
|
104
113
|
/** Opens the picker of types to add; the one picked goes after the selection. */
|
|
105
114
|
pick(): void;
|
|
106
|
-
/** The
|
|
107
|
-
readonly
|
|
115
|
+
/** The block the stage is narrowed to, when the path ends on one. */
|
|
116
|
+
readonly narrowedRow: LayerRow | null;
|
|
108
117
|
/** Nothing selected: the root node, and the whole list on the stage. */
|
|
109
118
|
readonly rootSelected: boolean;
|
|
110
119
|
rootLabel: () => string;
|
|
111
120
|
selectRoot: () => void;
|
|
112
121
|
breadcrumb: () => Crumb[];
|
|
113
122
|
isSelected: (rowPath: string) => boolean;
|
|
123
|
+
isNarrowedBlock: (rowPath: string) => boolean;
|
|
124
|
+
insertList: () => string | null;
|
|
114
125
|
isCollapsed: (rowPath: string) => boolean;
|
|
115
|
-
open: (
|
|
126
|
+
open: (target: string, selected?: string) => void;
|
|
116
127
|
close: () => void;
|
|
128
|
+
up: () => void;
|
|
117
129
|
rowsOf: (list: string, depth?: number) => LayerRow[];
|
|
130
|
+
rootRows: () => LayerRow[];
|
|
131
|
+
homeList: () => string | null;
|
|
118
132
|
allRows: () => LayerRow[];
|
|
119
133
|
visibleRows: () => LayerRow[];
|
|
120
134
|
moveTargets: () => {
|