@atmo-dev/kit 0.9.0 → 0.10.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.
Files changed (84) hide show
  1. package/README.md +27 -429
  2. package/dist/components/AccountMenu.svelte +7 -7
  3. package/dist/components/Avatar.svelte +1 -1
  4. package/dist/components/Badge.svelte +3 -3
  5. package/dist/components/Button.svelte +4 -3
  6. package/dist/components/Checkbox.svelte +31 -1
  7. package/dist/{events → components}/DatePicker.svelte +3 -3
  8. package/dist/components/ExternalEmbed.svelte +9 -6
  9. package/dist/components/GrainAlbumPicker.svelte +18 -9
  10. package/dist/components/GrainAlbumView.svelte +15 -6
  11. package/dist/components/Heading.svelte +1 -1
  12. package/dist/components/IconRail.svelte +11 -9
  13. package/dist/components/InlineEditor.svelte +3 -3
  14. package/dist/components/InsetImage.svelte +1 -1
  15. package/dist/components/Label.svelte +1 -1
  16. package/dist/components/LinkCard.svelte +6 -4
  17. package/dist/components/Modal.svelte +3 -3
  18. package/dist/components/NestedComments.svelte +9 -6
  19. package/dist/components/PhotoGrid.svelte +1 -1
  20. package/dist/components/Popover.svelte +1 -1
  21. package/dist/components/PostComposer.svelte +2 -2
  22. package/dist/components/PostContent.svelte +11 -9
  23. package/dist/components/PostVideo.svelte +1 -1
  24. package/dist/components/RichText.svelte +19 -7
  25. package/dist/components/Select.svelte +5 -2
  26. package/dist/components/Select.svelte.d.ts +2 -0
  27. package/dist/components/SocialClientPicker.svelte +1 -1
  28. package/dist/components/StreamplacePicker.svelte +1 -1
  29. package/dist/components/Subheading.svelte +4 -2
  30. package/dist/components/Surface.svelte +3 -2
  31. package/dist/components/Tabs.svelte +2 -2
  32. package/dist/{events → components}/TimePicker.svelte +10 -7
  33. package/dist/{events → components}/TimezonePicker.svelte +15 -7
  34. package/dist/components/ToggleGroup.svelte +1 -1
  35. package/dist/components/ToggleGroupItem.svelte +1 -1
  36. package/dist/components/UserProfile.svelte +16 -9
  37. package/dist/components/WorkspaceSidebar.svelte +1 -1
  38. package/dist/components/legal/LegalDocument.svelte +9 -3
  39. package/dist/components/legal/LegalFooter.svelte +2 -2
  40. package/dist/components/login/ActorSearchField.svelte +10 -6
  41. package/dist/components/login/AtmosphereApps.svelte +1 -1
  42. package/dist/components/login/LoginForm.svelte +15 -9
  43. package/dist/components/login/PermissionFields.svelte +9 -2
  44. package/dist/components/login/RecentAccounts.svelte +5 -3
  45. package/dist/events/EventAttendees.svelte +9 -3
  46. package/dist/events/EventCard.svelte +7 -5
  47. package/dist/events/EventComments.svelte +3 -3
  48. package/dist/events/EventEditor.svelte +20 -9
  49. package/dist/events/EventRsvp.svelte +10 -6
  50. package/dist/events/EventView.svelte +21 -7
  51. package/dist/events/StarterPackButton.svelte +3 -3
  52. package/dist/events/ThemePicker.svelte +7 -7
  53. package/dist/events/ThumbnailPresets.svelte +1 -1
  54. package/dist/events/VodPlayer.svelte +1 -1
  55. package/dist/events/editor/LinksSection.svelte +7 -3
  56. package/dist/events/editor/LocationSection.svelte +1 -1
  57. package/dist/events/editor/RecurringModal.svelte +6 -4
  58. package/dist/events/editor/ThemeSection.svelte +3 -1
  59. package/dist/events/event-view/EventDateBlock.svelte +3 -3
  60. package/dist/events/event-view/EventHostedBy.svelte +6 -2
  61. package/dist/events/event-view/EventLinksList.svelte +2 -2
  62. package/dist/events/event-view/EventLocationBlock.svelte +9 -5
  63. package/dist/events/event-view/EventLocationMap.svelte +4 -2
  64. package/dist/events/schedule/ConferenceTimetable.svelte +7 -7
  65. package/dist/events/schedule/DaySchedule.svelte +2 -2
  66. package/dist/events/schedule/ScheduleEventCell.svelte +2 -2
  67. package/dist/events/themes/Matrix.svelte +12 -6
  68. package/dist/events.d.ts +5 -5
  69. package/dist/events.js +6 -5
  70. package/dist/index.d.ts +5 -0
  71. package/dist/index.js +5 -0
  72. package/dist/social/mention-suggestions.js +4 -4
  73. package/dist/styles.d.ts +2 -2
  74. package/dist/styles.js +2 -2
  75. package/dist/theme.css +23 -44
  76. package/dist/theme.js +4 -12
  77. package/package.json +1 -1
  78. /package/dist/{events → components}/DatePicker.svelte.d.ts +0 -0
  79. /package/dist/{events → components}/DateTimePicker.svelte +0 -0
  80. /package/dist/{events → components}/DateTimePicker.svelte.d.ts +0 -0
  81. /package/dist/{events → components}/ImageDropper.svelte +0 -0
  82. /package/dist/{events → components}/ImageDropper.svelte.d.ts +0 -0
  83. /package/dist/{events → components}/TimePicker.svelte.d.ts +0 -0
  84. /package/dist/{events → components}/TimezonePicker.svelte.d.ts +0 -0
