@lapis-notes/workspace 0.2.0 → 0.3.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 +108 -9
- package/README.md +4 -0
- package/dist/WorkspaceShell.svelte +19 -2
- package/dist/WorkspaceShell.svelte.d.ts +3 -1
- package/dist/desktop/DesktopRecoveryBanner.css +46 -0
- package/dist/desktop/DesktopRecoveryBanner.svelte +70 -0
- package/dist/desktop/DesktopRecoveryBanner.svelte.d.ts +15 -0
- package/dist/desktop/DesktopVaultLauncher.svelte +278 -0
- package/dist/desktop/DesktopVaultLauncher.svelte.d.ts +17 -0
- package/dist/desktop/DesktopVaultLauncherDialogs.svelte +136 -0
- package/dist/desktop/DesktopVaultLauncherDialogs.svelte.d.ts +9 -0
- package/dist/desktop/DesktopWorkspaceStartup.css +8 -0
- package/dist/desktop/DesktopWorkspaceStartup.svelte +34 -0
- package/dist/desktop/DesktopWorkspaceStartup.svelte.d.ts +9 -0
- package/dist/desktop/desktop-vault-launcher-controls.css +142 -0
- package/dist/desktop/desktop-vault-launcher.css +181 -0
- package/dist/desktop/desktop-vault-launcher.d.ts +30 -0
- package/dist/desktop/desktop-vault-launcher.js +26 -0
- package/dist/desktop/desktop-vault-launcher.svelte.d.ts +36 -0
- package/dist/desktop/desktop-vault-launcher.svelte.js +140 -0
- package/dist/desktop/lapis-logo.svg +471 -0
- package/dist/file-conflicts/ConflictReview.svelte +145 -0
- package/dist/file-conflicts/ConflictReview.svelte.d.ts +8 -0
- package/dist/file-conflicts/ConflictReviewControls.svelte +66 -0
- package/dist/file-conflicts/ConflictReviewControls.svelte.d.ts +12 -0
- package/dist/file-conflicts/conflict-review-state.svelte.d.ts +22 -0
- package/dist/file-conflicts/conflict-review-state.svelte.js +59 -0
- package/dist/file-conflicts/conflict-review-view.d.ts +19 -0
- package/dist/file-conflicts/conflict-review-view.js +50 -0
- package/dist/file-conflicts/register-conflict-reviews.d.ts +7 -0
- package/dist/file-conflicts/register-conflict-reviews.js +132 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/dist/plugin-management/CorePluginsSettingsPage.svelte +47 -16
- package/dist/plugin-management/PluginBrowser.svelte +63 -7
- package/dist/plugin-management/PluginRegistryToolbar.svelte.d.ts +1 -1
- package/dist/plugin-management/plugin-browser-model.d.ts +1 -0
- package/dist/plugin-management/plugin-browser-model.js +11 -2
- package/dist/plugin-management/plugin-browser-navigation.d.ts +1 -1
- package/dist/plugin-management/plugin-browser-navigation.js +4 -2
- package/dist/plugin-management/plugin-registry-controller.svelte.js +5 -1
- package/dist/plugin-management/plugins-view.svelte.d.ts +2 -1
- package/dist/plugin-management/plugins-view.svelte.js +6 -2
- package/dist/plugin-management/register-plugin-management-settings.js +7 -6
- package/package.json +5 -4
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Search from "@lucide/svelte/icons/search";
|
|
3
|
+
import type { VaultProfile } from "@lapis-notes/api";
|
|
4
|
+
import * as Button from "@lapismd/design-core/shadcn/button";
|
|
5
|
+
import * as CommandView from "@lapismd/design-core/shadcn/command-view";
|
|
6
|
+
import * as Dialog from "@lapismd/design-core/shadcn/dialog";
|
|
7
|
+
import * as Input from "@lapismd/design-core/shadcn/input";
|
|
8
|
+
import { desktopAppearanceOptions } from "./desktop-vault-launcher";
|
|
9
|
+
import type { DesktopVaultLauncherState } from "./desktop-vault-launcher.svelte";
|
|
10
|
+
let {
|
|
11
|
+
model,
|
|
12
|
+
onOpenRecent,
|
|
13
|
+
}: {
|
|
14
|
+
model: DesktopVaultLauncherState;
|
|
15
|
+
onOpenRecent(profile: VaultProfile): Promise<void>;
|
|
16
|
+
} = $props();
|
|
17
|
+
$effect(() => {
|
|
18
|
+
if (!model.recentVaultDialogOpen) model.recentVaultQuery = "";
|
|
19
|
+
});
|
|
20
|
+
$effect(() => {
|
|
21
|
+
if (!model.renameDialogOpen) {
|
|
22
|
+
model.renameTarget = null;
|
|
23
|
+
model.renameDialogName = "";
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<Dialog.Root bind:open={model.settingsOpen}>
|
|
29
|
+
<Dialog.Content class="desktop-launcher__settings">
|
|
30
|
+
<Dialog.Header>
|
|
31
|
+
<Dialog.Title>Desktop Settings</Dialog.Title>
|
|
32
|
+
<Dialog.Description
|
|
33
|
+
>Choose how the vault chooser follows light and dark mode.</Dialog.Description
|
|
34
|
+
>
|
|
35
|
+
</Dialog.Header>
|
|
36
|
+
<div class="desktop-launcher__options">
|
|
37
|
+
{#each desktopAppearanceOptions as option (option.value)}
|
|
38
|
+
<Button.Root
|
|
39
|
+
variant={model.appearanceMode === option.value
|
|
40
|
+
? "default"
|
|
41
|
+
: "outline"}
|
|
42
|
+
class={`desktop-launcher__option${model.appearanceMode === option.value ? "" : " desktop-launcher__outline"}`}
|
|
43
|
+
onclick={() => void model.updateAppearance(option.value)}
|
|
44
|
+
>
|
|
45
|
+
<span class="desktop-launcher__option-copy">
|
|
46
|
+
<span class="desktop-launcher__label">{option.label}</span>
|
|
47
|
+
<span class="desktop-launcher__hint">{option.description}</span>
|
|
48
|
+
</span>
|
|
49
|
+
</Button.Root>
|
|
50
|
+
{/each}
|
|
51
|
+
</div>
|
|
52
|
+
</Dialog.Content>
|
|
53
|
+
</Dialog.Root>
|
|
54
|
+
|
|
55
|
+
<Dialog.Root bind:open={model.recentVaultDialogOpen}>
|
|
56
|
+
<Dialog.Content class="desktop-launcher__command" showCloseButton={false}>
|
|
57
|
+
<Dialog.Header class="sr-only">
|
|
58
|
+
<Dialog.Title>Recent Projects</Dialog.Title>
|
|
59
|
+
<Dialog.Description>Search and open a recent vault</Dialog.Description>
|
|
60
|
+
</Dialog.Header>
|
|
61
|
+
<CommandView.Root shouldFilter={false} label="Search recent vaults">
|
|
62
|
+
<CommandView.Input
|
|
63
|
+
bind:value={model.recentVaultQuery}
|
|
64
|
+
placeholder="Search recent vaults..."
|
|
65
|
+
aria-label="Search recent vaults"
|
|
66
|
+
autocomplete="off"
|
|
67
|
+
spellcheck="false"
|
|
68
|
+
/>
|
|
69
|
+
<CommandView.List aria-label="Recent projects">
|
|
70
|
+
<CommandView.Empty>No matching recent vaults</CommandView.Empty>
|
|
71
|
+
{#if model.filteredRecentVaults.length > 0}
|
|
72
|
+
<CommandView.Group>
|
|
73
|
+
{#each model.filteredRecentVaults as entry (entry.profile.id)}
|
|
74
|
+
<CommandView.Item
|
|
75
|
+
value={`${entry.name} ${entry.location}`}
|
|
76
|
+
onSelect={() =>
|
|
77
|
+
void model.invoke(() => onOpenRecent(entry.profile))}
|
|
78
|
+
>
|
|
79
|
+
<CommandView.ItemIcon>
|
|
80
|
+
<Search />
|
|
81
|
+
</CommandView.ItemIcon>
|
|
82
|
+
<CommandView.ItemLabel>{entry.name}</CommandView.ItemLabel>
|
|
83
|
+
<CommandView.ItemDescription>
|
|
84
|
+
{entry.location}
|
|
85
|
+
</CommandView.ItemDescription>
|
|
86
|
+
</CommandView.Item>
|
|
87
|
+
{/each}
|
|
88
|
+
</CommandView.Group>
|
|
89
|
+
{/if}
|
|
90
|
+
</CommandView.List>
|
|
91
|
+
</CommandView.Root>
|
|
92
|
+
</Dialog.Content>
|
|
93
|
+
</Dialog.Root>
|
|
94
|
+
|
|
95
|
+
<Dialog.Root bind:open={model.renameDialogOpen}>
|
|
96
|
+
<Dialog.Content class="desktop-launcher__rename">
|
|
97
|
+
<Dialog.Header>
|
|
98
|
+
<Dialog.Title>Rename vault</Dialog.Title>
|
|
99
|
+
<Dialog.Description
|
|
100
|
+
>Update the stored vault name used in recent projects and app URLs.</Dialog.Description
|
|
101
|
+
>
|
|
102
|
+
</Dialog.Header>
|
|
103
|
+
<form
|
|
104
|
+
class="desktop-launcher__form"
|
|
105
|
+
onsubmit={(event) => {
|
|
106
|
+
event.preventDefault();
|
|
107
|
+
void model.submitRename();
|
|
108
|
+
}}
|
|
109
|
+
>
|
|
110
|
+
<label class="desktop-launcher__field">
|
|
111
|
+
<span>Name</span>
|
|
112
|
+
<Input.Root
|
|
113
|
+
bind:value={model.renameDialogName}
|
|
114
|
+
autocomplete="off"
|
|
115
|
+
autofocus
|
|
116
|
+
/>
|
|
117
|
+
</label>
|
|
118
|
+
<Dialog.Footer>
|
|
119
|
+
<Button.Root
|
|
120
|
+
type="button"
|
|
121
|
+
variant="ghost"
|
|
122
|
+
onclick={() => (model.renameDialogOpen = false)}
|
|
123
|
+
>
|
|
124
|
+
Cancel
|
|
125
|
+
</Button.Root>
|
|
126
|
+
<Button.Root
|
|
127
|
+
type="submit"
|
|
128
|
+
disabled={!model.renameDialogName.trim() ||
|
|
129
|
+
model.activeActionId === model.renameTarget?.id}
|
|
130
|
+
>
|
|
131
|
+
Save
|
|
132
|
+
</Button.Root>
|
|
133
|
+
</Dialog.Footer>
|
|
134
|
+
</form>
|
|
135
|
+
</Dialog.Content>
|
|
136
|
+
</Dialog.Root>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { VaultProfile } from "@lapis-notes/api";
|
|
2
|
+
import type { DesktopVaultLauncherState } from "./desktop-vault-launcher.svelte";
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
model: DesktopVaultLauncherState;
|
|
5
|
+
onOpenRecent(profile: VaultProfile): Promise<void>;
|
|
6
|
+
};
|
|
7
|
+
declare const DesktopVaultLauncherDialogs: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type DesktopVaultLauncherDialogs = ReturnType<typeof DesktopVaultLauncherDialogs>;
|
|
9
|
+
export default DesktopVaultLauncherDialogs;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
WorkspaceStartup,
|
|
4
|
+
type WorkspaceStartupFailure,
|
|
5
|
+
type WorkspaceStartupTask,
|
|
6
|
+
} from "@lapismd/design-core/workspace/startup";
|
|
7
|
+
import lapisLogo from "./lapis-logo.svg";
|
|
8
|
+
import "./DesktopWorkspaceStartup.css";
|
|
9
|
+
|
|
10
|
+
let {
|
|
11
|
+
tasks = [],
|
|
12
|
+
failure = null,
|
|
13
|
+
}: {
|
|
14
|
+
tasks?: WorkspaceStartupTask[];
|
|
15
|
+
failure?: WorkspaceStartupFailure | null;
|
|
16
|
+
} = $props();
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
{#snippet lapisVisual()}
|
|
20
|
+
<img
|
|
21
|
+
class="desktop-workspace-startup__logo"
|
|
22
|
+
data-ui-component="desktop-workspace-startup"
|
|
23
|
+
data-ui-part="logo"
|
|
24
|
+
src={lapisLogo}
|
|
25
|
+
alt=""
|
|
26
|
+
/>
|
|
27
|
+
{/snippet}
|
|
28
|
+
|
|
29
|
+
<WorkspaceStartup
|
|
30
|
+
title="Opening Lapis Notes"
|
|
31
|
+
loadingVisual={lapisVisual}
|
|
32
|
+
{tasks}
|
|
33
|
+
{failure}
|
|
34
|
+
/>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type WorkspaceStartupFailure, type WorkspaceStartupTask } from "@lapismd/design-core/workspace/startup";
|
|
2
|
+
import "./DesktopWorkspaceStartup.css";
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
tasks?: WorkspaceStartupTask[];
|
|
5
|
+
failure?: WorkspaceStartupFailure | null;
|
|
6
|
+
};
|
|
7
|
+
declare const DesktopWorkspaceStartup: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
8
|
+
type DesktopWorkspaceStartup = ReturnType<typeof DesktopWorkspaceStartup>;
|
|
9
|
+
export default DesktopWorkspaceStartup;
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
.desktop-launcher__action[data-ui-component="button"],
|
|
2
|
+
.desktop-launcher__option[data-ui-component="button"] {
|
|
3
|
+
width: 100%;
|
|
4
|
+
height: auto;
|
|
5
|
+
min-width: 0;
|
|
6
|
+
align-items: flex-start;
|
|
7
|
+
justify-content: flex-start;
|
|
8
|
+
white-space: normal;
|
|
9
|
+
border-radius: 0.75rem;
|
|
10
|
+
padding: 1rem;
|
|
11
|
+
text-align: start;
|
|
12
|
+
}
|
|
13
|
+
.desktop-launcher__action-copy,
|
|
14
|
+
.desktop-launcher__option-copy {
|
|
15
|
+
display: flex;
|
|
16
|
+
min-width: 0;
|
|
17
|
+
flex: 1;
|
|
18
|
+
flex-direction: column;
|
|
19
|
+
align-items: flex-start;
|
|
20
|
+
gap: 0.25rem;
|
|
21
|
+
text-align: start;
|
|
22
|
+
}
|
|
23
|
+
.desktop-launcher__hint {
|
|
24
|
+
font-size: 0.75rem;
|
|
25
|
+
font-weight: 400;
|
|
26
|
+
opacity: 0.8;
|
|
27
|
+
}
|
|
28
|
+
.desktop-launcher__icon {
|
|
29
|
+
width: 1rem;
|
|
30
|
+
height: 1rem;
|
|
31
|
+
}
|
|
32
|
+
.desktop-launcher__large-icon {
|
|
33
|
+
width: 1.25rem;
|
|
34
|
+
height: 1.25rem;
|
|
35
|
+
flex-shrink: 0;
|
|
36
|
+
}
|
|
37
|
+
.desktop-launcher__settings-trigger[data-ui-component="button"],
|
|
38
|
+
.desktop-launcher__link[data-ui-component="button"] {
|
|
39
|
+
padding-inline: 0;
|
|
40
|
+
}
|
|
41
|
+
.desktop-launcher__close[data-ui-component="button"] {
|
|
42
|
+
border: 0;
|
|
43
|
+
border-radius: 50%;
|
|
44
|
+
box-shadow: none;
|
|
45
|
+
color: var(--secondary-foreground);
|
|
46
|
+
background: var(--secondary);
|
|
47
|
+
}
|
|
48
|
+
.desktop-launcher__close[data-ui-component="button"]:hover:not(:disabled) {
|
|
49
|
+
color: var(--ui-workspace-panel-action-hover-foreground);
|
|
50
|
+
background: var(--ui-workspace-panel-action-hover-background);
|
|
51
|
+
}
|
|
52
|
+
.desktop-launcher__recent-open {
|
|
53
|
+
display: flex;
|
|
54
|
+
min-width: 0;
|
|
55
|
+
flex: 1;
|
|
56
|
+
align-items: flex-start;
|
|
57
|
+
gap: 0.75rem;
|
|
58
|
+
border: 0;
|
|
59
|
+
border-radius: 0.5rem;
|
|
60
|
+
padding: 0.5rem 0.75rem;
|
|
61
|
+
color: inherit;
|
|
62
|
+
background: transparent;
|
|
63
|
+
font: inherit;
|
|
64
|
+
text-align: start;
|
|
65
|
+
cursor: pointer;
|
|
66
|
+
}
|
|
67
|
+
.desktop-launcher__recent-open:disabled {
|
|
68
|
+
opacity: 0.5;
|
|
69
|
+
cursor: default;
|
|
70
|
+
}
|
|
71
|
+
.desktop-launcher__recent-icon {
|
|
72
|
+
width: 1rem;
|
|
73
|
+
height: 1rem;
|
|
74
|
+
flex-shrink: 0;
|
|
75
|
+
margin-block-start: 0.125rem;
|
|
76
|
+
color: var(--ui-workspace-muted-foreground);
|
|
77
|
+
}
|
|
78
|
+
.desktop-launcher__outline[data-ui-component="button"]:hover:not(:disabled),
|
|
79
|
+
.desktop-launcher__recent-open:hover:not(:disabled) {
|
|
80
|
+
color: var(--ui-workspace-foreground);
|
|
81
|
+
background: var(--background-modifier-active-hover);
|
|
82
|
+
}
|
|
83
|
+
.desktop-launcher__recent-menu {
|
|
84
|
+
display: flex;
|
|
85
|
+
width: 2rem;
|
|
86
|
+
height: 2rem;
|
|
87
|
+
flex-shrink: 0;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: center;
|
|
90
|
+
margin-block: auto;
|
|
91
|
+
border: 0;
|
|
92
|
+
border-radius: 0.5rem;
|
|
93
|
+
color: var(--ui-workspace-muted-foreground);
|
|
94
|
+
background: transparent;
|
|
95
|
+
}
|
|
96
|
+
.desktop-launcher__recent-menu:hover {
|
|
97
|
+
color: var(--ui-workspace-foreground);
|
|
98
|
+
background: var(--ui-workspace-panel-action-hover-background);
|
|
99
|
+
}
|
|
100
|
+
.desktop-launcher__recent-menu:focus-visible,
|
|
101
|
+
.desktop-launcher__recent-open:focus-visible {
|
|
102
|
+
outline: 3px solid var(--ring);
|
|
103
|
+
outline-offset: 2px;
|
|
104
|
+
}
|
|
105
|
+
.desktop-launcher__settings[data-ui-component="dialog"][data-ui-part="dialog-content"],
|
|
106
|
+
.desktop-launcher__rename[data-ui-component="dialog"][data-ui-part="dialog-content"] {
|
|
107
|
+
top: 50%;
|
|
108
|
+
left: 50%;
|
|
109
|
+
width: min(28rem, calc(100% - 2rem));
|
|
110
|
+
max-width: 28rem;
|
|
111
|
+
max-height: calc(100% - 2rem);
|
|
112
|
+
overflow: auto;
|
|
113
|
+
translate: -50% -50%;
|
|
114
|
+
}
|
|
115
|
+
.desktop-launcher__command[data-ui-component="dialog"][data-ui-part="dialog-content"] {
|
|
116
|
+
top: 20vh;
|
|
117
|
+
left: 50%;
|
|
118
|
+
width: min(34rem, calc(100% - 2rem));
|
|
119
|
+
max-width: 34rem;
|
|
120
|
+
max-height: calc(80vh - 1rem);
|
|
121
|
+
overflow: hidden;
|
|
122
|
+
translate: -50% 0;
|
|
123
|
+
gap: 0;
|
|
124
|
+
padding: 0;
|
|
125
|
+
--ui-command-view-list-max-height: min(20rem, calc(80vh - 6rem));
|
|
126
|
+
}
|
|
127
|
+
.desktop-launcher__options {
|
|
128
|
+
display: grid;
|
|
129
|
+
gap: 0.75rem;
|
|
130
|
+
}
|
|
131
|
+
.desktop-launcher__option[data-ui-component="button"] {
|
|
132
|
+
padding-block: 0.75rem;
|
|
133
|
+
}
|
|
134
|
+
.desktop-launcher__form {
|
|
135
|
+
display: grid;
|
|
136
|
+
gap: 1rem;
|
|
137
|
+
}
|
|
138
|
+
.desktop-launcher__field {
|
|
139
|
+
display: grid;
|
|
140
|
+
gap: 0.5rem;
|
|
141
|
+
font-size: 0.875rem;
|
|
142
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
.desktop-launcher {
|
|
2
|
+
display: flex;
|
|
3
|
+
height: 100%;
|
|
4
|
+
min-height: 100%;
|
|
5
|
+
overflow: auto;
|
|
6
|
+
padding: 2.5rem 1rem;
|
|
7
|
+
color: var(--ui-workspace-foreground);
|
|
8
|
+
background: var(--ui-workspace-background);
|
|
9
|
+
}
|
|
10
|
+
.desktop-launcher__content {
|
|
11
|
+
display: grid;
|
|
12
|
+
width: 100%;
|
|
13
|
+
max-width: 64rem;
|
|
14
|
+
min-width: 0;
|
|
15
|
+
gap: 1.5rem;
|
|
16
|
+
margin: auto;
|
|
17
|
+
}
|
|
18
|
+
.desktop-launcher__header {
|
|
19
|
+
display: flex;
|
|
20
|
+
flex-direction: column;
|
|
21
|
+
justify-content: space-between;
|
|
22
|
+
gap: 1.25rem;
|
|
23
|
+
}
|
|
24
|
+
.desktop-launcher__brand {
|
|
25
|
+
display: flex;
|
|
26
|
+
min-width: 0;
|
|
27
|
+
align-items: center;
|
|
28
|
+
gap: 1rem;
|
|
29
|
+
}
|
|
30
|
+
.desktop-launcher__logo {
|
|
31
|
+
width: 3.5rem;
|
|
32
|
+
height: 3.5rem;
|
|
33
|
+
flex-shrink: 0;
|
|
34
|
+
border: 1px solid
|
|
35
|
+
color-mix(in srgb, var(--ui-workspace-border) 70%, transparent);
|
|
36
|
+
border-radius: 1rem;
|
|
37
|
+
background: var(--ui-workspace-panel-background);
|
|
38
|
+
object-fit: cover;
|
|
39
|
+
box-shadow: 0 1px 2px #0000000d;
|
|
40
|
+
}
|
|
41
|
+
.desktop-launcher__copy {
|
|
42
|
+
min-width: 0;
|
|
43
|
+
}
|
|
44
|
+
.desktop-launcher__eyebrow {
|
|
45
|
+
color: var(--ui-workspace-muted-foreground);
|
|
46
|
+
font-size: 0.75rem;
|
|
47
|
+
font-weight: 600;
|
|
48
|
+
letter-spacing: 0.28em;
|
|
49
|
+
text-transform: uppercase;
|
|
50
|
+
}
|
|
51
|
+
.desktop-launcher__heading {
|
|
52
|
+
margin: 0;
|
|
53
|
+
font-size: 1.5rem;
|
|
54
|
+
font-weight: 600;
|
|
55
|
+
letter-spacing: -0.025em;
|
|
56
|
+
line-height: 1.2;
|
|
57
|
+
}
|
|
58
|
+
.desktop-launcher__description {
|
|
59
|
+
margin: 0.25rem 0 0;
|
|
60
|
+
color: var(--ui-workspace-muted-foreground);
|
|
61
|
+
font-size: 0.875rem;
|
|
62
|
+
}
|
|
63
|
+
.desktop-launcher__header-actions {
|
|
64
|
+
display: flex;
|
|
65
|
+
flex-shrink: 0;
|
|
66
|
+
align-items: center;
|
|
67
|
+
gap: 0.25rem;
|
|
68
|
+
}
|
|
69
|
+
.desktop-launcher__columns {
|
|
70
|
+
display: grid;
|
|
71
|
+
min-width: 0;
|
|
72
|
+
gap: 1.25rem;
|
|
73
|
+
}
|
|
74
|
+
.desktop-launcher__card[data-ui-component="card"] {
|
|
75
|
+
min-width: 0;
|
|
76
|
+
gap: 0;
|
|
77
|
+
--ui-card-border-color: color-mix(
|
|
78
|
+
in srgb,
|
|
79
|
+
var(--ui-workspace-border) 70%,
|
|
80
|
+
transparent
|
|
81
|
+
);
|
|
82
|
+
--ui-card-background: color-mix(
|
|
83
|
+
in srgb,
|
|
84
|
+
var(--ui-workspace-panel-background) 90%,
|
|
85
|
+
transparent
|
|
86
|
+
);
|
|
87
|
+
backdrop-filter: blur(8px);
|
|
88
|
+
}
|
|
89
|
+
.desktop-launcher__card-header {
|
|
90
|
+
padding-inline: 1.5rem;
|
|
91
|
+
padding-block-end: 0;
|
|
92
|
+
}
|
|
93
|
+
.desktop-launcher__card-title {
|
|
94
|
+
font-size: 1.25rem;
|
|
95
|
+
}
|
|
96
|
+
.desktop-launcher__action-list {
|
|
97
|
+
display: grid;
|
|
98
|
+
gap: 0.75rem;
|
|
99
|
+
padding: 0 1.5rem 1.5rem;
|
|
100
|
+
}
|
|
101
|
+
.desktop-launcher__recents-header {
|
|
102
|
+
display: flex;
|
|
103
|
+
align-items: flex-start;
|
|
104
|
+
justify-content: space-between;
|
|
105
|
+
gap: 0.75rem;
|
|
106
|
+
}
|
|
107
|
+
.desktop-launcher__recent-list {
|
|
108
|
+
display: grid;
|
|
109
|
+
gap: 0.5rem;
|
|
110
|
+
padding: 0 1rem 1rem;
|
|
111
|
+
}
|
|
112
|
+
.desktop-launcher__recent {
|
|
113
|
+
display: flex;
|
|
114
|
+
width: 100%;
|
|
115
|
+
align-items: stretch;
|
|
116
|
+
gap: 0.25rem;
|
|
117
|
+
border: 1px solid
|
|
118
|
+
color-mix(in srgb, var(--ui-workspace-border) 60%, transparent);
|
|
119
|
+
border-radius: 0.75rem;
|
|
120
|
+
padding: 0.25rem;
|
|
121
|
+
}
|
|
122
|
+
.desktop-launcher__recent-copy {
|
|
123
|
+
display: flex;
|
|
124
|
+
min-width: 0;
|
|
125
|
+
flex: 1;
|
|
126
|
+
flex-direction: column;
|
|
127
|
+
gap: 0.25rem;
|
|
128
|
+
}
|
|
129
|
+
.desktop-launcher__recent-name,
|
|
130
|
+
.desktop-launcher__location {
|
|
131
|
+
overflow: hidden;
|
|
132
|
+
white-space: nowrap;
|
|
133
|
+
text-overflow: ellipsis;
|
|
134
|
+
}
|
|
135
|
+
.desktop-launcher__recent-name,
|
|
136
|
+
.desktop-launcher__label {
|
|
137
|
+
font-weight: 500;
|
|
138
|
+
}
|
|
139
|
+
.desktop-launcher__location {
|
|
140
|
+
color: var(--ui-workspace-muted-foreground);
|
|
141
|
+
font-size: 0.75rem;
|
|
142
|
+
}
|
|
143
|
+
.desktop-launcher__empty {
|
|
144
|
+
padding: 1.25rem 1rem;
|
|
145
|
+
border: 1px dashed
|
|
146
|
+
color-mix(in srgb, var(--ui-workspace-border) 70%, transparent);
|
|
147
|
+
border-radius: 0.75rem;
|
|
148
|
+
color: var(--ui-workspace-muted-foreground);
|
|
149
|
+
font-size: 0.875rem;
|
|
150
|
+
}
|
|
151
|
+
.desktop-launcher__error,
|
|
152
|
+
.desktop-launcher__message {
|
|
153
|
+
border: 1px solid
|
|
154
|
+
color-mix(in srgb, var(--ui-workspace-border) 70%, transparent);
|
|
155
|
+
border-radius: 0.75rem;
|
|
156
|
+
padding: 0.75rem 1rem;
|
|
157
|
+
font-size: 0.875rem;
|
|
158
|
+
background: var(--ui-workspace-panel-background);
|
|
159
|
+
}
|
|
160
|
+
.desktop-launcher__error {
|
|
161
|
+
border-color: color-mix(in srgb, var(--destructive) 40%, transparent);
|
|
162
|
+
color: var(--destructive);
|
|
163
|
+
background: color-mix(in srgb, var(--destructive) 10%, transparent);
|
|
164
|
+
}
|
|
165
|
+
@media (min-width: 40rem) {
|
|
166
|
+
.desktop-launcher {
|
|
167
|
+
padding-inline: 1.5rem;
|
|
168
|
+
}
|
|
169
|
+
.desktop-launcher__header {
|
|
170
|
+
flex-direction: row;
|
|
171
|
+
align-items: flex-start;
|
|
172
|
+
}
|
|
173
|
+
.desktop-launcher__heading {
|
|
174
|
+
font-size: 1.875rem;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
@media (min-width: 64rem) {
|
|
178
|
+
.desktop-launcher__columns {
|
|
179
|
+
grid-template-columns: minmax(0, 420px) minmax(0, 1fr);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { VaultProfile } from "@lapis-notes/api";
|
|
2
|
+
export type LauncherStatus = "loading" | "landing" | "opening" | "error";
|
|
3
|
+
export type DesktopLauncherAppearance = "system" | "light" | "dark";
|
|
4
|
+
/** Storage and native actions belong to the consuming desktop host. */
|
|
5
|
+
export interface DesktopVaultLauncherHost {
|
|
6
|
+
listProfiles(): Promise<VaultProfile[]>;
|
|
7
|
+
getAppearance(): Promise<DesktopLauncherAppearance>;
|
|
8
|
+
saveAppearance(mode: DesktopLauncherAppearance): Promise<void>;
|
|
9
|
+
copyId?(profile: VaultProfile): Promise<void>;
|
|
10
|
+
rename?(profile: VaultProfile, name: string): Promise<void>;
|
|
11
|
+
move?(profile: VaultProfile): Promise<boolean>;
|
|
12
|
+
reveal?(profile: VaultProfile): Promise<void>;
|
|
13
|
+
remove?(profile: VaultProfile): Promise<void>;
|
|
14
|
+
revealLabel?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function getVaultProfileRootPath(profile: VaultProfile): string | null;
|
|
17
|
+
export declare function getVaultProfileLocation(profile: VaultProfile): string;
|
|
18
|
+
export declare const desktopAppearanceOptions: readonly [{
|
|
19
|
+
readonly value: "system";
|
|
20
|
+
readonly label: "Match System";
|
|
21
|
+
readonly description: "Follow the current system appearance.";
|
|
22
|
+
}, {
|
|
23
|
+
readonly value: "light";
|
|
24
|
+
readonly label: "Light";
|
|
25
|
+
readonly description: "Use the light workspace palette on the vault chooser.";
|
|
26
|
+
}, {
|
|
27
|
+
readonly value: "dark";
|
|
28
|
+
readonly label: "Dark";
|
|
29
|
+
readonly description: "Use the dark workspace palette on the vault chooser.";
|
|
30
|
+
}];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function getVaultProfileRootPath(profile) {
|
|
2
|
+
const handle = profile.handle;
|
|
3
|
+
if (typeof handle === "string")
|
|
4
|
+
return handle;
|
|
5
|
+
return typeof handle?.rootPath === "string" ? handle.rootPath : null;
|
|
6
|
+
}
|
|
7
|
+
export function getVaultProfileLocation(profile) {
|
|
8
|
+
return getVaultProfileRootPath(profile) ?? "Desktop vault";
|
|
9
|
+
}
|
|
10
|
+
export const desktopAppearanceOptions = [
|
|
11
|
+
{
|
|
12
|
+
value: "system",
|
|
13
|
+
label: "Match System",
|
|
14
|
+
description: "Follow the current system appearance.",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
value: "light",
|
|
18
|
+
label: "Light",
|
|
19
|
+
description: "Use the light workspace palette on the vault chooser.",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
value: "dark",
|
|
23
|
+
label: "Dark",
|
|
24
|
+
description: "Use the dark workspace palette on the vault chooser.",
|
|
25
|
+
},
|
|
26
|
+
];
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { VaultProfile } from "@lapis-notes/api";
|
|
2
|
+
import { type DesktopLauncherAppearance, type DesktopVaultLauncherHost } from "./desktop-vault-launcher";
|
|
3
|
+
/** State from the Deno chooser, shared without depending on a native bridge. */
|
|
4
|
+
export declare class DesktopVaultLauncherState {
|
|
5
|
+
readonly host: DesktopVaultLauncherHost;
|
|
6
|
+
recentVaults: VaultProfile[];
|
|
7
|
+
recentVaultQuery: string;
|
|
8
|
+
recentVaultDialogOpen: boolean;
|
|
9
|
+
settingsOpen: boolean;
|
|
10
|
+
appearanceMode: DesktopLauncherAppearance;
|
|
11
|
+
activeActionId: string | null;
|
|
12
|
+
renameDialogOpen: boolean;
|
|
13
|
+
renameDialogName: string;
|
|
14
|
+
renameTarget: VaultProfile | null;
|
|
15
|
+
actionError: string;
|
|
16
|
+
actionMessage: string;
|
|
17
|
+
constructor(host: DesktopVaultLauncherHost);
|
|
18
|
+
get inlineRecentVaults(): VaultProfile[];
|
|
19
|
+
get filteredRecentVaults(): {
|
|
20
|
+
profile: VaultProfile;
|
|
21
|
+
name: string;
|
|
22
|
+
location: string;
|
|
23
|
+
kind: import("@lapis-notes/api").VaultStorageKind;
|
|
24
|
+
}[];
|
|
25
|
+
applyAppearance(mode: DesktopLauncherAppearance): void;
|
|
26
|
+
refresh(): Promise<void>;
|
|
27
|
+
invoke(action: () => Promise<void>): Promise<void>;
|
|
28
|
+
runAction(profile: VaultProfile, action: () => Promise<void>, message?: string): Promise<void>;
|
|
29
|
+
openRenameDialog(profile: VaultProfile): void;
|
|
30
|
+
submitRename(): Promise<void>;
|
|
31
|
+
moveRecentVault(profile: VaultProfile): Promise<void>;
|
|
32
|
+
copyVaultId(profile: VaultProfile): Promise<void>;
|
|
33
|
+
revealRecentVault(profile: VaultProfile): Promise<void>;
|
|
34
|
+
removeRecentVault(profile: VaultProfile): Promise<void>;
|
|
35
|
+
updateAppearance(mode: DesktopLauncherAppearance): Promise<void>;
|
|
36
|
+
}
|