@atmo-dev/kit 0.0.0-stage → 0.0.2
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/LICENSE +21 -0
- package/README.md +9 -2
- package/dist/components/Avatar.svelte +35 -0
- package/dist/components/Avatar.svelte.d.ts +9 -0
- package/dist/components/Badge.svelte +21 -0
- package/dist/components/Badge.svelte.d.ts +7 -0
- package/dist/components/Button.svelte +94 -0
- package/dist/components/Button.svelte.d.ts +13 -0
- package/dist/components/Checkbox.svelte +29 -0
- package/dist/components/Checkbox.svelte.d.ts +8 -0
- package/dist/components/Heading.svelte +24 -0
- package/dist/components/Heading.svelte.d.ts +8 -0
- package/dist/components/Icon.svelte +24 -0
- package/dist/components/Icon.svelte.d.ts +8 -0
- package/dist/components/IconButton.svelte +24 -0
- package/dist/components/IconButton.svelte.d.ts +8 -0
- package/dist/components/IconRail.svelte +183 -0
- package/dist/components/IconRail.svelte.d.ts +26 -0
- package/dist/components/InlineEditor.svelte +120 -0
- package/dist/components/InlineEditor.svelte.d.ts +19 -0
- package/dist/components/Input.svelte +32 -0
- package/dist/components/Input.svelte.d.ts +9 -0
- package/dist/components/InsetImage.svelte +29 -0
- package/dist/components/InsetImage.svelte.d.ts +9 -0
- package/dist/components/Label.svelte +19 -0
- package/dist/components/Label.svelte.d.ts +7 -0
- package/dist/components/LinkCard.svelte +47 -0
- package/dist/components/LinkCard.svelte.d.ts +12 -0
- package/dist/components/Modal.svelte +93 -0
- package/dist/components/Modal.svelte.d.ts +12 -0
- package/dist/components/NestedComments.svelte +61 -0
- package/dist/components/NestedComments.svelte.d.ts +8 -0
- package/dist/components/PageTitle.svelte +22 -0
- package/dist/components/PageTitle.svelte.d.ts +8 -0
- package/dist/components/Popover.svelte +49 -0
- package/dist/components/Popover.svelte.d.ts +12 -0
- package/dist/components/PostComposer.svelte +41 -0
- package/dist/components/PostComposer.svelte.d.ts +16 -0
- package/dist/components/PostContent.svelte +62 -0
- package/dist/components/PostContent.svelte.d.ts +8 -0
- package/dist/components/PostVideo.svelte +74 -0
- package/dist/components/PostVideo.svelte.d.ts +9 -0
- package/dist/components/Select.svelte +34 -0
- package/dist/components/Select.svelte.d.ts +9 -0
- package/dist/components/Subheading.svelte +22 -0
- package/dist/components/Subheading.svelte.d.ts +8 -0
- package/dist/components/Surface.svelte +40 -0
- package/dist/components/Surface.svelte.d.ts +11 -0
- package/dist/components/Tabs.svelte +47 -0
- package/dist/components/Tabs.svelte.d.ts +16 -0
- package/dist/components/Textarea.svelte +20 -0
- package/dist/components/Textarea.svelte.d.ts +7 -0
- package/dist/components/ToggleGroup.svelte +32 -0
- package/dist/components/ToggleGroup.svelte.d.ts +12 -0
- package/dist/components/ToggleGroupItem.svelte +26 -0
- package/dist/components/ToggleGroupItem.svelte.d.ts +8 -0
- package/dist/components/WorkspaceSidebar.svelte +82 -0
- package/dist/components/WorkspaceSidebar.svelte.d.ts +10 -0
- package/dist/components/login/ActorSearchField.svelte +238 -0
- package/dist/components/login/ActorSearchField.svelte.d.ts +19 -0
- package/dist/components/login/AtmosphereApps.svelte +19 -0
- package/dist/components/login/AtmosphereApps.svelte.d.ts +18 -0
- package/dist/components/login/LoginDialog.svelte +78 -0
- package/dist/components/login/LoginDialog.svelte.d.ts +9 -0
- package/dist/components/login/LoginForm.svelte +402 -0
- package/dist/components/login/LoginForm.svelte.d.ts +28 -0
- package/dist/components/login/RecentAccounts.svelte +57 -0
- package/dist/components/login/RecentAccounts.svelte.d.ts +10 -0
- package/dist/components/login/brands/README.md +7 -0
- package/dist/components/login/brands/blacksky.svg +3 -0
- package/dist/components/login/brands/bluesky.svg +3 -0
- package/dist/components/login/brands/bookhive.svg +3 -0
- package/dist/components/login/brands/graze.svg +3 -0
- package/dist/components/login/brands/leaflet.svg +3 -0
- package/dist/components/login/brands/pckt.svg +3 -0
- package/dist/components/login/brands/surf.svg +3 -0
- package/dist/components/login/brands/tangled.svg +3 -0
- package/dist/components/login/handle.d.ts +3 -0
- package/dist/components/login/handle.js +11 -0
- package/dist/components/login/permissions.d.ts +3 -0
- package/dist/components/login/permissions.js +13 -0
- package/dist/components/login/recent-accounts.d.ts +16 -0
- package/dist/components/login/recent-accounts.js +87 -0
- package/dist/components/login/search.d.ts +9 -0
- package/dist/components/login/search.js +47 -0
- package/dist/components/login/types.d.ts +27 -0
- package/dist/components/login/types.js +1 -0
- package/dist/confetti.d.ts +2 -0
- package/dist/confetti.js +13 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.js +40 -0
- package/dist/palettes.d.ts +2 -0
- package/dist/palettes.js +30 -0
- package/dist/social/mention-suggestions.d.ts +35 -0
- package/dist/social/mention-suggestions.js +122 -0
- package/dist/social/posts.d.ts +95 -0
- package/dist/social/posts.js +59 -0
- package/dist/social/richtext.d.ts +25 -0
- package/dist/social/richtext.js +100 -0
- package/dist/styles.d.ts +2 -0
- package/dist/styles.js +3 -0
- package/dist/theme.css +499 -0
- package/dist/theme.d.ts +2 -0
- package/dist/theme.js +23 -0
- package/dist/utils.d.ts +2 -0
- package/dist/utils.js +6 -0
- package/package.json +108 -3
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { PostData } from '../social/posts.js';
|
|
3
|
+
import { richTextSegments, safeWebUrl } from '../social/richtext.js';
|
|
4
|
+
import LinkCard from './LinkCard.svelte';
|
|
5
|
+
import PostVideo from './PostVideo.svelte';
|
|
6
|
+
import PostContent from './PostContent.svelte';
|
|
7
|
+
let { post }: { post: PostData } = $props();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<p class="text-sm leading-relaxed break-words whitespace-pre-wrap text-ink">
|
|
11
|
+
{#each richTextSegments(post.text, post.facets) as segment, index (index)}{#if segment.href}<a
|
|
12
|
+
href={segment.href}
|
|
13
|
+
target="_blank"
|
|
14
|
+
rel="noopener noreferrer nofollow"
|
|
15
|
+
class="text-action underline decoration-action/40 underline-offset-2 hover:decoration-action"
|
|
16
|
+
>{segment.text}</a
|
|
17
|
+
>{:else}{segment.text}{/if}{/each}
|
|
18
|
+
</p>
|
|
19
|
+
{#each post.embeds ?? [] as embed, index (index)}
|
|
20
|
+
<div class="mt-3">
|
|
21
|
+
{#if embed.type === 'external'}<LinkCard
|
|
22
|
+
href={embed.uri}
|
|
23
|
+
meta={{ title: embed.title, description: embed.description, image: embed.image }}
|
|
24
|
+
/>
|
|
25
|
+
{:else if embed.type === 'images'}<div
|
|
26
|
+
class="grid gap-1 overflow-hidden rounded-ui border border-line"
|
|
27
|
+
class:grid-cols-2={embed.images.length > 1}
|
|
28
|
+
>
|
|
29
|
+
{#each embed.images as image (image.src)}<a
|
|
30
|
+
href={safeWebUrl(image.fullsize ?? image.src)}
|
|
31
|
+
target="_blank"
|
|
32
|
+
rel="noopener noreferrer"
|
|
33
|
+
><img
|
|
34
|
+
src={safeWebUrl(image.src)}
|
|
35
|
+
alt={image.alt}
|
|
36
|
+
loading="lazy"
|
|
37
|
+
width={image.width}
|
|
38
|
+
height={image.height}
|
|
39
|
+
class="max-h-80 w-full object-cover"
|
|
40
|
+
class:aspect-square={embed.images.length > 1}
|
|
41
|
+
/></a
|
|
42
|
+
>{/each}
|
|
43
|
+
</div>
|
|
44
|
+
{:else if embed.type === 'video'}<PostVideo
|
|
45
|
+
playlist={embed.playlist}
|
|
46
|
+
poster={embed.poster}
|
|
47
|
+
label={embed.alt}
|
|
48
|
+
href={post.href}
|
|
49
|
+
/>
|
|
50
|
+
{:else if embed.type === 'quote'}<div class="rounded-ui border border-line p-3">
|
|
51
|
+
{#if embed.post}<a
|
|
52
|
+
href={safeWebUrl(embed.post.href)}
|
|
53
|
+
target="_blank"
|
|
54
|
+
rel="noopener noreferrer"
|
|
55
|
+
class="mb-2 block text-xs font-medium text-muted"
|
|
56
|
+
>{embed.post.author.name} · @{embed.post.author.handle}</a
|
|
57
|
+
><PostContent post={embed.post} />{:else}<p class="text-xs text-muted">
|
|
58
|
+
Post unavailable
|
|
59
|
+
</p>{/if}
|
|
60
|
+
</div>{/if}
|
|
61
|
+
</div>
|
|
62
|
+
{/each}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { PostData } from '../social/posts.js';
|
|
2
|
+
import PostContent from './PostContent.svelte';
|
|
3
|
+
type $$ComponentProps = {
|
|
4
|
+
post: PostData;
|
|
5
|
+
};
|
|
6
|
+
declare const PostContent: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type PostContent = ReturnType<typeof PostContent>;
|
|
8
|
+
export default PostContent;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { safeWebUrl } from '../social/richtext.js';
|
|
3
|
+
import Icon from './Icon.svelte';
|
|
4
|
+
import { ArrowUpRight } from '@sketchyicons/svelte';
|
|
5
|
+
let {
|
|
6
|
+
playlist,
|
|
7
|
+
poster,
|
|
8
|
+
label,
|
|
9
|
+
href
|
|
10
|
+
}: { playlist: string; poster?: string; label?: string; href: string } = $props();
|
|
11
|
+
let video = $state<HTMLVideoElement | null>(null);
|
|
12
|
+
// Writable derived state resets a playback failure when the source changes.
|
|
13
|
+
let failed = $derived(!safeWebUrl(playlist));
|
|
14
|
+
$effect(() => {
|
|
15
|
+
const source = safeWebUrl(playlist),
|
|
16
|
+
media = video;
|
|
17
|
+
if (!source || !media || failed) return;
|
|
18
|
+
let cancelled = false;
|
|
19
|
+
let destroy: (() => void) | undefined;
|
|
20
|
+
if (media.canPlayType('application/vnd.apple.mpegurl')) media.src = source;
|
|
21
|
+
else
|
|
22
|
+
void import('hls.js')
|
|
23
|
+
.then(({ default: Hls }) => {
|
|
24
|
+
if (cancelled) return;
|
|
25
|
+
if (!Hls.isSupported()) {
|
|
26
|
+
failed = true;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const hls = new Hls({ autoStartLoad: false });
|
|
30
|
+
hls.loadSource(source);
|
|
31
|
+
hls.attachMedia(media);
|
|
32
|
+
const play = () => hls.startLoad();
|
|
33
|
+
media.addEventListener('play', play);
|
|
34
|
+
hls.on(Hls.Events.ERROR, (_event, data) => {
|
|
35
|
+
if (data.fatal && !cancelled) failed = true;
|
|
36
|
+
});
|
|
37
|
+
destroy = () => {
|
|
38
|
+
media.removeEventListener('play', play);
|
|
39
|
+
hls.destroy();
|
|
40
|
+
};
|
|
41
|
+
})
|
|
42
|
+
.catch(() => {
|
|
43
|
+
if (!cancelled) failed = true;
|
|
44
|
+
});
|
|
45
|
+
return () => {
|
|
46
|
+
cancelled = true;
|
|
47
|
+
destroy?.();
|
|
48
|
+
media.pause();
|
|
49
|
+
media.removeAttribute('src');
|
|
50
|
+
media.load();
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
{#if !failed}
|
|
56
|
+
<!-- Bluesky's video view supplies alt text, but no caption track. -->
|
|
57
|
+
<video
|
|
58
|
+
bind:this={video}
|
|
59
|
+
poster={safeWebUrl(poster)}
|
|
60
|
+
aria-label={label || 'Bluesky video'}
|
|
61
|
+
controls
|
|
62
|
+
playsinline
|
|
63
|
+
preload="none"
|
|
64
|
+
class="max-h-96 w-full rounded-ui bg-black"
|
|
65
|
+
onerror={() => (failed = true)}
|
|
66
|
+
></video>
|
|
67
|
+
{/if}
|
|
68
|
+
<a
|
|
69
|
+
href={safeWebUrl(href)}
|
|
70
|
+
target="_blank"
|
|
71
|
+
rel="noopener noreferrer"
|
|
72
|
+
class="mt-1 inline-flex items-center gap-1 text-xs text-action hover:underline"
|
|
73
|
+
>Watch on Bluesky <Icon img={ArrowUpRight} size={14} /></a
|
|
74
|
+
>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLSelectAttributes } from 'svelte/elements';
|
|
3
|
+
import { cn } from '../utils.js';
|
|
4
|
+
import { control } from '../styles.js';
|
|
5
|
+
import Icon from './Icon.svelte';
|
|
6
|
+
import { ChevronDown } from '@sketchyicons/svelte';
|
|
7
|
+
let {
|
|
8
|
+
class: className,
|
|
9
|
+
value = $bindable<string | undefined>(),
|
|
10
|
+
ref = $bindable(null),
|
|
11
|
+
children,
|
|
12
|
+
...rest
|
|
13
|
+
}: Omit<HTMLSelectAttributes, 'value' | 'multiple'> & {
|
|
14
|
+
value?: string;
|
|
15
|
+
multiple?: never;
|
|
16
|
+
ref?: HTMLSelectElement | null;
|
|
17
|
+
} = $props();
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<span class="relative block">
|
|
21
|
+
<select
|
|
22
|
+
{...rest}
|
|
23
|
+
bind:value
|
|
24
|
+
bind:this={ref}
|
|
25
|
+
data-slot="select"
|
|
26
|
+
class={cn(control, 'cursor-pointer appearance-none pr-11', className)}
|
|
27
|
+
>{@render children?.()}</select
|
|
28
|
+
>
|
|
29
|
+
<Icon
|
|
30
|
+
img={ChevronDown}
|
|
31
|
+
size={17}
|
|
32
|
+
class="pointer-events-none absolute top-1/2 right-3 -translate-y-1/2 text-muted"
|
|
33
|
+
/>
|
|
34
|
+
</span>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { HTMLSelectAttributes } from 'svelte/elements';
|
|
2
|
+
type $$ComponentProps = Omit<HTMLSelectAttributes, 'value' | 'multiple'> & {
|
|
3
|
+
value?: string;
|
|
4
|
+
multiple?: never;
|
|
5
|
+
ref?: HTMLSelectElement | null;
|
|
6
|
+
};
|
|
7
|
+
declare const Select: import("svelte").Component<$$ComponentProps, {}, "value" | "ref">;
|
|
8
|
+
type Select = ReturnType<typeof Select>;
|
|
9
|
+
export default Select;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import { cn } from '../utils.js';
|
|
4
|
+
let {
|
|
5
|
+
class: className,
|
|
6
|
+
level = 2,
|
|
7
|
+
ref = $bindable(null),
|
|
8
|
+
children,
|
|
9
|
+
...rest
|
|
10
|
+
}: HTMLAttributes<HTMLHeadingElement> & {
|
|
11
|
+
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
12
|
+
ref?: HTMLHeadingElement | null;
|
|
13
|
+
} = $props();
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<svelte:element
|
|
17
|
+
this={`h${level}`}
|
|
18
|
+
{...rest}
|
|
19
|
+
bind:this={ref}
|
|
20
|
+
class={cn('m-0 text-lg leading-snug font-medium tracking-tight text-ink', className)}
|
|
21
|
+
>{@render children?.()}</svelte:element
|
|
22
|
+
>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
type $$ComponentProps = HTMLAttributes<HTMLHeadingElement> & {
|
|
3
|
+
level?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
4
|
+
ref?: HTMLHeadingElement | null;
|
|
5
|
+
};
|
|
6
|
+
declare const Subheading: import("svelte").Component<$$ComponentProps, {}, "ref">;
|
|
7
|
+
type Subheading = ReturnType<typeof Subheading>;
|
|
8
|
+
export default Subheading;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import { cn } from '../utils.js';
|
|
4
|
+
import { focus } from '../styles.js';
|
|
5
|
+
let {
|
|
6
|
+
class: className,
|
|
7
|
+
as = 'div',
|
|
8
|
+
variant = 'recessed',
|
|
9
|
+
ref = $bindable(null),
|
|
10
|
+
type,
|
|
11
|
+
disabled,
|
|
12
|
+
children,
|
|
13
|
+
...rest
|
|
14
|
+
}: HTMLAttributes<HTMLElement> & {
|
|
15
|
+
as?: 'div' | 'section' | 'article' | 'aside' | 'main' | 'button';
|
|
16
|
+
type?: 'button' | 'submit' | 'reset';
|
|
17
|
+
disabled?: boolean;
|
|
18
|
+
variant?: 'recessed' | 'plain';
|
|
19
|
+
ref?: HTMLElement | null;
|
|
20
|
+
} = $props();
|
|
21
|
+
</script>
|
|
22
|
+
|
|
23
|
+
<svelte:element
|
|
24
|
+
this={as}
|
|
25
|
+
{...rest}
|
|
26
|
+
type={as === 'button' ? (type ?? 'button') : undefined}
|
|
27
|
+
disabled={as === 'button' ? disabled : undefined}
|
|
28
|
+
bind:this={ref}
|
|
29
|
+
data-slot="surface"
|
|
30
|
+
class={cn(
|
|
31
|
+
'rounded-panel p-6 text-ink',
|
|
32
|
+
variant === 'recessed' && 'border border-line bg-recess shadow-(--ui-recess-shadow)',
|
|
33
|
+
as === 'button' &&
|
|
34
|
+
cn(
|
|
35
|
+
'cursor-pointer touch-manipulation disabled:pointer-events-none disabled:opacity-45',
|
|
36
|
+
focus
|
|
37
|
+
),
|
|
38
|
+
className
|
|
39
|
+
)}>{@render children?.()}</svelte:element
|
|
40
|
+
>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
type $$ComponentProps = HTMLAttributes<HTMLElement> & {
|
|
3
|
+
as?: 'div' | 'section' | 'article' | 'aside' | 'main' | 'button';
|
|
4
|
+
type?: 'button' | 'submit' | 'reset';
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
variant?: 'recessed' | 'plain';
|
|
7
|
+
ref?: HTMLElement | null;
|
|
8
|
+
};
|
|
9
|
+
declare const Surface: import("svelte").Component<$$ComponentProps, {}, "ref">;
|
|
10
|
+
type Surface = ReturnType<typeof Surface>;
|
|
11
|
+
export default Surface;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<script lang="ts" module>
|
|
2
|
+
export type TabItem = { value: string; label: string; disabled?: boolean };
|
|
3
|
+
</script>
|
|
4
|
+
|
|
5
|
+
<script lang="ts">
|
|
6
|
+
import type { Snippet } from 'svelte';
|
|
7
|
+
import { Tabs as Primitive } from 'bits-ui';
|
|
8
|
+
import { cn } from '../utils.js';
|
|
9
|
+
import { focus } from '../styles.js';
|
|
10
|
+
let {
|
|
11
|
+
items,
|
|
12
|
+
value = $bindable(''),
|
|
13
|
+
label,
|
|
14
|
+
class: className,
|
|
15
|
+
children,
|
|
16
|
+
...rest
|
|
17
|
+
}: Omit<Primitive.RootProps, 'children' | 'child' | 'value'> & {
|
|
18
|
+
items: readonly TabItem[];
|
|
19
|
+
value?: string;
|
|
20
|
+
label: string;
|
|
21
|
+
children: Snippet<[string]>;
|
|
22
|
+
} = $props();
|
|
23
|
+
$effect(() => {
|
|
24
|
+
if (!items.some((item) => item.value === value && !item.disabled))
|
|
25
|
+
value = items.find((item) => !item.disabled)?.value ?? '';
|
|
26
|
+
});
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<Primitive.Root {...rest} bind:value class={cn('min-w-0', className)}>
|
|
30
|
+
<Primitive.List
|
|
31
|
+
aria-label={label}
|
|
32
|
+
class="flex w-fit max-w-full flex-wrap items-center gap-1 rounded-[12px_14px_11px_13px] border border-line bg-recess p-1 shadow-[inset_0_2px_4px_var(--ui-shadow)]"
|
|
33
|
+
>
|
|
34
|
+
{#each items as item (item.value)}<Primitive.Trigger
|
|
35
|
+
value={item.value}
|
|
36
|
+
disabled={item.disabled}
|
|
37
|
+
class={cn(
|
|
38
|
+
'cursor-pointer rounded-[8px_10px_7px_9px] px-3.5 py-1.75 text-[.8125rem] leading-normal text-muted hover:text-ink disabled:cursor-default disabled:opacity-45 data-[state=active]:bg-surface data-[state=active]:text-ink',
|
|
39
|
+
focus
|
|
40
|
+
)}>{item.label}</Primitive.Trigger
|
|
41
|
+
>{/each}
|
|
42
|
+
</Primitive.List>
|
|
43
|
+
{#each items as item (item.value)}<Primitive.Content
|
|
44
|
+
value={item.value}
|
|
45
|
+
class={cn('rounded pt-6', focus)}>{@render children(item.value)}</Primitive.Content
|
|
46
|
+
>{/each}
|
|
47
|
+
</Primitive.Root>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type TabItem = {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
};
|
|
6
|
+
import type { Snippet } from 'svelte';
|
|
7
|
+
import { Tabs as Primitive } from 'bits-ui';
|
|
8
|
+
type $$ComponentProps = Omit<Primitive.RootProps, 'children' | 'child' | 'value'> & {
|
|
9
|
+
items: readonly TabItem[];
|
|
10
|
+
value?: string;
|
|
11
|
+
label: string;
|
|
12
|
+
children: Snippet<[string]>;
|
|
13
|
+
};
|
|
14
|
+
declare const Tabs: import("svelte").Component<$$ComponentProps, {}, "value">;
|
|
15
|
+
type Tabs = ReturnType<typeof Tabs>;
|
|
16
|
+
export default Tabs;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLTextareaAttributes } from 'svelte/elements';
|
|
3
|
+
import { cn } from '../utils.js';
|
|
4
|
+
import { control } from '../styles.js';
|
|
5
|
+
let {
|
|
6
|
+
class: className,
|
|
7
|
+
value = $bindable(''),
|
|
8
|
+
ref = $bindable(null),
|
|
9
|
+
rows = 4,
|
|
10
|
+
...rest
|
|
11
|
+
}: HTMLTextareaAttributes & { ref?: HTMLTextAreaElement | null } = $props();
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<textarea
|
|
15
|
+
{...rest}
|
|
16
|
+
{rows}
|
|
17
|
+
bind:value
|
|
18
|
+
bind:this={ref}
|
|
19
|
+
data-slot="textarea"
|
|
20
|
+
class={cn(control, 'min-h-28 resize-y', className)}></textarea>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { HTMLTextareaAttributes } from 'svelte/elements';
|
|
2
|
+
type $$ComponentProps = HTMLTextareaAttributes & {
|
|
3
|
+
ref?: HTMLTextAreaElement | null;
|
|
4
|
+
};
|
|
5
|
+
declare const Textarea: import("svelte").Component<$$ComponentProps, {}, "value" | "ref">;
|
|
6
|
+
type Textarea = ReturnType<typeof Textarea>;
|
|
7
|
+
export default Textarea;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ToggleGroup } from 'bits-ui';
|
|
3
|
+
import { cn } from '../utils.js';
|
|
4
|
+
let {
|
|
5
|
+
value = $bindable(''),
|
|
6
|
+
size = 'sm',
|
|
7
|
+
class: className,
|
|
8
|
+
children,
|
|
9
|
+
...rest
|
|
10
|
+
}: Omit<
|
|
11
|
+
Extract<ToggleGroup.RootProps, { type: 'single' }>,
|
|
12
|
+
'type' | 'value' | 'children' | 'child'
|
|
13
|
+
> & {
|
|
14
|
+
type?: 'single';
|
|
15
|
+
value?: string;
|
|
16
|
+
size?: 'xs' | 'sm';
|
|
17
|
+
children?: import('svelte').Snippet;
|
|
18
|
+
} = $props();
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<ToggleGroup.Root
|
|
22
|
+
{...rest}
|
|
23
|
+
type="single"
|
|
24
|
+
bind:value
|
|
25
|
+
data-size={size}
|
|
26
|
+
class={cn(
|
|
27
|
+
'inline-flex flex-wrap gap-1 rounded-ui bg-recess p-1 [box-shadow:var(--ui-recess-shadow)]',
|
|
28
|
+
className
|
|
29
|
+
)}
|
|
30
|
+
>
|
|
31
|
+
{@render children?.()}
|
|
32
|
+
</ToggleGroup.Root>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ToggleGroup } from 'bits-ui';
|
|
2
|
+
type $$ComponentProps = Omit<Extract<ToggleGroup.RootProps, {
|
|
3
|
+
type: 'single';
|
|
4
|
+
}>, 'type' | 'value' | 'children' | 'child'> & {
|
|
5
|
+
type?: 'single';
|
|
6
|
+
value?: string;
|
|
7
|
+
size?: 'xs' | 'sm';
|
|
8
|
+
children?: import('svelte').Snippet;
|
|
9
|
+
};
|
|
10
|
+
declare const ToggleGroup: import("svelte").Component<$$ComponentProps, {}, "value">;
|
|
11
|
+
type ToggleGroup = ReturnType<typeof ToggleGroup>;
|
|
12
|
+
export default ToggleGroup;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { ToggleGroup } from 'bits-ui';
|
|
3
|
+
import { cn } from '../utils.js';
|
|
4
|
+
import { focus } from '../styles.js';
|
|
5
|
+
let {
|
|
6
|
+
class: className,
|
|
7
|
+
size = 'sm',
|
|
8
|
+
children,
|
|
9
|
+
...rest
|
|
10
|
+
}: Omit<ToggleGroup.ItemProps, 'children'> & {
|
|
11
|
+
size?: 'xs' | 'sm';
|
|
12
|
+
children?: import('svelte').Snippet;
|
|
13
|
+
} = $props();
|
|
14
|
+
</script>
|
|
15
|
+
|
|
16
|
+
<ToggleGroup.Item
|
|
17
|
+
{...rest}
|
|
18
|
+
class={cn(
|
|
19
|
+
'cursor-pointer rounded-ui px-3 py-1.5 text-xs font-medium text-muted transition-colors duration-(--atmo-duration) hover:text-ink disabled:pointer-events-none disabled:opacity-45 data-[state=on]:bg-surface data-[state=on]:text-action motion-reduce:transition-none',
|
|
20
|
+
focus,
|
|
21
|
+
size === 'xs' && 'px-2 py-1 text-[.6875rem]',
|
|
22
|
+
className
|
|
23
|
+
)}
|
|
24
|
+
>
|
|
25
|
+
{@render children?.()}
|
|
26
|
+
</ToggleGroup.Item>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ToggleGroup } from 'bits-ui';
|
|
2
|
+
type $$ComponentProps = Omit<ToggleGroup.ItemProps, 'children'> & {
|
|
3
|
+
size?: 'xs' | 'sm';
|
|
4
|
+
children?: import('svelte').Snippet;
|
|
5
|
+
};
|
|
6
|
+
declare const ToggleGroupItem: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
|
+
type ToggleGroupItem = ReturnType<typeof ToggleGroupItem>;
|
|
8
|
+
export default ToggleGroupItem;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { tick, type Snippet } from 'svelte';
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import { MediaQuery } from 'svelte/reactivity';
|
|
5
|
+
import Surface from './Surface.svelte';
|
|
6
|
+
import Modal from './Modal.svelte';
|
|
7
|
+
import { cn } from '../utils.js';
|
|
8
|
+
let {
|
|
9
|
+
label,
|
|
10
|
+
open = $bindable(false),
|
|
11
|
+
children,
|
|
12
|
+
class: className,
|
|
13
|
+
style,
|
|
14
|
+
...rest
|
|
15
|
+
}: Omit<HTMLAttributes<HTMLElement>, 'children'> & {
|
|
16
|
+
label: string;
|
|
17
|
+
open?: boolean;
|
|
18
|
+
children: Snippet;
|
|
19
|
+
} = $props();
|
|
20
|
+
// Native null means “remove the attribute”; Bits UI accepts undefined instead.
|
|
21
|
+
const modalAttributes = $derived(
|
|
22
|
+
Object.fromEntries(Object.entries(rest).filter(([, value]) => value !== null))
|
|
23
|
+
);
|
|
24
|
+
let desktop = $state<HTMLElement | null>(null);
|
|
25
|
+
const mobile = new MediaQuery('(width < 48rem)', false);
|
|
26
|
+
let drawerWasOpen = false;
|
|
27
|
+
$effect(() => {
|
|
28
|
+
const leavingDrawer = !mobile.current && drawerWasOpen;
|
|
29
|
+
drawerWasOpen = mobile.current && open;
|
|
30
|
+
if (!mobile.current) open = false;
|
|
31
|
+
if (leavingDrawer) {
|
|
32
|
+
void tick().then(() => {
|
|
33
|
+
if (!mobile.current)
|
|
34
|
+
desktop
|
|
35
|
+
?.querySelector<HTMLElement>(
|
|
36
|
+
'a[href], button:not(:disabled), input:not(:disabled), [tabindex="0"]'
|
|
37
|
+
)
|
|
38
|
+
?.focus();
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
</script>
|
|
43
|
+
|
|
44
|
+
{#if !mobile.current}
|
|
45
|
+
<Surface
|
|
46
|
+
{...rest}
|
|
47
|
+
as="aside"
|
|
48
|
+
bind:ref={desktop}
|
|
49
|
+
{style}
|
|
50
|
+
aria-label={label}
|
|
51
|
+
data-slot="workspace-sidebar"
|
|
52
|
+
class={cn(
|
|
53
|
+
'fixed top-[calc(var(--atmo-nav-top,0px)+12px)] bottom-3 left-3 z-40 w-[var(--atmo-sidebar-width,238px)] overflow-hidden rounded-[21px_18px_23px_19px] p-0 max-md:hidden',
|
|
54
|
+
className
|
|
55
|
+
)}
|
|
56
|
+
>
|
|
57
|
+
<nav aria-label={label} class="h-full overflow-y-auto overscroll-contain px-3 py-4">
|
|
58
|
+
{@render children()}
|
|
59
|
+
</nav>
|
|
60
|
+
</Surface>
|
|
61
|
+
{:else}
|
|
62
|
+
<Modal
|
|
63
|
+
{...modalAttributes}
|
|
64
|
+
bind:open
|
|
65
|
+
title={label}
|
|
66
|
+
onCloseAutoFocus={(event) => {
|
|
67
|
+
if (!mobile.current) {
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
}
|
|
70
|
+
}}
|
|
71
|
+
style={style ?? undefined}
|
|
72
|
+
data-slot="workspace-sidebar"
|
|
73
|
+
class={cn(
|
|
74
|
+
'top-[calc(var(--atmo-nav-top,0px)+12px)] bottom-3 left-3 flex h-auto max-h-none w-[min(280px,calc(100%-24px))] max-w-none translate-x-0 translate-y-0 flex-col overflow-hidden rounded-[21px_18px_23px_19px] bg-recess p-3 shadow-(--ui-recess-shadow) sm:p-3 [&>header]:mb-3 [&>header]:px-2 [&>header]:pt-2 [&>header_h2]:text-sm',
|
|
75
|
+
className
|
|
76
|
+
)}
|
|
77
|
+
>
|
|
78
|
+
<nav aria-label={label} class="min-h-0 flex-1 overflow-y-auto overscroll-contain">
|
|
79
|
+
{@render children()}
|
|
80
|
+
</nav>
|
|
81
|
+
</Modal>
|
|
82
|
+
{/if}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
type $$ComponentProps = Omit<HTMLAttributes<HTMLElement>, 'children'> & {
|
|
4
|
+
label: string;
|
|
5
|
+
open?: boolean;
|
|
6
|
+
children: Snippet;
|
|
7
|
+
};
|
|
8
|
+
declare const WorkspaceSidebar: import("svelte").Component<$$ComponentProps, {}, "open">;
|
|
9
|
+
type WorkspaceSidebar = ReturnType<typeof WorkspaceSidebar>;
|
|
10
|
+
export default WorkspaceSidebar;
|