@@ -87,7 +87,7 @@
87
87
  >{replacing ? 'Replace stream' : 'Add stream'}</Button
88
88
  >
89
89
  </div>
90
- {#if replacing}<p class="mt-3 text-sm text-muted">
90
+ {#if replacing}<p class="mt-3 text-sm text-base-600 dark:text-base-400">
91
91
  This replaces the current Streamplace link.
92
92
  </p>{/if}
93
93
  {#if error}<p class="mt-3 text-sm text-red-600 dark:text-red-400" role="alert">{error}</p>{/if}
@@ -17,6 +17,8 @@
17
17
  this={`h${level}`}
18
18
  {...rest}
19
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
20
+ class={cn(
21
+ 'm-0 text-lg leading-snug font-medium tracking-tight text-base-950 dark:text-base-50',
22
+ className
23
+ )}>{@render children?.()}</svelte:element
22
24
  >
@@ -28,8 +28,9 @@
28
28
  bind:this={ref}
29
29
  data-slot="surface"
30
30
  class={cn(
31
- 'rounded-panel p-6 text-ink',
32
- variant === 'recessed' && 'border border-line bg-recess shadow-(--ui-recess-shadow)',
31
+ 'rounded-panel p-6 text-base-950 dark:text-base-50',
32
+ variant === 'recessed' &&
33
+ 'border border-base-300 bg-[color-mix(in_srgb,var(--base-100)_75%,var(--base-200))] shadow-[inset_0_2px_4px_color-mix(in_srgb,var(--base-950)_8%,transparent),inset_0_5px_12px_color-mix(in_srgb,var(--base-950)_2%,transparent)] dark:border-[color-mix(in_srgb,var(--base-800)_80%,var(--base-950))] dark:bg-base-950 dark:shadow-[inset_0_2px_4px_#0006,inset_0_5px_12px_#0002]',
33
34
  as === 'button' &&
34
35
  cn(
35
36
  'cursor-pointer touch-manipulation disabled:pointer-events-none disabled:opacity-45',
@@ -29,13 +29,13 @@
29
29
  <Primitive.Root {...rest} bind:value class={cn('min-w-0', className)}>
30
30
  <Primitive.List
31
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)]"
32
+ class="flex w-fit max-w-full flex-wrap items-center gap-1 rounded-[12px_14px_11px_13px] border border-base-300 bg-[color-mix(in_srgb,var(--base-100)_75%,var(--base-200))] p-1 shadow-[inset_0_2px_4px_color-mix(in_srgb,var(--base-950)_8%,transparent)] dark:border-[color-mix(in_srgb,var(--base-800)_80%,var(--base-950))] dark:bg-base-950 dark:shadow-[inset_0_2px_4px_#0006]"
33
33
  >
34
34
  {#each items as item (item.value)}<Primitive.Trigger
35
35
  value={item.value}
36
36
  disabled={item.disabled}
37
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',
38
+ 'cursor-pointer rounded-[8px_10px_7px_9px] px-3.5 py-1.75 text-[.8125rem] leading-normal text-base-600 hover:text-base-950 disabled:cursor-default disabled:opacity-45 data-[state=active]:bg-base-50 data-[state=active]:text-base-950 dark:text-base-400 dark:hover:text-base-50 dark:data-[state=active]:bg-base-900 dark:data-[state=active]:text-base-50',
39
39
  focus
40
40
  )}>{item.label}</Primitive.Trigger
41
41
  >{/each}
@@ -2,7 +2,9 @@
2
2
  import { TimeField } from 'bits-ui';
3
3
  import { Time } from '@internationalized/date';
4
4
  import { untrack } from 'svelte';
5
- import { Icon, IconButton, Popover } from '../index.js';
5
+ import Icon from './Icon.svelte';
6
+ import IconButton from './IconButton.svelte';
7
+ import Popover from './Popover.svelte';
6
8
  import { Clock } from '@sketchyicons/svelte';
7
9
 
8
10
  let {
@@ -59,7 +61,7 @@
59
61
  </script>
60
62
 
61
63
  <div
62
- class="flex h-11 items-center gap-1 rounded-ui border border-line bg-recess px-2 text-sm text-ink shadow-(--ui-recess-shadow) focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-focus hover:border-control-hover"
64
+ class="flex h-11 items-center gap-1 rounded-ui border border-base-300 bg-[color-mix(in_srgb,var(--base-100)_75%,var(--base-200))] px-2 text-sm text-base-950 shadow-[inset_0_2px_4px_color-mix(in_srgb,var(--base-950)_8%,transparent),inset_0_5px_12px_color-mix(in_srgb,var(--base-950)_2%,transparent)] focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-accent-700 hover:border-base-400 dark:border-[color-mix(in_srgb,var(--base-800)_80%,var(--base-950))] dark:bg-base-950 dark:text-base-50 dark:shadow-[inset_0_2px_4px_#0006,inset_0_5px_12px_#0002] dark:focus-within:outline-accent-300 dark:hover:border-base-700"
63
65
  >
64
66
  <TimeField.Root
65
67
  bind:value={internalValue}
@@ -71,10 +73,11 @@
71
73
  <TimeField.Label class="sr-only">{label}</TimeField.Label>
72
74
  <TimeField.Input class="whitespace-nowrap">
73
75
  {#snippet children({ segments })}{#each segments as segment, i (segment.part + i)}
74
- {#if segment.part === 'literal'}<span class="text-muted">{segment.value}</span
76
+ {#if segment.part === 'literal'}<span class="text-base-600 dark:text-base-400"
77
+ >{segment.value}</span
75
78
  >{:else}<TimeField.Segment
76
79
  part={segment.part}
77
- class="rounded px-0.5 hover:bg-recess focus:bg-accent-soft focus:outline-none"
80
+ class="rounded px-0.5 hover:bg-[color-mix(in_srgb,var(--base-100)_75%,var(--base-200))] focus:bg-accent-50 focus:outline-none dark:hover:bg-base-950 dark:focus:bg-[color-mix(in_srgb,var(--accent-950)_65%,var(--base-950))]"
78
81
  >{segment.value}</TimeField.Segment
79
82
  >{/if}
80
83
  {/each}{/snippet}
@@ -101,15 +104,15 @@
101
104
  <div bind:this={listEl}>
102
105
  {#each slots as slot (slot.key)}<button
103
106
  type="button"
104
- class="flex w-full items-center justify-between gap-4 rounded-ui px-3 py-1.5 text-left text-sm text-ink hover:bg-recess aria-pressed:bg-accent-soft aria-pressed:text-action"
107
+ class="flex w-full items-center justify-between gap-4 rounded-ui px-3 py-1.5 text-left text-sm text-base-950 hover:bg-[color-mix(in_srgb,var(--base-100)_75%,var(--base-200))] aria-pressed:bg-accent-50 aria-pressed:text-accent-700 dark:text-base-50 dark:hover:bg-base-950 dark:aria-pressed:bg-[color-mix(in_srgb,var(--accent-950)_65%,var(--base-950))] dark:aria-pressed:text-accent-300"
105
108
  aria-pressed={value === slot.key}
106
109
  data-selected={value === slot.key ? '' : undefined}
107
110
  onclick={() => {
108
111
  value = slot.key;
109
112
  isOpen = false;
110
113
  }}
111
- >{slot.label}{#if durationLabel(slot.key)}<span class="text-xs text-muted"
112
- >{durationLabel(slot.key)}</span
114
+ >{slot.label}{#if durationLabel(slot.key)}<span
115
+ class="text-xs text-base-600 dark:text-base-400">{durationLabel(slot.key)}</span
113
116
  >{/if}</button
114
117
  >{/each}
115
118
  </div>
@@ -1,5 +1,8 @@
1
1
  <script lang="ts">
2
- import { Button, Icon, Input, Popover } from '../index.js';
2
+ import Button from './Button.svelte';
3
+ import Icon from './Icon.svelte';
4
+ import Input from './Input.svelte';
5
+ import Popover from './Popover.svelte';
3
6
  import { Globe } from '@sketchyicons/svelte';
4
7
  let { value = $bindable('') }: { value: string } = $props();
5
8
  let isOpen = $state(false);
@@ -38,12 +41,12 @@
38
41
  {#snippet trigger({ props })}<Button
39
42
  {...props}
40
43
  variant="secondary"
41
- class="min-h-11 w-full justify-start gap-2.5 border-line bg-recess px-3 text-xs shadow-(--ui-recess-shadow) hover:border-control-hover"
44
+ class="min-h-11 w-full justify-start gap-2.5 border-base-300 bg-[color-mix(in_srgb,var(--base-100)_75%,var(--base-200))] px-3 text-xs shadow-[inset_0_2px_4px_color-mix(in_srgb,var(--base-950)_8%,transparent),inset_0_5px_12px_color-mix(in_srgb,var(--base-950)_2%,transparent)] hover:border-base-400 dark:border-[color-mix(in_srgb,var(--base-800)_80%,var(--base-950))] dark:bg-base-950 dark:shadow-[inset_0_2px_4px_#0006,inset_0_5px_12px_#0002] dark:hover:border-base-700"
42
45
  aria-label={`Timezone: ${value}`}
43
46
  >
44
- <Icon img={Globe} size={17} class="text-muted" />
47
+ <Icon img={Globe} size={17} class="text-base-600 dark:text-base-400" />
45
48
  <span class="min-w-0 flex-1 truncate text-left">{getCityName(value)}</span>
46
- <span class="shrink-0 text-muted">{getOffset(value)}</span>
49
+ <span class="shrink-0 text-base-600 dark:text-base-400">{getOffset(value)}</span>
47
50
  </Button>{/snippet}
48
51
  <Input
49
52
  type="search"
@@ -55,14 +58,19 @@
55
58
  <div class="max-h-60 overflow-y-auto">
56
59
  {#each filtered as tz (tz)}<button
57
60
  type="button"
58
- class="flex w-full items-center justify-between gap-3 rounded-ui px-3 py-2 text-left text-xs text-ink hover:bg-recess aria-pressed:bg-accent-soft aria-pressed:text-action"
61
+ class="flex w-full items-center justify-between gap-3 rounded-ui px-3 py-2 text-left text-xs text-base-950 hover:bg-[color-mix(in_srgb,var(--base-100)_75%,var(--base-200))] aria-pressed:bg-accent-50 aria-pressed:text-accent-700 dark:text-base-50 dark:hover:bg-base-950 dark:aria-pressed:bg-[color-mix(in_srgb,var(--accent-950)_65%,var(--base-950))] dark:aria-pressed:text-accent-300"
59
62
  aria-pressed={value === tz}
60
63
  onclick={() => {
61
64
  value = tz;
62
65
  isOpen = false;
63
66
  search = '';
64
- }}><span>{getCityName(tz)}</span><span class="text-muted">{getOffset(tz)}</span></button
67
+ }}
68
+ ><span>{getCityName(tz)}</span><span class="text-base-600 dark:text-base-400"
69
+ >{getOffset(tz)}</span
70
+ ></button
65
71
  >{/each}
66
- {#if !filtered.length}<p class="p-3 text-xs text-muted">No results</p>{/if}
72
+ {#if !filtered.length}<p class="p-3 text-xs text-base-600 dark:text-base-400">
73
+ No results
74
+ </p>{/if}
67
75
  </div>
68
76
  </Popover>
@@ -24,7 +24,7 @@
24
24
  bind:value
25
25
  data-size={size}
26
26
  class={cn(
27
- 'inline-flex flex-wrap gap-1 rounded-ui bg-recess p-1 [box-shadow:var(--ui-recess-shadow)]',
27
+ 'inline-flex flex-wrap gap-1 rounded-ui bg-[color-mix(in_srgb,var(--base-100)_75%,var(--base-200))] p-1 shadow-[inset_0_2px_4px_color-mix(in_srgb,var(--base-950)_8%,transparent),inset_0_5px_12px_color-mix(in_srgb,var(--base-950)_2%,transparent)] dark:bg-base-950 dark:shadow-[inset_0_2px_4px_#0006,inset_0_5px_12px_#0002]',
28
28
  className
29
29
  )}
30
30
  >
@@ -16,7 +16,7 @@
16
16
  <ToggleGroup.Item
17
17
  {...rest}
18
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',
19
+ 'cursor-pointer rounded-ui px-3 py-1.5 text-xs font-medium text-base-600 transition-colors duration-(--atmo-duration) hover:text-base-950 disabled:pointer-events-none disabled:opacity-45 data-[state=on]:bg-base-50 data-[state=on]:text-accent-700 motion-reduce:transition-none dark:text-base-400 dark:hover:text-base-50 dark:data-[state=on]:bg-base-900 dark:data-[state=on]:text-accent-300',
20
20
  focus,
21
21
  size === 'xs' && 'px-2 py-1 text-[.6875rem]',
22
22
  className
@@ -50,11 +50,11 @@
50
50
  let pronouns = $derived(profile.pronouns?.trim().toLowerCase());
51
51
  </script>
52
52
 
53
- <section class={cn('min-w-0 text-ink', className)} aria-label="Profile">
53
+ <section class={cn('min-w-0 text-base-950 dark:text-base-50', className)} aria-label="Profile">
54
54
  {#if banner}
55
55
  <div
56
56
  data-slot="profile-banner"
57
- class="relative aspect-3/1 w-full overflow-hidden rounded-panel bg-recess"
57
+ class="relative aspect-3/1 w-full overflow-hidden rounded-panel bg-[color-mix(in_srgb,var(--base-100)_75%,var(--base-200))] dark:bg-base-950"
58
58
  >
59
59
  <img
60
60
  src={banner}
@@ -75,7 +75,10 @@
75
75
  {name}
76
76
  src={safeProfileUrl(profile.avatar)}
77
77
  size={96}
78
- class={cn('relative size-20 sm:size-24', banner && '-mt-10 ring-4 ring-page sm:-mt-12')}
78
+ class={cn(
79
+ 'relative size-20 sm:size-24',
80
+ banner && '-mt-10 ring-4 ring-base-50 sm:-mt-12 dark:ring-base-925'
81
+ )}
79
82
  />
80
83
  <div class={cn('flex flex-wrap items-center gap-2', banner && 'pt-3')}>
81
84
  <Button {href} target="_blank" rel="noopener noreferrer" variant="secondary" size="sm">
@@ -88,7 +91,9 @@
88
91
  <h1 class="text-2xl font-semibold tracking-tight wrap-anywhere sm:text-3xl">
89
92
  <bdi>{name}</bdi>
90
93
  </h1>
91
- <div class="mt-1 flex flex-wrap items-baseline gap-x-3 gap-y-1 text-sm text-muted">
94
+ <div
95
+ class="mt-1 flex flex-wrap items-baseline gap-x-3 gap-y-1 text-sm text-base-600 dark:text-base-400"
96
+ >
92
97
  {#if profile.handle}<a
93
98
  {href}
94
99
  target="_blank"
@@ -103,7 +108,7 @@
103
108
  {#each displayedMetrics as metric (metric.label)}
104
109
  {#if metric.value !== undefined}<div class="flex gap-1">
105
110
  <dd class="font-semibold">{metric.value.toLocaleString('en')}</dd>
106
- <dt class="text-muted">{metric.label}</dt>
111
+ <dt class="text-base-600 dark:text-base-400">{metric.label}</dt>
107
112
  </div>{/if}
108
113
  {/each}
109
114
  </dl>
@@ -114,7 +119,7 @@
114
119
  href={segment.href}
115
120
  target={segment.href.startsWith('/') ? undefined : '_blank'}
116
121
  rel={segment.href.startsWith('/') ? undefined : 'noopener noreferrer nofollow ugc'}
117
- class="text-action underline decoration-action/40 underline-offset-2 hover:decoration-action"
122
+ class="text-accent-700 underline decoration-accent-700/40 underline-offset-2 hover:decoration-accent-700 dark:text-accent-300 dark:decoration-accent-300/40 dark:hover:decoration-accent-300"
118
123
  >{segment.text}</a
119
124
  >{:else}{segment.text}{/if}{/each}
120
125
  </p>
@@ -123,11 +128,13 @@
123
128
  <ul aria-label="Profile links" class="mt-4 flex flex-wrap gap-2">
124
129
  {#each links as link (link.url)}
125
130
  <li class="max-w-full min-w-0">
126
- <a
131
+ <Button
127
132
  href={link.url}
128
133
  target="_blank"
129
134
  rel="noopener noreferrer nofollow ugc"
130
- class="inline-flex max-w-full items-center gap-2 rounded-ui border border-line px-3 py-1.5 text-sm hover:bg-recess"
135
+ variant="secondary"
136
+ size="sm"
137
+ class="max-w-full"
131
138
  >
132
139
  {#if link.icon && failedLinkIcons[link.url] !== link.icon}
133
140
  <img
@@ -143,7 +150,7 @@
143
150
  />
144
151
  {/if}
145
152
  <span class="min-w-0 wrap-anywhere">{link.title || new URL(link.url).hostname}</span>
146
- </a>
153
+ </Button>
147
154
  </li>
148
155
  {/each}
149
156
  </ul>
@@ -71,7 +71,7 @@
71
71
  style={style ?? undefined}
72
72
  data-slot="workspace-sidebar"
73
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',
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-[color-mix(in_srgb,var(--base-100)_75%,var(--base-200))] p-3 shadow-[inset_0_2px_4px_color-mix(in_srgb,var(--base-950)_8%,transparent),inset_0_5px_12px_color-mix(in_srgb,var(--base-950)_2%,transparent)] sm:p-3 dark:bg-base-950 dark:shadow-[inset_0_2px_4px_#0006,inset_0_5px_12px_#0002] [&>header]:mb-3 [&>header]:px-2 [&>header]:pt-2 [&>header_h2]:text-sm',
75
75
  className
76
76
  )}
77
77
  >
@@ -13,11 +13,17 @@
13
13
  const uid = $props.id();
14
14
  </script>
15
15
 
16
- <article {...rest} class={cn('mx-auto max-w-3xl px-6 py-10 text-sm leading-7 text-ink', className)}>
16
+ <article
17
+ {...rest}
18
+ class={cn(
19
+ 'mx-auto max-w-3xl px-6 py-10 text-sm leading-7 text-base-950 dark:text-base-50',
20
+ className
21
+ )}
22
+ >
17
23
  <header class="mb-8">
18
24
  <h1 class="m-0 text-3xl font-semibold tracking-tight">{document.title}</h1>
19
25
  {#if document.updated}
20
- <p class="mt-3 text-muted">
26
+ <p class="mt-3 text-base-600 dark:text-base-400">
21
27
  Last updated: <time datetime={document.updated}>{document.updated}</time>
22
28
  </p>
23
29
  {/if}
@@ -44,7 +50,7 @@
44
50
  <li>
45
51
  {#if safeLegalHref(link.href, true)}<a
46
52
  href={safeLegalHref(link.href, true)}
47
- class="rounded underline underline-offset-4 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-focus"
53
+ class="rounded underline underline-offset-4 focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-accent-700 dark:focus-visible:outline-accent-300"
48
54
  >{link.label}</a
49
55
  >{:else}{link.label}{/if}
50
56
  </li>
@@ -17,11 +17,11 @@
17
17
  const showReportAction = $derived(links.report !== false && !!reportAction);
18
18
  const items = $derived(legalFooterItems(showReportAction ? { ...links, report: false } : links));
19
19
  const linkClass =
20
- 'rounded text-inherit underline-offset-4 hover:text-ink hover:underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-focus';
20
+ 'rounded text-inherit underline-offset-4 hover:text-base-950 dark:hover:text-base-50 hover:underline focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-accent-700 dark:focus-visible:outline-accent-300';
21
21
  </script>
22
22
 
23
23
  {#if items.length || showReportAction}
24
- <footer {...rest} class={cn('py-8 text-xs text-muted', className)}>
24
+ <footer {...rest} class={cn('py-8 text-xs text-base-600 dark:text-base-400', className)}>
25
25
  <nav aria-label="Legal and contact">
26
26
  <ul class="m-0 flex list-none flex-wrap items-center justify-center gap-x-5 gap-y-3 p-0">
27
27
  {#each items as item, index (index)}
@@ -145,7 +145,7 @@
145
145
  <Icon
146
146
  img={AtSign}
147
147
  size={18}
148
- class="pointer-events-none absolute top-[13px] left-3 z-1 text-muted"
148
+ class="pointer-events-none absolute top-[13px] left-3 z-1 text-base-600 dark:text-base-400"
149
149
  />
150
150
  {#if searchActors}
151
151
  <Combobox.Root
@@ -190,12 +190,12 @@
190
190
  sideOffset={6}
191
191
  collisionPadding={12}
192
192
  style={inherited}
193
- class="z-70 max-h-[min(20rem,var(--bits-combobox-content-available-height))] w-(--bits-combobox-anchor-width) min-w-52 overflow-y-auto overscroll-contain rounded-ui border border-line bg-field p-1.5 font-sans text-ink outline-none"
193
+ class="z-70 max-h-[min(20rem,var(--bits-combobox-content-available-height))] w-(--bits-combobox-anchor-width) min-w-52 overflow-y-auto overscroll-contain rounded-ui border border-base-300 bg-[color-mix(in_srgb,var(--base-100)_75%,var(--base-200))] p-1.5 font-sans text-base-950 outline-none dark:border-[color-mix(in_srgb,var(--base-800)_80%,var(--base-950))] dark:bg-base-975 dark:text-base-50"
194
194
  >
195
195
  {#each results as actor (actor.did)}<Combobox.Item
196
196
  value={actor.handle}
197
197
  label={actor.handle}
198
- class="flex min-h-14 cursor-pointer items-center gap-3 rounded-ui px-2.5 py-2 outline-none data-highlighted:bg-accent-soft data-highlighted:text-action"
198
+ class="flex min-h-14 cursor-pointer items-center gap-3 rounded-ui px-2.5 py-2 outline-none data-highlighted:bg-accent-50 data-highlighted:text-accent-700 dark:data-highlighted:bg-[color-mix(in_srgb,var(--accent-950)_65%,var(--base-950))] dark:data-highlighted:text-accent-300"
199
199
  ><Avatar
200
200
  name={actorName(actor)}
201
201
  src={actor.avatar}
@@ -203,7 +203,8 @@
203
203
  aria-hidden="true"
204
204
  /><span class="grid min-w-0 gap-0.5"
205
205
  ><strong class="truncate text-[.8125rem] font-medium">{actorName(actor)}</strong
206
- >{#if actor.displayName}<span class="truncate text-xs text-muted"
206
+ >{#if actor.displayName}<span
207
+ class="truncate text-xs text-base-600 dark:text-base-400"
207
208
  >@{actor.handle}</span
208
209
  >{/if}</span
209
210
  ></Combobox.Item
@@ -214,7 +215,7 @@
214
215
  {#if status === 'loading'}<Icon
215
216
  img={LoaderCircle}
216
217
  size={16}
217
- class="pointer-events-none absolute top-3.5 right-3 text-muted motion-safe:animate-spin"
218
+ class="pointer-events-none absolute top-3.5 right-3 text-base-600 motion-safe:animate-spin dark:text-base-400"
218
219
  />{/if}
219
220
  {:else}<Input
220
221
  {id}
@@ -232,7 +233,10 @@
232
233
  data-autofocus
233
234
  class="pl-10"
234
235
  />{/if}
235
- {#if message}<p id={`${uid}-status`} class="mt-2 text-xs leading-relaxed text-muted">
236
+ {#if message}<p
237
+ id={`${uid}-status`}
238
+ class="mt-2 text-xs leading-relaxed text-base-600 dark:text-base-400"
239
+ >
236
240
  {message}
237
241
  </p>{/if}
238
242
  <span class="sr-only" role="status">{announcement}</span>
@@ -13,7 +13,7 @@
13
13
  <!-- Existing brand marks, not replacement UI icons. Static: no endless decorative motion. -->
14
14
  <div class="flex items-center justify-between gap-2 py-2" aria-hidden="true">
15
15
  {#each apps as src (src)}<span
16
- class="size-5 shrink-0 bg-muted [mask-size:contain] [mask-position:center] [mask-repeat:no-repeat] opacity-70 sm:size-6"
16
+ class="size-5 shrink-0 bg-base-600 [mask-size:contain] [mask-position:center] [mask-repeat:no-repeat] opacity-70 sm:size-6 dark:bg-base-400"
17
17
  class:scale-125={src === muSocial}
18
18
  style:mask-image={`url("${src}")`}
19
19
  ></span>{/each}
@@ -250,7 +250,7 @@
250
250
  bind:this={ref}
251
251
  aria-label={rest['aria-label'] ?? headingText}
252
252
  aria-busy={busy}
253
- class={cn('grid w-full min-w-0 gap-4 text-ink', className)}
253
+ class={cn('grid w-full min-w-0 gap-4 text-base-950 dark:text-base-50', className)}
254
254
  data-slot="login-form"
255
255
  novalidate
256
256
  onsubmit={(event) => {
@@ -266,7 +266,9 @@
266
266
  tabindex={step === 'login' ? undefined : -1}
267
267
  class="text-[1.375rem] leading-snug tracking-tight outline-none">{headingText}</Heading
268
268
  >
269
- {#if descriptionText}<p class="text-[.8125rem] leading-relaxed text-muted">
269
+ {#if descriptionText}<p
270
+ class="text-[.8125rem] leading-relaxed text-base-600 dark:text-base-400"
271
+ >
270
272
  {descriptionText}
271
273
  </p>{/if}
272
274
  </header>{/if}
@@ -290,7 +292,7 @@
290
292
  >
291
293
  {:else}
292
294
  {#if selected}<div
293
- class="flex min-h-15 items-center gap-3 rounded-ui border border-line bg-field py-2 pr-2 pl-3"
295
+ class="flex min-h-15 items-center gap-3 rounded-ui border border-base-300 bg-[color-mix(in_srgb,var(--base-100)_75%,var(--base-200))] py-2 pr-2 pl-3 dark:border-[color-mix(in_srgb,var(--base-800)_80%,var(--base-950))] dark:bg-base-975"
294
296
  data-slot="selected-account"
295
297
  >
296
298
  <Avatar
@@ -300,8 +302,8 @@
300
302
  aria-hidden="true"
301
303
  /><span class="grid min-w-0 flex-1 gap-0.5"
302
304
  ><strong class="truncate text-[.8125rem] font-medium">{actorName(selected)}</strong
303
- >{#if selected.displayName}<span class="truncate text-xs text-muted"
304
- >@{selected.handle}</span
305
+ >{#if selected.displayName}<span
306
+ class="truncate text-xs text-base-600 dark:text-base-400">@{selected.handle}</span
305
307
  >{/if}</span
306
308
  ><IconButton
307
309
  label={`Clear @${selected.handle}`}
@@ -336,8 +338,10 @@
336
338
  />{/if}</Button
337
339
  >
338
340
  {/if}
339
- {#if signup}<div class="grid gap-3 border-t border-line pt-4">
340
- <p class="text-[.8125rem] text-muted">Don't have an account?</p>
341
+ {#if signup}<div
342
+ class="grid gap-3 border-t border-base-300 pt-4 dark:border-[color-mix(in_srgb,var(--base-800)_80%,var(--base-950))]"
343
+ >
344
+ <p class="text-[.8125rem] text-base-600 dark:text-base-400">Don't have an account?</p>
341
345
  <Button
342
346
  variant="secondary"
343
347
  disabled={busy}
@@ -346,7 +350,9 @@
346
350
  >
347
351
  </div>{/if}
348
352
  {:else if step === 'permissions'}
349
- {#if pending}<p class="flex min-w-0 items-center gap-2 text-xs text-muted">
353
+ {#if pending}<p
354
+ class="flex min-w-0 items-center gap-2 text-xs text-base-600 dark:text-base-400"
355
+ >
350
356
  <span class="shrink-0">Logging in as</span>
351
357
  {#if pending.actor}<Avatar
352
358
  name={actorName(pending.actor)}
@@ -371,7 +377,7 @@
371
377
  {#if error}<p
372
378
  id={`${uid}-error`}
373
379
  role="alert"
374
- class="red flex items-start gap-2 text-xs leading-relaxed text-action"
380
+ class="red flex items-start gap-2 text-xs leading-relaxed text-accent-700 dark:text-accent-300"
375
381
  >
376
382
  <Icon img={TriangleAlert} size={16} class="mt-0.5 shrink-0" />{error}
377
383
  </p>{/if}
@@ -23,7 +23,11 @@
23
23
  <legend class="sr-only">Requested permissions</legend>
24
24
  {#each permissions as permission, index (permission.id)}
25
25
  <div class="flex items-start gap-3">
26
- <Icon img={permission.icon ?? ShieldCheck} size={20} class="mt-1 shrink-0 text-muted" />
26
+ <Icon
27
+ img={permission.icon ?? ShieldCheck}
28
+ size={20}
29
+ class="mt-1 shrink-0 text-base-600 dark:text-base-400"
30
+ />
27
31
  <div class="min-w-0 flex-1 space-y-1.5">
28
32
  <Label
29
33
  id={`${uid}-${index}-label`}
@@ -32,7 +36,10 @@
32
36
  >
33
37
  {permission.label}{permission.required ? ' (required)' : ''}
34
38
  </Label>
35
- <p id={`${uid}-${index}-description`} class="text-xs leading-relaxed text-muted">
39
+ <p
40
+ id={`${uid}-${index}-description`}
41
+ class="text-xs leading-relaxed text-base-600 dark:text-base-400"
42
+ >
36
43
  {permission.description}
37
44
  </p>
38
45
  </div>
@@ -29,7 +29,7 @@
29
29
 
30
30
  <div class="grid gap-2" bind:this={root} aria-label="Recent accounts">
31
31
  {#each accounts as actor, index (actor.did)}<div
32
- class="flex min-w-0 items-center gap-1 rounded-ui border border-line bg-field"
32
+ class="flex min-w-0 items-center gap-1 rounded-ui border border-base-300 bg-[color-mix(in_srgb,var(--base-100)_75%,var(--base-200))] dark:border-[color-mix(in_srgb,var(--base-800)_80%,var(--base-950))] dark:bg-base-975"
33
33
  >
34
34
  <Button
35
35
  data-account
@@ -41,8 +41,10 @@
41
41
  >
42
42
  <Avatar name={actorName(actor)} src={actor.avatar} size={34} aria-hidden="true" />
43
43
  <span class="grid min-w-0 flex-1 gap-0.5"
44
- ><strong class="truncate text-[.8125rem] font-medium text-ink">{actorName(actor)}</strong
45
- >{#if actor.displayName}<span class="truncate text-xs text-muted">@{actor.handle}</span
44
+ ><strong class="truncate text-[.8125rem] font-medium text-base-950 dark:text-base-50"
45
+ >{actorName(actor)}</strong
46
+ >{#if actor.displayName}<span class="truncate text-xs text-base-600 dark:text-base-400"
47
+ >@{actor.handle}</span
46
48
  >{/if}</span
47
49
  ><Icon img={ArrowRight} size={16} />
48
50
  </Button>
@@ -102,7 +102,10 @@
102
102
  >
103
103
  <p class="mb-2 text-sm text-base-900 dark:text-base-50">
104
104
  <span class="font-bold">{goingCount}</span>
105
- <span class="text-xs font-semibold tracking-wider text-muted uppercase">Going</span>
105
+ <span
106
+ class="text-xs font-semibold tracking-wider text-base-600 uppercase dark:text-base-400"
107
+ >Going</span
108
+ >
106
109
  </p>
107
110
  <div class="flex items-center">
108
111
  <div class="flex flex-wrap -space-y-2 -space-x-4 pr-4">
@@ -139,7 +142,10 @@
139
142
  >
140
143
  <p class="mb-2 text-sm text-base-900 dark:text-base-50">
141
144
  <span class="font-bold">{interestedCount}</span>
142
- <span class="text-xs font-semibold tracking-wider text-muted uppercase">Interested</span>
145
+ <span
146
+ class="text-xs font-semibold tracking-wider text-base-600 uppercase dark:text-base-400"
147
+ >Interested</span
148
+ >
143
149
  </p>
144
150
  <div class="flex items-center">
145
151
  <div class="flex flex-wrap -space-y-2 -space-x-4 pr-4">
@@ -188,7 +194,7 @@
188
194
  {person.name}
189
195
  </p>
190
196
  {#if person.handle}
191
- <p class="truncate text-xs text-muted">
197
+ <p class="truncate text-xs text-base-600 dark:text-base-400">
192
198
  @{person.handle}
193
199
  </p>
194
200
  {/if}
@@ -86,7 +86,7 @@
86
86
 
87
87
  <a
88
88
  href={eventUrl(event, actor)}
89
- class="group grid grid-cols-[5rem_minmax(0,1fr)] gap-3 rounded-ui outline-offset-4 transition-colors focus-visible:outline-2 focus-visible:outline-focus sm:grid-cols-[6rem_minmax(0,1fr)] sm:gap-3.5"
89
+ class="group grid grid-cols-[5rem_minmax(0,1fr)] gap-3 rounded-ui outline-offset-4 transition-colors focus-visible:outline-2 focus-visible:outline-accent-700 sm:grid-cols-[6rem_minmax(0,1fr)] sm:gap-3.5 dark:focus-visible:outline-accent-300"
90
90
  >
91
91
  <div class="w-full">
92
92
  {#if thumbnail}
@@ -94,11 +94,11 @@
94
94
  src={thumbnail.url}
95
95
  alt={thumbnail.alt}
96
96
  loading="lazy"
97
- class="block aspect-square w-full rounded-[14px_12px_15px_13px] border border-line object-cover"
97
+ class="block aspect-square w-full rounded-[14px_12px_15px_13px] border border-base-300 object-cover dark:border-[color-mix(in_srgb,var(--base-800)_80%,var(--base-950))]"
98
98
  />
99
99
  {:else}
100
100
  <div
101
- class="aspect-square w-full overflow-hidden rounded-[14px_12px_15px_13px] border border-line [&>svg]:h-full [&>svg]:w-full"
101
+ class="aspect-square w-full overflow-hidden rounded-[14px_12px_15px_13px] border border-base-300 dark:border-[color-mix(in_srgb,var(--base-800)_80%,var(--base-950))] [&>svg]:h-full [&>svg]:w-full"
102
102
  >
103
103
  <Avatar
104
104
  size={96}
@@ -112,7 +112,7 @@
112
112
  </div>
113
113
 
114
114
  <div class="min-w-0 self-center">
115
- <p class="flex items-center gap-1.5 text-xs font-medium text-muted">
115
+ <p class="flex items-center gap-1.5 text-xs font-medium text-base-600 dark:text-base-400">
116
116
  <Icon img={CalendarDays} size={14} class="shrink-0" />
117
117
  {#if isOngoing && event.endsAt}
118
118
  Ends {formatEndsAt(event.endsAt)}
@@ -132,7 +132,9 @@
132
132
  <span class="line-clamp-2">{event.name}</span>
133
133
  </h3>
134
134
  {#if location || mode}
135
- <p class="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-muted">
135
+ <p
136
+ class="mt-1 flex flex-wrap items-center gap-x-2 gap-y-1 text-xs text-base-600 dark:text-base-400"
137
+ >
136
138
  {#if location}
137
139
  <span class="inline-flex max-w-full min-w-0 items-center gap-1.5" title={location}>
138
140
  <Icon img={MapPin} size={14} class="shrink-0" />
@@ -80,11 +80,11 @@
80
80
  {/if}
81
81
 
82
82
  {#if loading}
83
- <p class="text-sm text-muted">Loading comments…</p>
83
+ <p class="text-sm text-base-600 dark:text-base-400">Loading comments…</p>
84
84
  {:else if errorMessage}
85
- <p class="text-sm text-muted">{errorMessage}</p>
85
+ <p class="text-sm text-base-600 dark:text-base-400">{errorMessage}</p>
86
86
  {:else if comments.length === 0}
87
- <p class="text-sm text-muted">No comments yet.</p>
87
+ <p class="text-sm text-base-600 dark:text-base-400">No comments yet.</p>
88
88
  {:else}
89
89
  <div class="not-prose comments-no-divider">
90
90
  <NestedComments {comments} {socialClient} />