@seorii/tiptap 0.3.0-next.9 → 0.4.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/i18n/index.d.ts +106 -6
- package/dist/i18n/index.js +56 -11
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/plugin/command/emoji.d.ts +3 -17
- package/dist/plugin/command/emoji.js +51 -24
- package/dist/plugin/command/stores.svelte.d.ts +52 -0
- package/dist/plugin/command/stores.svelte.js +69 -0
- package/dist/plugin/command/suggest.d.ts +6 -19
- package/dist/plugin/command/suggest.js +149 -49
- package/dist/plugin/embed.d.ts +2 -2
- package/dist/plugin/embed.js +6 -2
- package/dist/plugin/iframe.js +1 -1
- package/dist/plugin/image/dragdrop.d.ts +2 -0
- package/dist/plugin/image/dragdrop.js +126 -15
- package/dist/plugin/image/index.js +4 -3
- package/dist/plugin/indent.js +0 -1
- package/dist/plugin/orderedlist/index.d.ts +1 -1
- package/dist/plugin/orderedlist/index.js +1 -1
- package/dist/plugin/orderedlist/{korean.scss → korean.css} +2 -2
- package/dist/plugin/resize/index.d.ts +8 -0
- package/dist/plugin/resize/index.js +454 -0
- package/dist/plugin/table/index.d.ts +1 -1
- package/dist/plugin/table/index.js +19 -11
- package/dist/plugin/table/style/{cell.scss → cell.css} +6 -5
- package/dist/plugin/table/style/{grip.scss → grip.css} +14 -19
- package/dist/plugin/table/style/resize.css +28 -0
- package/dist/plugin/table/style/{table.scss → table.css} +15 -17
- package/dist/plugin/table/style.css +4 -0
- package/dist/plugin/table/tableCell/index.js +2 -4
- package/dist/plugin/table/tableHeader/index.js +1 -2
- package/dist/plugin/upload/skeleton/UploadSkeleton.svelte +97 -0
- package/dist/plugin/upload/skeleton/UploadSkeleton.svelte.d.ts +5 -0
- package/dist/plugin/upload/skeleton/index.d.ts +30 -0
- package/dist/plugin/upload/skeleton/index.js +147 -0
- package/dist/plugin/youtube.js +1 -1
- package/dist/tiptap/Bubble.svelte +231 -92
- package/dist/tiptap/Bubble.svelte.d.ts +9 -6
- package/dist/tiptap/Command.svelte +160 -158
- package/dist/tiptap/Command.svelte.d.ts +2 -3
- package/dist/tiptap/Floating.svelte +51 -24
- package/dist/tiptap/Floating.svelte.d.ts +1 -0
- package/dist/tiptap/TipTap.svelte +302 -140
- package/dist/tiptap/TipTap.svelte.d.ts +10 -3
- package/dist/tiptap/ToolbarButton.svelte +30 -10
- package/dist/tiptap/ToolbarButton.svelte.d.ts +10 -6
- package/dist/tiptap/setMath.d.ts +2 -1
- package/dist/tiptap/setMath.js +74 -12
- package/dist/tiptap/tiptap.d.ts +9 -1
- package/dist/tiptap/tiptap.js +172 -16
- package/package.json +63 -57
- package/dist/plugin/command/stores.d.ts +0 -13
- package/dist/plugin/command/stores.js +0 -7
- package/dist/plugin/table/style/resize.scss +0 -26
- package/dist/plugin/table/style.scss +0 -4
|
@@ -1,131 +1,128 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Button, IconButton, Input, List, OneLine, TwoLine } from 'nunui';
|
|
3
|
-
import { getContext } from 'svelte';
|
|
3
|
+
import { getContext, tick } from 'svelte';
|
|
4
4
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
} from '../plugin/command/stores';
|
|
5
|
+
isSlashGroup,
|
|
6
|
+
isSlashItem,
|
|
7
|
+
slashState,
|
|
8
|
+
type SlashGroup,
|
|
9
|
+
type SlashItem
|
|
10
|
+
} from '../plugin/command/stores.svelte';
|
|
12
11
|
import { fly, slide } from 'svelte/transition';
|
|
13
12
|
import { quartOut } from 'svelte/easing';
|
|
14
|
-
import
|
|
13
|
+
import defaultI18n, { I18N_CONTEXT, type I18nTranslate } from '../i18n';
|
|
15
14
|
|
|
16
15
|
const editor = getContext<{ v: any }>('editor');
|
|
16
|
+
const i18nFromContext = getContext<I18nTranslate | undefined>(I18N_CONTEXT);
|
|
17
|
+
const i18n: I18nTranslate = (...args) =>
|
|
18
|
+
i18nFromContext ? i18nFromContext(...args) : defaultI18n(...args);
|
|
17
19
|
const tiptap = $derived(editor.v);
|
|
18
|
-
let { selectedIndex = 0 } = $props();
|
|
19
20
|
|
|
20
|
-
let height = $state(0)
|
|
21
|
-
elements = $state([]);
|
|
21
|
+
let height = $state(0);
|
|
22
22
|
let input = $state(''),
|
|
23
|
-
focus
|
|
23
|
+
focus = $state<HTMLInputElement | HTMLTextAreaElement | undefined>(undefined);
|
|
24
|
+
let menu = $state<HTMLElement | null>(null);
|
|
25
|
+
|
|
26
|
+
const emojiItems = $derived(slashState.items.filter(isSlashItem));
|
|
27
|
+
const groupedItems = $derived(slashState.items.filter(isSlashGroup));
|
|
28
|
+
|
|
29
|
+
function runCommand(item: SlashItem | undefined) {
|
|
30
|
+
if (!item) return;
|
|
31
|
+
const { editor, range } = slashState.props;
|
|
32
|
+
if (!editor || !range) return;
|
|
33
|
+
|
|
34
|
+
item.command({ editor, range });
|
|
35
|
+
setTimeout(() => tiptap?.commands?.focus?.());
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function runDetailCommand() {
|
|
39
|
+
const detail = slashState.detail;
|
|
40
|
+
if (!detail || detail === 'emoji') return;
|
|
41
|
+
|
|
42
|
+
slashState.selection?.();
|
|
43
|
+
detail.handler(input);
|
|
44
|
+
}
|
|
24
45
|
|
|
25
46
|
$effect(() => {
|
|
26
|
-
if (
|
|
47
|
+
if (slashState.visible) input = '';
|
|
27
48
|
});
|
|
28
49
|
$effect(() => {
|
|
29
50
|
focus;
|
|
30
51
|
setTimeout(() => focus?.focus?.(), 100);
|
|
31
52
|
});
|
|
53
|
+
|
|
54
|
+
$effect(() => {
|
|
55
|
+
if (!slashState.visible) return;
|
|
56
|
+
const detail = slashState.detail;
|
|
57
|
+
if (detail && detail !== 'emoji') return;
|
|
58
|
+
|
|
59
|
+
const selectedIndex = slashState.selectedIndex;
|
|
60
|
+
void tick().then(() => {
|
|
61
|
+
const target = menu?.querySelector<HTMLElement>(`[data-slash-index="${selectedIndex}"]`);
|
|
62
|
+
target?.scrollIntoView({ block: 'nearest' });
|
|
63
|
+
});
|
|
64
|
+
});
|
|
32
65
|
</script>
|
|
33
66
|
|
|
34
67
|
<svelte:window bind:innerHeight={height} />
|
|
35
68
|
|
|
36
|
-
{#if
|
|
37
|
-
|
|
69
|
+
{#if slashState.visible}
|
|
70
|
+
<!-- svelte-ignore a11y_click_events_have_key_events, a11y_no_static_element_interactions -->
|
|
71
|
+
<div class="scrim" onclick={() => (slashState.visible = false)}></div>
|
|
38
72
|
<main
|
|
39
|
-
|
|
73
|
+
bind:this={menu}
|
|
74
|
+
style="left: {slashState.location.x}px; top: {slashState.location.y +
|
|
75
|
+
slashState.location.height +
|
|
76
|
+
384 >
|
|
40
77
|
height
|
|
41
|
-
?
|
|
42
|
-
:
|
|
78
|
+
? slashState.location.y - slashState.location.height - 384
|
|
79
|
+
: slashState.location.y + slashState.location.height}px;"
|
|
43
80
|
transition:fly={{ y: 10, duration: 200, easing: quartOut }}
|
|
44
81
|
>
|
|
45
|
-
{#if
|
|
82
|
+
{#if slashState.detail === 'emoji'}
|
|
46
83
|
<div class="list">
|
|
47
84
|
<List>
|
|
48
|
-
{#each
|
|
49
|
-
<div transition:slide={{ duration: 400, easing: quartOut }}>
|
|
85
|
+
{#each emojiItems as item, i (item.title)}
|
|
86
|
+
<div data-slash-index={i} transition:slide={{ duration: 400, easing: quartOut }}>
|
|
50
87
|
<OneLine
|
|
51
|
-
onclick={() =>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}}
|
|
55
|
-
bind:this={elements[i]}
|
|
56
|
-
{title}
|
|
57
|
-
active={selectedIndex === i}
|
|
88
|
+
onclick={() => runCommand(item)}
|
|
89
|
+
title={item.title}
|
|
90
|
+
active={slashState.selectedIndex === i}
|
|
58
91
|
/>
|
|
59
92
|
</div>
|
|
60
93
|
{/each}
|
|
61
|
-
{#if
|
|
94
|
+
{#if !emojiItems.length}
|
|
62
95
|
<div class="section" transition:slide={{ duration: 400, easing: quartOut }}>
|
|
63
96
|
{i18n('noResult')}
|
|
64
97
|
</div>
|
|
65
98
|
{/if}
|
|
66
99
|
</List>
|
|
67
100
|
</div>
|
|
68
|
-
{:else if
|
|
101
|
+
{:else if slashState.detail}
|
|
69
102
|
<div class="detail">
|
|
70
103
|
<header>
|
|
71
|
-
<IconButton icon="arrow_back" onclick={() => (
|
|
72
|
-
<div class="title">{
|
|
73
|
-
</header>
|
|
74
|
-
<div>
|
|
75
|
-
<Button
|
|
76
|
-
small
|
|
77
|
-
onclick={() => {
|
|
78
|
-
$slashSelection?.();
|
|
79
|
-
$slashDetail.handler(undefined);
|
|
80
|
-
}}>{i18n('auto')}</Button
|
|
81
|
-
>
|
|
82
|
-
{#each ['cpp', 'python', 'java'] as lang}
|
|
83
|
-
<Button
|
|
84
|
-
small
|
|
85
|
-
outlined
|
|
86
|
-
onclick={() => {
|
|
87
|
-
$slashSelection?.();
|
|
88
|
-
$slashDetail.handler(lang);
|
|
89
|
-
}}>{lang}</Button
|
|
90
|
-
>
|
|
91
|
-
{/each}
|
|
92
|
-
</div>
|
|
93
|
-
</div>
|
|
94
|
-
{:else if $slashDetail}
|
|
95
|
-
<div class="detail">
|
|
96
|
-
<header>
|
|
97
|
-
<IconButton icon="arrow_back" onclick={() => ($slashDetail = null)} />
|
|
98
|
-
<div class="title">{$slashDetail.title}</div>
|
|
104
|
+
<IconButton icon="arrow_back" onclick={() => (slashState.detail = null)} />
|
|
105
|
+
<div class="title">{slashState.detail.title}</div>
|
|
99
106
|
</header>
|
|
100
107
|
<Input
|
|
101
|
-
placeholder={
|
|
102
|
-
|
|
108
|
+
placeholder={slashState.detail.placeholder}
|
|
109
|
+
block
|
|
103
110
|
bind:value={input}
|
|
104
111
|
bind:input={focus}
|
|
105
|
-
onsubmit={
|
|
106
|
-
$slashSelection?.();
|
|
107
|
-
$slashDetail.handler(input);
|
|
108
|
-
}}
|
|
112
|
+
onsubmit={runDetailCommand}
|
|
109
113
|
/>
|
|
110
114
|
<footer>
|
|
111
115
|
<Button
|
|
112
|
-
tabindex=
|
|
116
|
+
tabindex={0}
|
|
113
117
|
transparent
|
|
114
118
|
small
|
|
115
119
|
onclick={() => {
|
|
116
120
|
input = '';
|
|
117
|
-
|
|
121
|
+
slashState.detail = null;
|
|
118
122
|
}}
|
|
119
123
|
>{i18n('cancel')}
|
|
120
124
|
</Button>
|
|
121
|
-
<Button
|
|
122
|
-
tabindex="0"
|
|
123
|
-
transparent
|
|
124
|
-
small
|
|
125
|
-
onclick={() => {
|
|
126
|
-
$slashSelection?.();
|
|
127
|
-
$slashDetail.handler(input);
|
|
128
|
-
}}
|
|
125
|
+
<Button tabindex={0} transparent small onclick={runDetailCommand}
|
|
129
126
|
>{i18n('insert')}
|
|
130
127
|
</Button>
|
|
131
128
|
</footer>
|
|
@@ -133,33 +130,32 @@
|
|
|
133
130
|
{:else}
|
|
134
131
|
<div class="list">
|
|
135
132
|
<List>
|
|
136
|
-
{#each
|
|
137
|
-
{@const lastCount =
|
|
133
|
+
{#each groupedItems as group, j (group.section)}
|
|
134
|
+
{@const lastCount = groupedItems
|
|
138
135
|
.slice(0, j)
|
|
139
136
|
.reduce((acc, cur) => acc + cur.list.length, 0)}
|
|
140
137
|
<div class="section" transition:slide={{ duration: 400, easing: quartOut }}>
|
|
141
|
-
{section}
|
|
138
|
+
{group.section}
|
|
142
139
|
</div>
|
|
143
140
|
<div transition:slide={{ duration: 400, easing: quartOut }}>
|
|
144
|
-
{#each list
|
|
145
|
-
<div
|
|
141
|
+
{#each group.list as item, i (item.title)}
|
|
142
|
+
<div
|
|
143
|
+
data-slash-index={i + lastCount}
|
|
144
|
+
transition:slide={{ duration: 400, easing: quartOut }}
|
|
145
|
+
>
|
|
146
146
|
<TwoLine
|
|
147
|
-
onmouseenter={() => (selectedIndex = i + lastCount)}
|
|
148
|
-
onclick={() =>
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
{icon}
|
|
154
|
-
{title}
|
|
155
|
-
subtitle={subtitle || ''}
|
|
156
|
-
active={selectedIndex === i + lastCount}
|
|
147
|
+
onmouseenter={() => (slashState.selectedIndex = i + lastCount)}
|
|
148
|
+
onclick={() => runCommand(item)}
|
|
149
|
+
icon={item.icon}
|
|
150
|
+
title={item.title}
|
|
151
|
+
subtitle={item.subtitle || ''}
|
|
152
|
+
active={slashState.selectedIndex === i + lastCount}
|
|
157
153
|
/>
|
|
158
154
|
</div>
|
|
159
155
|
{/each}
|
|
160
156
|
</div>
|
|
161
157
|
{/each}
|
|
162
|
-
{#if
|
|
158
|
+
{#if !groupedItems.length}
|
|
163
159
|
<div class="section" transition:slide={{ duration: 400, easing: quartOut }}>
|
|
164
160
|
{i18n('noResult')}
|
|
165
161
|
</div>
|
|
@@ -170,70 +166,76 @@
|
|
|
170
166
|
</main>
|
|
171
167
|
{/if}
|
|
172
168
|
|
|
173
|
-
<style
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
169
|
+
<style>
|
|
170
|
+
.scrim {
|
|
171
|
+
position: fixed;
|
|
172
|
+
top: 0;
|
|
173
|
+
left: 0;
|
|
174
|
+
width: 100%;
|
|
175
|
+
height: 100%;
|
|
176
|
+
cursor: default;
|
|
177
|
+
z-index: 0;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
main {
|
|
181
|
+
position: fixed;
|
|
182
|
+
background: var(--surface, #fff);
|
|
183
|
+
width: 220px;
|
|
184
|
+
max-height: 384px;
|
|
185
|
+
border-radius: 4px;
|
|
186
|
+
overflow-y: scroll;
|
|
187
|
+
z-index: 10;
|
|
188
|
+
box-shadow: var(--shadow);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.section {
|
|
192
|
+
padding: 8px 16px;
|
|
193
|
+
font-size: 0.8em;
|
|
194
|
+
font-weight: 300;
|
|
195
|
+
color: var(--on-surface, #000);
|
|
196
|
+
opacity: 0.7;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
.list {
|
|
200
|
+
color: var(--primary-dark7);
|
|
201
|
+
|
|
202
|
+
& :global(.title) {
|
|
203
|
+
font-size: 0.7em !important;
|
|
204
|
+
font-weight: 300 !important;
|
|
205
|
+
margin-bottom: 4px;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
& :global(.subtitle) {
|
|
209
|
+
font-size: 0.8em !important;
|
|
210
|
+
font-weight: 300 !important;
|
|
211
|
+
color: var(--primary-dark1);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.detail {
|
|
216
|
+
font-size: 0.8em;
|
|
217
|
+
padding: 8px;
|
|
218
|
+
display: flex;
|
|
219
|
+
flex-direction: column;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
header {
|
|
223
|
+
display: flex;
|
|
224
|
+
align-items: center;
|
|
225
|
+
margin-bottom: 6px;
|
|
226
|
+
|
|
227
|
+
& > :global(*) {
|
|
228
|
+
margin-right: 8px;
|
|
229
|
+
|
|
230
|
+
&:last-child {
|
|
231
|
+
margin-right: 0;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
footer {
|
|
237
|
+
margin-top: 0.6em;
|
|
238
|
+
display: flex;
|
|
239
|
+
justify-content: flex-end;
|
|
240
|
+
}
|
|
241
|
+
</style>
|
|
@@ -2,11 +2,42 @@
|
|
|
2
2
|
import { FloatingMenu } from 'svelte-tiptap';
|
|
3
3
|
import { getContext } from 'svelte';
|
|
4
4
|
import { IconButton, List, OneLine, Paper } from 'nunui';
|
|
5
|
+
import type { CommandProps } from '@tiptap/core';
|
|
6
|
+
import { NodeSelection } from '@tiptap/pm/state';
|
|
5
7
|
import ToolbarButton from './ToolbarButton.svelte';
|
|
6
|
-
import
|
|
8
|
+
import defaultI18n, { I18N_CONTEXT, type I18nTranslate } from '../i18n';
|
|
7
9
|
|
|
8
10
|
const editor = getContext<{ v: any }>('editor');
|
|
11
|
+
const i18nFromContext = getContext<I18nTranslate | undefined>(I18N_CONTEXT);
|
|
12
|
+
const i18n: I18nTranslate = (...args) =>
|
|
13
|
+
i18nFromContext ? i18nFromContext(...args) : defaultI18n(...args);
|
|
9
14
|
const tiptap = $derived(editor.v);
|
|
15
|
+
|
|
16
|
+
function insertMathInline() {
|
|
17
|
+
tiptap
|
|
18
|
+
.chain()
|
|
19
|
+
.focus()
|
|
20
|
+
.command(({ state, tr, dispatch }: CommandProps) => {
|
|
21
|
+
const { math_inline: mathInline } = state.schema.nodes;
|
|
22
|
+
if (!mathInline) return false;
|
|
23
|
+
|
|
24
|
+
const fromSelection = state.selection.$from;
|
|
25
|
+
const index = fromSelection.index();
|
|
26
|
+
if (!fromSelection.parent.canReplaceWith(index, index, mathInline)) return false;
|
|
27
|
+
|
|
28
|
+
const insertedPosition = fromSelection.pos;
|
|
29
|
+
const mathNode = mathInline.create({});
|
|
30
|
+
const nextTr = tr.replaceSelectionWith(mathNode);
|
|
31
|
+
nextTr.setSelection(NodeSelection.create(nextTr.doc, insertedPosition));
|
|
32
|
+
dispatch?.(nextTr);
|
|
33
|
+
return true;
|
|
34
|
+
})
|
|
35
|
+
.run();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function insertCodeBlock() {
|
|
39
|
+
tiptap.chain().focus().setCodeBlock({ language: null }).run();
|
|
40
|
+
}
|
|
10
41
|
</script>
|
|
11
42
|
|
|
12
43
|
{#if tiptap}
|
|
@@ -16,7 +47,7 @@
|
|
|
16
47
|
<span>
|
|
17
48
|
{i18n('newLineInfo')}
|
|
18
49
|
</span>
|
|
19
|
-
<Paper bl hover
|
|
50
|
+
<Paper bl hover style="width: 160px">
|
|
20
51
|
{#snippet target()}
|
|
21
52
|
<IconButton size="1.2em" icon="text_fields" />
|
|
22
53
|
{/snippet}
|
|
@@ -52,32 +83,28 @@
|
|
|
52
83
|
<ToolbarButton
|
|
53
84
|
icon="functions"
|
|
54
85
|
handler={() => {
|
|
55
|
-
|
|
56
|
-
tiptap
|
|
57
|
-
.chain()
|
|
58
|
-
.focus()
|
|
59
|
-
.insertContent({
|
|
60
|
-
type: 'math_inline'
|
|
61
|
-
})
|
|
62
|
-
.insertContent(' ')
|
|
63
|
-
.run();
|
|
86
|
+
insertMathInline();
|
|
64
87
|
}}
|
|
65
88
|
/>
|
|
66
|
-
<ToolbarButton icon="code"
|
|
89
|
+
<ToolbarButton icon="code" handler={insertCodeBlock} />
|
|
67
90
|
</main>
|
|
68
91
|
</FloatingMenu>
|
|
69
92
|
{/if}
|
|
70
93
|
|
|
71
|
-
<style>
|
|
72
|
-
|
|
73
|
-
|
|
94
|
+
<style>
|
|
95
|
+
span {
|
|
96
|
+
opacity: 0.6;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
main {
|
|
100
|
+
display: flex;
|
|
101
|
+
flex-wrap: wrap;
|
|
102
|
+
width: max-content;
|
|
103
|
+
align-items: center;
|
|
104
|
+
position: relative;
|
|
74
105
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
main > :global(*) {
|
|
82
|
-
margin-right: 4px;
|
|
83
|
-
}</style>
|
|
106
|
+
& > :global(*) {
|
|
107
|
+
margin-right: 4px;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
</style>
|