tangled
alpha
login
or
join now
dbushell.com
/
attic.social
11
fork
atom
Attic is a cozy space with lofty ambitions.
attic.social
11
fork
atom
overview
issues
pulls
pipelines
fix pointer dialog
dbushell.com
1 week ago
22a88c4b
2ca2aaa2
verified
This commit was signed with the committer's
known signature
.
dbushell.com
SSH Key Fingerprint:
SHA256:Sj5AfJ6VbC0PEnnQD2kGGEiGFwHdFBS/ypN5oifzzFI=
+94
-51
6 changed files
expand all
collapse all
unified
split
src
app.html
css
components
bookmark.css
main.css
lib
dialog.svelte.ts
routes
+layout.svelte
bookmarks
[did=did]
+page.svelte
-1
src/app.html
···
10
10
</head>
11
11
<body data-sveltekit-preload-data="hover">
12
12
<attic-app>%sveltekit.body%</attic-app>
13
13
-
<div class="pointer"></div>
14
13
</body>
15
14
</html>
+1
-1
src/css/components/bookmark.css
···
70
70
& > code {
71
71
align-self: baseline;
72
72
font-size: var(--font-size-1);
73
73
-
grid-template-columns: 2;
73
73
+
grid-column: 2;
74
74
text-overflow: ellipsis;
75
75
opacity: 0.8;
76
76
overflow: hidden;
+5
-1
src/css/main.css
···
20
20
font-weight: 700;
21
21
}
22
22
23
23
-
.pointer {
23
23
+
#pointer {
24
24
--size: 50px;
25
25
background: url("/images/pointer.svg") center / 100% auto no-repeat;
26
26
block-size: var(--size);
···
35
35
position: fixed;
36
36
user-select: none;
37
37
z-index: 999;
38
38
+
39
39
+
:where(body:not(:has(:is(a[href], button):hover, :focus-visible))) & {
40
40
+
display: none;
41
41
+
}
38
42
39
43
@supports not (inset: anchor(start)) {
40
44
display: none;
+32
src/lib/dialog.svelte.ts
···
1
1
+
export let pointer: { ref: HTMLElement | null } = $state({ ref: null });
2
2
+
3
3
+
export const openDialog = (dialog?: HTMLDialogElement) => {
4
4
+
if (dialog === undefined) {
5
5
+
return;
6
6
+
}
7
7
+
8
8
+
dialog.showModal();
9
9
+
10
10
+
dialog.addEventListener("close", () => {
11
11
+
if (pointer.ref) {
12
12
+
document.querySelector("attic-app")?.append(pointer.ref);
13
13
+
pointer.ref.showPopover();
14
14
+
}
15
15
+
}, { once: true });
16
16
+
17
17
+
if (pointer.ref) {
18
18
+
dialog.append(pointer.ref);
19
19
+
pointer.ref.showPopover();
20
20
+
}
21
21
+
};
22
22
+
23
23
+
export const closeDialog = (dialog?: HTMLDialogElement) => {
24
24
+
if (dialog === undefined) {
25
25
+
return;
26
26
+
}
27
27
+
dialog.close();
28
28
+
// if (pointer.ref) {
29
29
+
// document.querySelector("attic-app")?.append(pointer.ref);
30
30
+
// pointer.ref.showPopover();
31
31
+
// }
32
32
+
};
+10
src/routes/+layout.svelte
···
1
1
<script lang="ts">
2
2
import "$css/main.css";
3
3
+
import { pointer } from "$lib/dialog.svelte.js";
4
4
+
import { onMount } from "svelte";
5
5
+
6
6
+
onMount(() => {
7
7
+
if (pointer.ref) {
8
8
+
pointer.ref.showPopover();
9
9
+
}
10
10
+
});
3
11
4
12
let { data, children } = $props();
5
13
</script>
···
35
43
</small>
36
44
</p>
37
45
</footer>
46
46
+
47
47
+
<div bind:this={pointer.ref} id="pointer" popover="manual"></div>
+46
-48
src/routes/bookmarks/[did=did]/+page.svelte
···
1
1
<script lang="ts">
2
2
+
import { closeDialog, openDialog } from "$lib/dialog.svelte.js";
2
3
import type { EventHandler } from "svelte/elements";
3
4
import type { PageProps } from "./$types";
4
4
-
5
5
let { data, form, params }: PageProps = $props();
6
6
7
7
const isSelf = $derived(data.user && params.did === data.user.did);
···
53
53
$effect(() => {
54
54
if (form?.action === "editBookmark" && "error" in form) {
55
55
if (editDialog?.open === false) {
56
56
-
editDialog?.showModal();
56
56
+
openDialog(editDialog);
57
57
}
58
58
}
59
59
});
···
61
61
$effect(() => {
62
62
if (form?.action === "createBookmark" && "error" in form) {
63
63
if (createDialog?.open === false) {
64
64
-
createDialog?.showModal();
64
64
+
openDialog(createDialog);
65
65
}
66
66
}
67
67
});
···
91
91
commandfor={dialog?.id}
92
92
onclick={(ev) => {
93
93
ev.preventDefault();
94
94
-
dialog?.close();
94
94
+
closeDialog(dialog);
95
95
}}
96
96
>
97
97
<span class="visually-hidden">close</span>
···
189
189
</dialog>
190
190
{/if}
191
191
192
192
-
{#if data.bookmarks.length}
193
193
-
<div class="Bookmarks">
194
194
-
<div class="Bookmarks-header">
195
195
-
<h2>Bookmarks</h2>
192
192
+
<div class="Bookmarks">
193
193
+
<div class="Bookmarks-header">
194
194
+
<h2>Bookmarks</h2>
195
195
+
{#if isSelf}
196
196
+
<button type="button" onclick={() => openDialog(createDialog)}>
197
197
+
New
198
198
+
</button>
199
199
+
{/if}
200
200
+
</div>
201
201
+
{#each data.bookmarks as entry (entry.cid)}
202
202
+
<article id={entry.cid} class="Bookmark">
203
203
+
<h3>
204
204
+
<a href={entry.url} rel="noopener noreferrer" target="_blank">
205
205
+
<img
206
206
+
alt=""
207
207
+
width="16"
208
208
+
height="16"
209
209
+
src="/bookmarks/favicon/{new URL(entry.url).hostname}"
210
210
+
/>
211
211
+
{entry.title}
212
212
+
</a>
213
213
+
</h3>
214
214
+
<time datetime={entry.createdAt}>
215
215
+
{dateFormat.format(new Date(entry.createdAt))}
216
216
+
</time>
217
217
+
<code aria-hidden="true">{entry.url}</code>
196
218
{#if isSelf}
197
197
-
<button type="button" onclick={() => createDialog?.showModal()}>
198
198
-
New
199
199
-
</button>
219
219
+
<div class="flex flex-wrap">
220
220
+
<button
221
221
+
type="button"
222
222
+
onclick={(ev) => {
223
223
+
ev.preventDefault();
224
224
+
form = null;
225
225
+
editData = entry;
226
226
+
openDialog(editDialog);
227
227
+
}}
228
228
+
>
229
229
+
Edit
230
230
+
</button>
231
231
+
</div>
200
232
{/if}
201
201
-
</div>
202
202
-
{#each data.bookmarks as entry (entry.cid)}
203
203
-
<article id={entry.cid} class="Bookmark">
204
204
-
<h3>
205
205
-
<a href={entry.url} rel="noopener noreferrer" target="_blank">
206
206
-
<img
207
207
-
alt=""
208
208
-
width="16"
209
209
-
height="16"
210
210
-
src="/bookmarks/favicon/{new URL(entry.url).hostname}"
211
211
-
/>
212
212
-
{entry.title}
213
213
-
</a>
214
214
-
</h3>
215
215
-
<time datetime={entry.createdAt}>
216
216
-
{dateFormat.format(new Date(entry.createdAt))}
217
217
-
</time>
218
218
-
<code aria-hidden="true">{entry.url}</code>
219
219
-
{#if isSelf}
220
220
-
<div class="flex flex-wrap">
221
221
-
<button
222
222
-
type="button"
223
223
-
onclick={(ev) => {
224
224
-
ev.preventDefault();
225
225
-
form = null;
226
226
-
editData = entry;
227
227
-
editDialog?.showModal();
228
228
-
}}
229
229
-
>
230
230
-
Edit
231
231
-
</button>
232
232
-
</div>
233
233
-
{/if}
234
234
-
</article>
235
235
-
{/each}
236
236
-
</div>
237
237
-
{/if}
233
233
+
</article>
234
234
+
{/each}
235
235
+
</div>