-
+
Profile unavailable
@@ -580,7 +580,7 @@ function ProfileErrorView(props: { error: string | null; onRetry: () => void })
type="button"
class="ui-control ui-control-hoverable inline-flex items-center justify-center gap-2 rounded-full px-4 py-2 text-sm font-medium text-on-surface"
onClick={() => props.onRetry()}>
-
+
Retry
diff --git a/src/components/rail/AppRailButton.tsx b/src/components/rail/AppRailButton.tsx
index a09c357..f706d36 100644
--- a/src/components/rail/AppRailButton.tsx
+++ b/src/components/rail/AppRailButton.tsx
@@ -13,7 +13,7 @@ function RailButtonContent(props: RailButtonVisualProps) {
return (
<>
-
+
0}>
void; lo
when={props.loadingMore}
fallback={
<>
-
+
Load More
>
}>
-
+
Loading more...
@@ -467,9 +467,7 @@ function SavedPostsHeader(
class="inline-flex h-10 items-center gap-2 rounded-full border-0 bg-surface-container-high px-4 text-sm font-medium text-on-surface-variant transition duration-150 hover:-translate-y-px hover:text-on-surface disabled:cursor-not-allowed disabled:opacity-60"
disabled={props.loading}
onClick={() => props.onRefresh()}>
- }>
-
-
+ } />
Refreshing...
diff --git a/src/components/search/HashtagPanel.tsx b/src/components/search/HashtagPanel.tsx
index 17102b1..6ae976a 100644
--- a/src/components/search/HashtagPanel.tsx
+++ b/src/components/search/HashtagPanel.tsx
@@ -108,7 +108,7 @@ export function HashtagPanel() {
}>
diff --git a/src/components/search/LocalPostResultsList.tsx b/src/components/search/LocalPostResultsList.tsx
index 5a9f903..4102401 100644
--- a/src/components/search/LocalPostResultsList.tsx
+++ b/src/components/search/LocalPostResultsList.tsx
@@ -5,7 +5,7 @@ import { SearchResultCard } from "./SearchResultCard";
function LocalPostResultsSkeleton() {
return (
-
+
diff --git a/src/components/search/SearchPreflightPanel.tsx b/src/components/search/SearchPreflightPanel.tsx
index c0b430e..adb2180 100644
--- a/src/components/search/SearchPreflightPanel.tsx
+++ b/src/components/search/SearchPreflightPanel.tsx
@@ -1,5 +1,5 @@
/* eslint react/jsx-max-depth: ["error", { "max": 5 }] */
-import { Icon } from "$/components/shared/Icon";
+import { Icon, LoadingIcon } from "$/components/shared/Icon";
import { useAppPreferences } from "$/contexts/app-preferences";
import { normalizeSearchReturnRoute } from "$/lib/search-routes";
import { formatBytes, formatEtaSeconds, formatProgress } from "$/lib/utils/text";
@@ -207,10 +207,10 @@ function SearchPreflightFooter(props: { handleDismiss: () => void; enable: () =>
onClick={() => void props.enable()}
disabled={props.activating}
class="inline-flex items-center gap-2 rounded-full border-0 bg-primary px-4 py-2 text-sm font-medium text-on-primary-fixed transition hover:bg-primary-dim disabled:cursor-not-allowed disabled:opacity-50">
-
+ } />
Enable semantic search}>
Downloading model...
diff --git a/src/components/search/SearchQueryInput.tsx b/src/components/search/SearchQueryInput.tsx
index 8c898a3..aafae75 100644
--- a/src/components/search/SearchQueryInput.tsx
+++ b/src/components/search/SearchQueryInput.tsx
@@ -1,6 +1,6 @@
import type { JSX, ParentProps } from "solid-js";
import { Show } from "solid-js";
-import { Icon } from "../shared/Icon";
+import { Icon, LoadingIcon } from "../shared/Icon";
type SearchQueryInputA11y = {
ariaActivedescendant?: string;
@@ -79,7 +79,7 @@ function SearchInputField(
onKeyDown={(event) => props.actions.onKeyDown?.(event)} />
-
+ ;
@@ -88,14 +88,6 @@ function SearchInputField(
);
}
-function LoadingIndicator(props: { loading: boolean }) {
- return (
-
-
-
- );
-}
-
function ClearButton(props: { query: string; loading: boolean; onClear: () => void }) {
return (
diff --git a/src/components/search/SyncStatusPanel.tsx b/src/components/search/SyncStatusPanel.tsx
index ab1d374..707e426 100644
--- a/src/components/search/SyncStatusPanel.tsx
+++ b/src/components/search/SyncStatusPanel.tsx
@@ -1,4 +1,4 @@
-import { Icon } from "$/components/shared/Icon";
+import { Icon, LoadingIcon } from "$/components/shared/Icon";
import { SearchController } from "$/lib/api/search";
import type { SyncStatus } from "$/lib/api/types/search";
import { formatRelativeTime } from "$/lib/utils/text";
@@ -40,9 +40,7 @@ function ReindexButton(props: { isSyncing: boolean; isReindexing: boolean; onRei
onClick={() => void props.onReindex()}
disabled={props.isSyncing || props.isReindexing}
class="inline-flex items-center gap-2 rounded-xl border-0 bg-white/6 px-3 py-2 text-xs font-medium text-on-surface-variant transition hover:bg-white/10 hover:text-on-surface disabled:cursor-not-allowed disabled:opacity-50">
- }>
-
-
+ } />
Reindexing...
);
@@ -55,9 +53,7 @@ function SyncButton(props: { isSyncing: boolean; isReindexing: boolean; onSync:
onClick={() => void props.onSync()}
disabled={props.isSyncing || props.isReindexing}
class="inline-flex items-center gap-2 rounded-xl border-0 bg-white/6 px-3 py-2 text-xs font-medium text-on-surface-variant transition hover:bg-white/10 hover:text-on-surface disabled:cursor-not-allowed disabled:opacity-50">
- }>
-
-
+ } />
Syncing...
);
diff --git a/src/components/settings/SettingsInlineFeedback.tsx b/src/components/settings/SettingsInlineFeedback.tsx
index 18a030a..7dd6e58 100644
--- a/src/components/settings/SettingsInlineFeedback.tsx
+++ b/src/components/settings/SettingsInlineFeedback.tsx
@@ -45,7 +45,7 @@ export function SettingsInlineFeedback(props: { feedback: SettingsFeedback | nul
aria-live={kind === "error" ? "assertive" : "polite"}
class="inline-flex w-fit items-center gap-2 rounded-full bg-surface-container-high px-3 py-1.5 text-sm"
classList={{ "text-emerald-300": kind === "success", "text-red-300": kind === "error" }}>
-
+
{message}
);
diff --git a/src/components/settings/SettingsModeration.tsx b/src/components/settings/SettingsModeration.tsx
index 7003a94..945f9da 100644
--- a/src/components/settings/SettingsModeration.tsx
+++ b/src/components/settings/SettingsModeration.tsx
@@ -308,7 +308,7 @@ export function SettingsModeration() {
type="button"
class="inline-flex w-fit items-center gap-2 rounded-full border-0 bg-primary/20 px-3 py-1.5 text-xs font-medium text-primary transition hover:bg-primary/30"
onClick={() => void openUrl("https://bsky.app/settings/content-moderation")}>
-
+
Open web settings
diff --git a/src/components/settings/SettingsPanel.tsx b/src/components/settings/SettingsPanel.tsx
index c917a1a..a8f4cf7 100644
--- a/src/components/settings/SettingsPanel.tsx
+++ b/src/components/settings/SettingsPanel.tsx
@@ -267,7 +267,7 @@ export function SettingsPanel() {
onClick={() => navigate(-1)}
class="ui-control ui-control-hoverable inline-flex h-10 w-10 items-center justify-center rounded-full"
title="Close settings">
-
+
diff --git a/src/components/shared/ContextMenu.tsx b/src/components/shared/ContextMenu.tsx
index 50bf9ca..216491a 100644
--- a/src/components/shared/ContextMenu.tsx
+++ b/src/components/shared/ContextMenu.tsx
@@ -191,9 +191,7 @@ export function ContextMenu(props: ContextMenuProps) {
item.onSelect();
props.onClose();
}}>
-
- {(icon) => }
-
+
{(icon) => }
{item.label}
)}
diff --git a/src/components/shared/ErrorToast.tsx b/src/components/shared/ErrorToast.tsx
index 5f94a52..bfeb6e4 100644
--- a/src/components/shared/ErrorToast.tsx
+++ b/src/components/shared/ErrorToast.tsx
@@ -17,13 +17,13 @@ export function ErrorToast(props: ErrorToastProps) {
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: 16, scale: 0.94 }}
transition={{ duration: 0.2 }}>
-
+
{message()}
diff --git a/src/components/shared/Icon.tsx b/src/components/shared/Icon.tsx
index 9b33bab..2eb30fc 100644
--- a/src/components/shared/Icon.tsx
+++ b/src/components/shared/Icon.tsx
@@ -1,6 +1,6 @@
import type { ExplorerTargetKind } from "$/lib/api/types/explorer";
import type { SearchMode } from "$/lib/api/types/search";
-import { type JSX, Match, splitProps, Switch } from "solid-js";
+import { type JSX, Match, Show, splitProps, Switch } from "solid-js";
type ActionIconKind = "add" | "edit" | "delete" | "save" | "cancel";
@@ -60,7 +60,12 @@ export type IconKind =
| "rss"
| "messages"
| "unpin"
- | "bookmark";
+ | "bookmark"
+ | "diagnostics"
+ | "stethoscope"
+ | "check"
+ | "radar"
+ | "unfollow";
type IconProps = JSX.HTMLAttributes
& {
class?: string;
@@ -183,6 +188,18 @@ export function Icon(props: IconProps) {
+
+
+
+
+
+
+
+
+
+
+
+
);
@@ -212,7 +229,7 @@ export function SettingsIcon(props: IconProps & { kind: SettingsIconKind }) {
-
+
@@ -334,3 +351,16 @@ export function ActionIcon(props: Omit & { kind: ActionIconKi
);
}
+
+export function LoadingIcon(
+ props: JSX.HTMLAttributes & { isLoading: boolean; class?: string; fallback?: JSX.Element },
+) {
+ const [local, rest] = splitProps(props, ["class", "isLoading"]);
+ return (
+
+
+
+
+
+ );
+}