@lapis-notes/workspace 0.1.0 → 0.2.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 +26 -0
- package/LICENSE.md +3 -3
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/plugin-management/CommunityPluginsSettingsPage.svelte +152 -73
- package/dist/plugin-management/PluginBrowser.svelte +517 -0
- package/dist/plugin-management/PluginBrowser.svelte.d.ts +17 -0
- package/dist/plugin-management/PluginBrowserCard.svelte +230 -0
- package/dist/plugin-management/PluginBrowserCard.svelte.d.ts +9 -0
- package/dist/plugin-management/PluginBrowserDetail.svelte +1168 -0
- package/dist/plugin-management/PluginBrowserDetail.svelte.d.ts +20 -0
- package/dist/plugin-management/PluginBrowserDirectory.svelte +1069 -0
- package/dist/plugin-management/PluginBrowserDirectory.svelte.d.ts +21 -0
- package/dist/plugin-management/PluginBrowserLanding.svelte +341 -0
- package/dist/plugin-management/PluginBrowserLanding.svelte.d.ts +12 -0
- package/dist/plugin-management/PluginRegistryBadge.svelte +41 -0
- package/dist/plugin-management/PluginRegistryBadge.svelte.d.ts +8 -0
- package/dist/plugin-management/PluginRegistryContentState.svelte +80 -0
- package/dist/plugin-management/PluginRegistryContentState.svelte.d.ts +14 -0
- package/dist/plugin-management/PluginRegistryImage.svelte +64 -0
- package/dist/plugin-management/PluginRegistryImage.svelte.d.ts +9 -0
- package/dist/plugin-management/PluginRegistryMedia.svelte +223 -0
- package/dist/plugin-management/PluginRegistryMedia.svelte.d.ts +8 -0
- package/dist/plugin-management/PluginRegistryMediaViewer.svelte +155 -0
- package/dist/plugin-management/PluginRegistryMediaViewer.svelte.d.ts +13 -0
- package/dist/plugin-management/PluginRegistryRow.svelte +120 -0
- package/dist/plugin-management/PluginRegistryRow.svelte.d.ts +25 -0
- package/dist/plugin-management/PluginRegistrySettingsPage.svelte +1009 -512
- package/dist/plugin-management/PluginRegistryStatus.svelte +33 -0
- package/dist/plugin-management/PluginRegistryStatus.svelte.d.ts +8 -0
- package/dist/plugin-management/PluginRegistryToolbar.svelte +159 -0
- package/dist/plugin-management/PluginRegistryToolbar.svelte.d.ts +21 -0
- package/dist/plugin-management/community-presentation/CommunityChip.svelte +229 -0
- package/dist/plugin-management/community-presentation/CommunityChip.svelte.d.ts +4 -0
- package/dist/plugin-management/community-presentation/CommunityMemberAvatar.svelte +42 -0
- package/dist/plugin-management/community-presentation/CommunityMemberAvatar.svelte.d.ts +13 -0
- package/dist/plugin-management/community-presentation/RegistryMediaGallery.svelte +282 -0
- package/dist/plugin-management/community-presentation/RegistryMediaGallery.svelte.d.ts +8 -0
- package/dist/plugin-management/community-presentation/RegistryMediaViewer.css +179 -0
- package/dist/plugin-management/community-presentation/RegistryMediaViewer.svelte +241 -0
- package/dist/plugin-management/community-presentation/RegistryMediaViewer.svelte.d.ts +14 -0
- package/dist/plugin-management/community-presentation/RegistryPluginChangelog.svelte +216 -0
- package/dist/plugin-management/community-presentation/RegistryPluginChangelog.svelte.d.ts +8 -0
- package/dist/plugin-management/community-presentation/RegistryVerifiedImage.svelte +179 -0
- package/dist/plugin-management/community-presentation/RegistryVerifiedImage.svelte.d.ts +15 -0
- package/dist/plugin-management/community-presentation/avatar-model.d.ts +14 -0
- package/dist/plugin-management/community-presentation/avatar-model.js +21 -0
- package/dist/plugin-management/community-presentation/community-member-avatar.css +137 -0
- package/dist/plugin-management/community-presentation/community-typography.css +30 -0
- package/dist/plugin-management/community-presentation/model-adapter.d.ts +54 -0
- package/dist/plugin-management/community-presentation/model-adapter.js +90 -0
- package/dist/plugin-management/community-presentation/model.d.ts +9 -0
- package/dist/plugin-management/community-presentation/model.js +40 -0
- package/dist/plugin-management/community-presentation/props.d.ts +21 -0
- package/dist/plugin-management/community-presentation/props.js +1 -0
- package/dist/plugin-management/community-presentation/registry-filter-icons.d.ts +3 -0
- package/dist/plugin-management/community-presentation/registry-filter-icons.js +70 -0
- package/dist/plugin-management/community-presentation/registry-markdown.d.ts +1 -0
- package/dist/plugin-management/community-presentation/registry-markdown.js +57 -0
- package/dist/plugin-management/community-presentation/registry-plugin-icons.d.ts +2 -0
- package/dist/plugin-management/community-presentation/registry-plugin-icons.js +31 -0
- package/dist/plugin-management/plugin-browser-model.d.ts +43 -0
- package/dist/plugin-management/plugin-browser-model.js +95 -0
- package/dist/plugin-management/plugin-browser-navigation.d.ts +3 -0
- package/dist/plugin-management/plugin-browser-navigation.js +36 -0
- package/dist/plugin-management/plugin-download-stats.d.ts +1 -0
- package/dist/plugin-management/plugin-download-stats.js +15 -0
- package/dist/plugin-management/plugin-management.css +1088 -117
- package/dist/plugin-management/plugin-registry-controller.svelte.d.ts +29 -0
- package/dist/plugin-management/plugin-registry-controller.svelte.js +154 -0
- package/dist/plugin-management/plugin-registry-detail-session.svelte.d.ts +18 -0
- package/dist/plugin-management/plugin-registry-detail-session.svelte.js +106 -0
- package/dist/plugin-management/plugin-registry-detail.d.ts +17 -0
- package/dist/plugin-management/plugin-registry-detail.js +1 -0
- package/dist/plugin-management/plugins-view.svelte.d.ts +40 -0
- package/dist/plugin-management/plugins-view.svelte.js +105 -0
- package/package.json +5 -5
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Component } from "svelte";
|
|
2
|
+
import { type PluginDirectoryState as RegistryDirectoryState } from "./plugin-browser-model";
|
|
3
|
+
import type { PluginCatalogEntry as RegistryCatalogEntry } from "@lapis-notes/api";
|
|
4
|
+
import type { PluginRegistryController } from "./plugin-registry-controller.svelte";
|
|
5
|
+
type $$ComponentProps = {
|
|
6
|
+
registry: PluginRegistryController;
|
|
7
|
+
compact?: boolean;
|
|
8
|
+
filtersOpen?: boolean;
|
|
9
|
+
ontogglefilters: (event: MouseEvent) => void;
|
|
10
|
+
onhome: () => void;
|
|
11
|
+
contentRef?: HTMLDivElement | null;
|
|
12
|
+
directoryState: RegistryDirectoryState;
|
|
13
|
+
installedIds: Set<string>;
|
|
14
|
+
updateIds: ReadonlySet<string>;
|
|
15
|
+
downloads: (id: string) => number;
|
|
16
|
+
onopen: (plugin: RegistryCatalogEntry) => void;
|
|
17
|
+
onchange: (state: RegistryDirectoryState) => void;
|
|
18
|
+
};
|
|
19
|
+
declare const PluginBrowserDirectory: Component<$$ComponentProps, {}, "contentRef">;
|
|
20
|
+
type PluginBrowserDirectory = ReturnType<typeof PluginBrowserDirectory>;
|
|
21
|
+
export default PluginBrowserDirectory;
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import ChevronRightIcon from "@lucide/svelte/icons/chevron-right";
|
|
3
|
+
import PackageIcon from "@lucide/svelte/icons/package";
|
|
4
|
+
|
|
5
|
+
import { landingSections as registryLandingSections } from "./plugin-browser-model";
|
|
6
|
+
import type { PluginCatalogEntry as RegistryCatalogEntry } from "@lapis-notes/api";
|
|
7
|
+
import RegistryPluginCard from "./PluginBrowserCard.svelte";
|
|
8
|
+
import { registryFilterIcon } from "./community-presentation/registry-filter-icons";
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
plugins,
|
|
12
|
+
updateIds,
|
|
13
|
+
onOpenUpdates,
|
|
14
|
+
onOpenDirectory,
|
|
15
|
+
onOpenPlugin,
|
|
16
|
+
onOpenCategory,
|
|
17
|
+
}: {
|
|
18
|
+
plugins: readonly RegistryCatalogEntry[];
|
|
19
|
+
updateIds: ReadonlySet<string>;
|
|
20
|
+
onOpenUpdates: () => void;
|
|
21
|
+
onOpenDirectory: () => void;
|
|
22
|
+
onOpenPlugin: (plugin: RegistryCatalogEntry) => void;
|
|
23
|
+
onOpenCategory: (category: string) => void;
|
|
24
|
+
} = $props();
|
|
25
|
+
|
|
26
|
+
const sections = $derived(registryLandingSections(plugins, updateIds));
|
|
27
|
+
|
|
28
|
+
function interceptNavigation(event: MouseEvent, action: () => void): void {
|
|
29
|
+
if (
|
|
30
|
+
event.button !== 0 ||
|
|
31
|
+
event.metaKey ||
|
|
32
|
+
event.ctrlKey ||
|
|
33
|
+
event.shiftKey ||
|
|
34
|
+
event.altKey
|
|
35
|
+
)
|
|
36
|
+
return;
|
|
37
|
+
event.preventDefault();
|
|
38
|
+
action();
|
|
39
|
+
}
|
|
40
|
+
</script>
|
|
41
|
+
|
|
42
|
+
<div class="registry-landing">
|
|
43
|
+
<header class="registry-landing__hero">
|
|
44
|
+
<span class="registry-landing__eyebrow"
|
|
45
|
+
><PackageIcon aria-hidden="true" /> Plugin registry</span
|
|
46
|
+
>
|
|
47
|
+
<h1>Make Lapis Notes yours.</h1>
|
|
48
|
+
<p>
|
|
49
|
+
Browse {plugins.length} plugins built for Lapis Notes by the community.
|
|
50
|
+
</p>
|
|
51
|
+
</header>
|
|
52
|
+
|
|
53
|
+
{#if sections.updates.length}
|
|
54
|
+
<section
|
|
55
|
+
class="registry-landing__section"
|
|
56
|
+
aria-labelledby="registry-landing-updates"
|
|
57
|
+
>
|
|
58
|
+
<a
|
|
59
|
+
class="registry-landing__section-link"
|
|
60
|
+
href="#/registry/plugins?updates"
|
|
61
|
+
onclick={(event) => interceptNavigation(event, onOpenUpdates)}
|
|
62
|
+
>
|
|
63
|
+
<h2 id="registry-landing-updates">Updates</h2>
|
|
64
|
+
<ChevronRightIcon aria-hidden="true" />
|
|
65
|
+
</a>
|
|
66
|
+
<div class="registry-landing__updates">
|
|
67
|
+
{#each sections.updates as plugin (plugin.id)}
|
|
68
|
+
<RegistryPluginCard
|
|
69
|
+
{plugin}
|
|
70
|
+
variant="compact"
|
|
71
|
+
onOpen={onOpenPlugin}
|
|
72
|
+
/>
|
|
73
|
+
{/each}
|
|
74
|
+
</div>
|
|
75
|
+
</section>
|
|
76
|
+
{/if}
|
|
77
|
+
|
|
78
|
+
<section
|
|
79
|
+
class="registry-landing__section"
|
|
80
|
+
aria-labelledby="registry-landing-plugins"
|
|
81
|
+
>
|
|
82
|
+
<a
|
|
83
|
+
class="registry-landing__section-link"
|
|
84
|
+
href="#/registry/plugins"
|
|
85
|
+
onclick={(event) => interceptNavigation(event, onOpenDirectory)}
|
|
86
|
+
>
|
|
87
|
+
<h2 id="registry-landing-plugins">Plugins</h2>
|
|
88
|
+
<ChevronRightIcon aria-hidden="true" />
|
|
89
|
+
</a>
|
|
90
|
+
<div class="registry-landing__lanes">
|
|
91
|
+
<section>
|
|
92
|
+
<a
|
|
93
|
+
class="registry-landing__lane-link"
|
|
94
|
+
href="#/registry/plugins"
|
|
95
|
+
onclick={(event) => interceptNavigation(event, onOpenDirectory)}
|
|
96
|
+
>
|
|
97
|
+
Featured <ChevronRightIcon aria-hidden="true" />
|
|
98
|
+
</a>
|
|
99
|
+
<div class="registry-landing__list">
|
|
100
|
+
{#each sections.featured.slice(0, 5) as plugin (plugin.id)}
|
|
101
|
+
<RegistryPluginCard
|
|
102
|
+
{plugin}
|
|
103
|
+
variant="compact"
|
|
104
|
+
onOpen={onOpenPlugin}
|
|
105
|
+
/>
|
|
106
|
+
{/each}
|
|
107
|
+
</div>
|
|
108
|
+
</section>
|
|
109
|
+
<section>
|
|
110
|
+
<a
|
|
111
|
+
class="registry-landing__lane-link"
|
|
112
|
+
href="#/registry/plugins"
|
|
113
|
+
onclick={(event) => interceptNavigation(event, onOpenDirectory)}
|
|
114
|
+
>
|
|
115
|
+
New <ChevronRightIcon aria-hidden="true" />
|
|
116
|
+
</a>
|
|
117
|
+
<div class="registry-landing__list">
|
|
118
|
+
{#each sections.newlyReleased as plugin (plugin.id)}
|
|
119
|
+
<RegistryPluginCard
|
|
120
|
+
{plugin}
|
|
121
|
+
variant="compact"
|
|
122
|
+
onOpen={onOpenPlugin}
|
|
123
|
+
/>
|
|
124
|
+
{/each}
|
|
125
|
+
</div>
|
|
126
|
+
</section>
|
|
127
|
+
<section>
|
|
128
|
+
<a
|
|
129
|
+
class="registry-landing__lane-link"
|
|
130
|
+
href="#/registry/plugins"
|
|
131
|
+
onclick={(event) => interceptNavigation(event, onOpenDirectory)}
|
|
132
|
+
>
|
|
133
|
+
Recently updated <ChevronRightIcon aria-hidden="true" />
|
|
134
|
+
</a>
|
|
135
|
+
<div class="registry-landing__list">
|
|
136
|
+
{#each sections.recentlyUpdated as plugin (plugin.id)}
|
|
137
|
+
<RegistryPluginCard
|
|
138
|
+
{plugin}
|
|
139
|
+
variant="compact"
|
|
140
|
+
onOpen={onOpenPlugin}
|
|
141
|
+
/>
|
|
142
|
+
{/each}
|
|
143
|
+
</div>
|
|
144
|
+
</section>
|
|
145
|
+
</div>
|
|
146
|
+
</section>
|
|
147
|
+
|
|
148
|
+
<section
|
|
149
|
+
class="registry-landing__section"
|
|
150
|
+
aria-labelledby="registry-landing-categories"
|
|
151
|
+
>
|
|
152
|
+
<a
|
|
153
|
+
class="registry-landing__section-link"
|
|
154
|
+
href="#/registry/plugins"
|
|
155
|
+
onclick={(event) => interceptNavigation(event, onOpenDirectory)}
|
|
156
|
+
>
|
|
157
|
+
<h2 id="registry-landing-categories">Categories</h2>
|
|
158
|
+
<ChevronRightIcon aria-hidden="true" />
|
|
159
|
+
</a>
|
|
160
|
+
<div class="registry-landing__categories">
|
|
161
|
+
{#each sections.categories as category (category.id)}
|
|
162
|
+
{@const CategoryIcon = registryFilterIcon(category.id)}
|
|
163
|
+
<a
|
|
164
|
+
href="#/registry/plugins"
|
|
165
|
+
aria-label={`${category.label}, ${category.count} plugin${category.count === 1 ? "" : "s"}`}
|
|
166
|
+
onclick={(event) =>
|
|
167
|
+
interceptNavigation(event, () => onOpenCategory(category.id))}
|
|
168
|
+
>
|
|
169
|
+
<CategoryIcon aria-hidden="true" />
|
|
170
|
+
<strong>{category.label}</strong>
|
|
171
|
+
<span>{category.count}</span>
|
|
172
|
+
</a>
|
|
173
|
+
{/each}
|
|
174
|
+
</div>
|
|
175
|
+
</section>
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
<style>
|
|
179
|
+
.registry-landing {
|
|
180
|
+
display: grid;
|
|
181
|
+
gap: clamp(2.5rem, 7cqi, 5rem);
|
|
182
|
+
min-width: 0;
|
|
183
|
+
width: min(100%, 76rem);
|
|
184
|
+
margin-inline: auto;
|
|
185
|
+
padding: clamp(2rem, 6cqi, 5rem) clamp(1rem, 4cqi, 3rem);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.registry-landing__hero {
|
|
189
|
+
display: grid;
|
|
190
|
+
justify-items: center;
|
|
191
|
+
gap: 0.85rem;
|
|
192
|
+
padding-block: clamp(2rem, 8cqi, 5rem);
|
|
193
|
+
text-align: center;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.registry-landing__eyebrow {
|
|
197
|
+
display: inline-flex;
|
|
198
|
+
align-items: center;
|
|
199
|
+
gap: 0.4rem;
|
|
200
|
+
color: var(--primary);
|
|
201
|
+
font-size: var(--community-text-secondary);
|
|
202
|
+
font-weight: 700;
|
|
203
|
+
text-transform: uppercase;
|
|
204
|
+
letter-spacing: 0.08em;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
.registry-landing__eyebrow :global(svg) {
|
|
208
|
+
width: 1rem;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
h1,
|
|
212
|
+
h2,
|
|
213
|
+
p {
|
|
214
|
+
margin: 0;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
h1 {
|
|
218
|
+
max-width: 15ch;
|
|
219
|
+
font-size: var(--community-text-page);
|
|
220
|
+
line-height: 0.96;
|
|
221
|
+
letter-spacing: -0.05em;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.registry-landing__hero p {
|
|
225
|
+
color: var(--muted-foreground);
|
|
226
|
+
font-size: var(--community-text-section);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.registry-landing__section {
|
|
230
|
+
display: grid;
|
|
231
|
+
gap: 1.25rem;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.registry-landing__section-link,
|
|
235
|
+
.registry-landing__lane-link {
|
|
236
|
+
display: inline-flex;
|
|
237
|
+
width: fit-content;
|
|
238
|
+
align-items: center;
|
|
239
|
+
gap: 0.25rem;
|
|
240
|
+
border: 0;
|
|
241
|
+
padding: 0;
|
|
242
|
+
color: inherit;
|
|
243
|
+
background: none;
|
|
244
|
+
font: inherit;
|
|
245
|
+
font-weight: 700;
|
|
246
|
+
cursor: pointer;
|
|
247
|
+
text-decoration: none;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.registry-landing__section-link :global(svg) {
|
|
251
|
+
width: 1.4rem;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.registry-landing__lane-link {
|
|
255
|
+
margin-bottom: 0.25rem;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.registry-landing__lane-link :global(svg) {
|
|
259
|
+
width: 1rem;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.registry-landing__section-link:hover,
|
|
263
|
+
.registry-landing__lane-link:hover {
|
|
264
|
+
color: var(--primary);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.registry-landing__lanes,
|
|
268
|
+
.registry-landing__updates {
|
|
269
|
+
display: grid;
|
|
270
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
271
|
+
gap: clamp(1.5rem, 4cqi, 3rem);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.registry-landing__list {
|
|
275
|
+
display: grid;
|
|
276
|
+
min-width: 0;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.registry-landing__categories {
|
|
280
|
+
display: grid;
|
|
281
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
282
|
+
gap: 0.75rem;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.registry-landing__categories a {
|
|
286
|
+
display: grid;
|
|
287
|
+
grid-template-columns: auto minmax(0, 1fr) auto;
|
|
288
|
+
align-items: center;
|
|
289
|
+
gap: 0.75rem;
|
|
290
|
+
border: 1px solid var(--border);
|
|
291
|
+
border-radius: var(--radius);
|
|
292
|
+
padding: 1rem;
|
|
293
|
+
color: var(--foreground);
|
|
294
|
+
background: var(--card);
|
|
295
|
+
text-align: start;
|
|
296
|
+
cursor: pointer;
|
|
297
|
+
text-decoration: none;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.registry-landing__categories a:hover,
|
|
301
|
+
.registry-landing__categories a:focus-visible {
|
|
302
|
+
border-color: color-mix(in srgb, var(--primary) 45%, var(--border));
|
|
303
|
+
background: var(--accent);
|
|
304
|
+
outline: none;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.registry-landing__categories a > span {
|
|
308
|
+
color: var(--muted-foreground);
|
|
309
|
+
font-variant-numeric: tabular-nums;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
.registry-landing__categories a > strong {
|
|
313
|
+
min-width: 0;
|
|
314
|
+
overflow-wrap: anywhere;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.registry-landing__categories a :global(svg) {
|
|
318
|
+
width: 1.4rem;
|
|
319
|
+
height: 1.4rem;
|
|
320
|
+
color: var(--muted-foreground);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
@container plugin-browser (max-width: 58rem) {
|
|
324
|
+
.registry-landing__lanes,
|
|
325
|
+
.registry-landing__updates {
|
|
326
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
.registry-landing__categories {
|
|
330
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
@container plugin-browser (max-width: 38rem) {
|
|
335
|
+
.registry-landing__lanes,
|
|
336
|
+
.registry-landing__updates,
|
|
337
|
+
.registry-landing__categories {
|
|
338
|
+
grid-template-columns: minmax(0, 1fr);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
</style>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { PluginCatalogEntry as RegistryCatalogEntry } from "@lapis-notes/api";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
plugins: readonly RegistryCatalogEntry[];
|
|
4
|
+
updateIds: ReadonlySet<string>;
|
|
5
|
+
onOpenUpdates: () => void;
|
|
6
|
+
onOpenDirectory: () => void;
|
|
7
|
+
onOpenPlugin: (plugin: RegistryCatalogEntry) => void;
|
|
8
|
+
onOpenCategory: (category: string) => void;
|
|
9
|
+
};
|
|
10
|
+
declare const PluginBrowserLanding: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
11
|
+
type PluginBrowserLanding = ReturnType<typeof PluginBrowserLanding>;
|
|
12
|
+
export default PluginBrowserLanding;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Globe2 from "@lucide/svelte/icons/globe-2";
|
|
3
|
+
import Monitor from "@lucide/svelte/icons/monitor";
|
|
4
|
+
import ShieldCheck from "@lucide/svelte/icons/shield-check";
|
|
5
|
+
import Tag from "@lucide/svelte/icons/tag";
|
|
6
|
+
import UsersRound from "@lucide/svelte/icons/users-round";
|
|
7
|
+
import * as Badge from "@lapismd/design-core/shadcn/badge";
|
|
8
|
+
|
|
9
|
+
export type PluginRegistryBadgeTone =
|
|
10
|
+
| "neutral"
|
|
11
|
+
| "official"
|
|
12
|
+
| "community"
|
|
13
|
+
| "category"
|
|
14
|
+
| "web"
|
|
15
|
+
| "desktop"
|
|
16
|
+
| "danger";
|
|
17
|
+
|
|
18
|
+
let {
|
|
19
|
+
label,
|
|
20
|
+
tone = "neutral",
|
|
21
|
+
}: { label: string; tone?: PluginRegistryBadgeTone } = $props();
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<Badge.Badge
|
|
25
|
+
class="lapis-plugin-registry-badge"
|
|
26
|
+
data-registry-badge-tone={tone}
|
|
27
|
+
variant={tone === "danger" ? "destructive" : "outline"}
|
|
28
|
+
>
|
|
29
|
+
{#if tone === "official"}
|
|
30
|
+
<ShieldCheck aria-hidden="true" />
|
|
31
|
+
{:else if tone === "community"}
|
|
32
|
+
<UsersRound aria-hidden="true" />
|
|
33
|
+
{:else if tone === "category"}
|
|
34
|
+
<Tag aria-hidden="true" />
|
|
35
|
+
{:else if tone === "web"}
|
|
36
|
+
<Globe2 aria-hidden="true" />
|
|
37
|
+
{:else if tone === "desktop"}
|
|
38
|
+
<Monitor aria-hidden="true" />
|
|
39
|
+
{/if}
|
|
40
|
+
{label}
|
|
41
|
+
</Badge.Badge>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type PluginRegistryBadgeTone = "neutral" | "official" | "community" | "category" | "web" | "desktop" | "danger";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
label: string;
|
|
4
|
+
tone?: PluginRegistryBadgeTone;
|
|
5
|
+
};
|
|
6
|
+
declare const PluginRegistryBadge: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type PluginRegistryBadge = ReturnType<typeof PluginRegistryBadge>;
|
|
8
|
+
export default PluginRegistryBadge;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import AlertTriangle from "@lucide/svelte/icons/alert-triangle";
|
|
3
|
+
import CircleCheck from "@lucide/svelte/icons/circle-check";
|
|
4
|
+
import PackageIcon from "@lucide/svelte/icons/package";
|
|
5
|
+
import SearchX from "@lucide/svelte/icons/search-x";
|
|
6
|
+
import Sparkles from "@lucide/svelte/icons/sparkles";
|
|
7
|
+
import * as Button from "@lapismd/design-core/shadcn/button";
|
|
8
|
+
|
|
9
|
+
let {
|
|
10
|
+
kind,
|
|
11
|
+
heading,
|
|
12
|
+
description,
|
|
13
|
+
actionLabel,
|
|
14
|
+
onaction,
|
|
15
|
+
sourceUrl,
|
|
16
|
+
diagnostic,
|
|
17
|
+
compact = false,
|
|
18
|
+
part,
|
|
19
|
+
}: {
|
|
20
|
+
kind: "empty" | "filtered" | "success" | "loading" | "error" | "warning";
|
|
21
|
+
heading: string;
|
|
22
|
+
description: string;
|
|
23
|
+
actionLabel?: string;
|
|
24
|
+
onaction?: () => void;
|
|
25
|
+
sourceUrl?: string;
|
|
26
|
+
diagnostic?: string;
|
|
27
|
+
compact?: boolean;
|
|
28
|
+
part?: string;
|
|
29
|
+
} = $props();
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<div
|
|
33
|
+
class="lapis-plugin-registry-state"
|
|
34
|
+
data-ui-component="plugin-registry-content-state"
|
|
35
|
+
data-state-kind={kind}
|
|
36
|
+
data-compact={compact || undefined}
|
|
37
|
+
data-ui-part={part}
|
|
38
|
+
role={kind === "error" || kind === "warning" ? "status" : undefined}
|
|
39
|
+
>
|
|
40
|
+
<div
|
|
41
|
+
class="lapis-plugin-registry-state__icon"
|
|
42
|
+
data-empty-icon={kind === "success"
|
|
43
|
+
? "circle-check"
|
|
44
|
+
: kind === "filtered"
|
|
45
|
+
? "search-x"
|
|
46
|
+
: kind === "error" || kind === "warning"
|
|
47
|
+
? "alert-triangle"
|
|
48
|
+
: "package"}
|
|
49
|
+
aria-hidden="true"
|
|
50
|
+
>
|
|
51
|
+
{#if kind === "success"}
|
|
52
|
+
<CircleCheck />
|
|
53
|
+
{:else if kind === "filtered"}
|
|
54
|
+
<SearchX />
|
|
55
|
+
{:else if kind === "error" || kind === "warning"}
|
|
56
|
+
<AlertTriangle />
|
|
57
|
+
{:else}
|
|
58
|
+
<PackageIcon />
|
|
59
|
+
{#if kind !== "loading"}<Sparkles />{/if}
|
|
60
|
+
{/if}
|
|
61
|
+
</div>
|
|
62
|
+
<div class="lapis-plugin-registry-state__body">
|
|
63
|
+
<h2>{heading}</h2>
|
|
64
|
+
<p>{description}</p>
|
|
65
|
+
<div class="lapis-plugin-registry-state__actions">
|
|
66
|
+
{#if actionLabel && onaction}
|
|
67
|
+
<Button.Root size="sm" variant={kind === "error" ? "outline" : "default"} onclick={onaction}
|
|
68
|
+
>{actionLabel}</Button.Root
|
|
69
|
+
>
|
|
70
|
+
{/if}
|
|
71
|
+
{#if sourceUrl}<a href={sourceUrl}>View source</a>{/if}
|
|
72
|
+
</div>
|
|
73
|
+
{#if diagnostic}
|
|
74
|
+
<details>
|
|
75
|
+
<summary>Diagnostic</summary>
|
|
76
|
+
<code>{diagnostic}</code>
|
|
77
|
+
</details>
|
|
78
|
+
{/if}
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type $$ComponentProps = {
|
|
2
|
+
kind: "empty" | "filtered" | "success" | "loading" | "error" | "warning";
|
|
3
|
+
heading: string;
|
|
4
|
+
description: string;
|
|
5
|
+
actionLabel?: string;
|
|
6
|
+
onaction?: () => void;
|
|
7
|
+
sourceUrl?: string;
|
|
8
|
+
diagnostic?: string;
|
|
9
|
+
compact?: boolean;
|
|
10
|
+
part?: string;
|
|
11
|
+
};
|
|
12
|
+
declare const PluginRegistryContentState: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
13
|
+
type PluginRegistryContentState = ReturnType<typeof PluginRegistryContentState>;
|
|
14
|
+
export default PluginRegistryContentState;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
fetchVerifiedPluginImage,
|
|
4
|
+
type RegistryMediaV2,
|
|
5
|
+
resolveRegistryMedia,
|
|
6
|
+
} from "@lapis-notes/api";
|
|
7
|
+
let {
|
|
8
|
+
media,
|
|
9
|
+
variant = "preview",
|
|
10
|
+
presentation = "inline",
|
|
11
|
+
}: {
|
|
12
|
+
media: RegistryMediaV2;
|
|
13
|
+
presentation?: "inline" | "viewer";
|
|
14
|
+
variant?: "preview" | "full" | "light" | "dark";
|
|
15
|
+
} = $props();
|
|
16
|
+
let imageUrl = $state<string | null>(null);
|
|
17
|
+
let error = $state(false);
|
|
18
|
+
$effect(() => {
|
|
19
|
+
const reference = resolveRegistryMedia(media, variant);
|
|
20
|
+
const controller = new AbortController();
|
|
21
|
+
let ownedUrl: string | null = null;
|
|
22
|
+
imageUrl = null;
|
|
23
|
+
error = false;
|
|
24
|
+
void fetchVerifiedPluginImage(reference, fetch, controller.signal)
|
|
25
|
+
.then((blob) => {
|
|
26
|
+
if (controller.signal.aborted) return;
|
|
27
|
+
ownedUrl = URL.createObjectURL(blob);
|
|
28
|
+
imageUrl = ownedUrl;
|
|
29
|
+
})
|
|
30
|
+
.catch(() => {
|
|
31
|
+
if (!controller.signal.aborted) error = true;
|
|
32
|
+
});
|
|
33
|
+
return () => {
|
|
34
|
+
controller.abort();
|
|
35
|
+
if (ownedUrl) URL.revokeObjectURL(ownedUrl);
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
{#if imageUrl}<img
|
|
41
|
+
class:viewer={presentation === "viewer"}
|
|
42
|
+
src={imageUrl}
|
|
43
|
+
alt={media.alt}
|
|
44
|
+
loading="lazy"
|
|
45
|
+
/>
|
|
46
|
+
{:else}<p role="status">
|
|
47
|
+
{error ? "Verified image unavailable" : "Loading image…"}
|
|
48
|
+
</p>{/if}
|
|
49
|
+
|
|
50
|
+
<style>
|
|
51
|
+
img {
|
|
52
|
+
display: block;
|
|
53
|
+
width: 100%;
|
|
54
|
+
max-width: 100%;
|
|
55
|
+
height: auto;
|
|
56
|
+
border-radius: var(--radius);
|
|
57
|
+
}
|
|
58
|
+
img.viewer {
|
|
59
|
+
width: auto;
|
|
60
|
+
max-height: calc(100dvh - 12rem);
|
|
61
|
+
margin-inline: auto;
|
|
62
|
+
object-fit: contain;
|
|
63
|
+
}
|
|
64
|
+
</style>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type RegistryMediaV2 } from "@lapis-notes/api";
|
|
2
|
+
type $$ComponentProps = {
|
|
3
|
+
media: RegistryMediaV2;
|
|
4
|
+
presentation?: "inline" | "viewer";
|
|
5
|
+
variant?: "preview" | "full" | "light" | "dark";
|
|
6
|
+
};
|
|
7
|
+
declare const PluginRegistryImage: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type PluginRegistryImage = ReturnType<typeof PluginRegistryImage>;
|
|
9
|
+
export default PluginRegistryImage;
|