diff --git a/CHANGELOG.md b/CHANGELOG.md
index e463677..5426872 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ What changed in each release of SCN Chat, for the people who use it, run it, or
### Changed
- The server now works with PDSs on the 2026-10-22 spaces alpha, and no longer with older spaces PDSs. On an updated PDS, the chat list failed to load with `Missing required key "hash"`. Opening a shared chat also needs the owner's new `#atproto_kem` key in their DID document. An updated PDS publishes one for the did:plc accounts it manages, and a did:web account has to add its own.
+- The login page and shared chats download about 15 KB less, compressed, before they show, since the router's loading page no longer brings the settings form kit with it. For forks: `SettingsPageSkeleton` and `SettingRowSkeleton` moved to `shared/ui/SettingsPageSkeleton.tsx`, and `dividedRows` and `undivided` to `shared/ui/divided-rows.ts`.
### Fixed
diff --git a/apps/web/src/features/admin/components/ProviderModels.tsx b/apps/web/src/features/admin/components/ProviderModels.tsx
index 8ee2232..c2e6c61 100644
--- a/apps/web/src/features/admin/components/ProviderModels.tsx
+++ b/apps/web/src/features/admin/components/ProviderModels.tsx
@@ -8,13 +8,13 @@ import { ErrorAlert } from '../../../shared/ui/Alert.tsx'
import { Badge } from '../../../shared/ui/Badge.tsx'
import { Button } from '../../../shared/ui/Button.tsx'
import { Checklist, ChecklistItem } from '../../../shared/ui/Checklist.tsx'
+import { undivided } from '../../../shared/ui/divided-rows.ts'
import * as ItemList from '../../../shared/ui/ItemList.tsx'
import {
inlineForm,
SettingRow,
SettingsEmpty,
SettingsGroup,
- undivided,
} from '../../../shared/ui/SettingsPage.tsx'
import { ToggleChip } from '../../../shared/ui/ToggleChip.tsx'
import { type Capabilities, capabilities } from '../../models/capabilities.ts'
diff --git a/apps/web/src/features/admin/pages/UsersAdmin.tsx b/apps/web/src/features/admin/pages/UsersAdmin.tsx
index 8cd8b79..58017eb 100644
--- a/apps/web/src/features/admin/pages/UsersAdmin.tsx
+++ b/apps/web/src/features/admin/pages/UsersAdmin.tsx
@@ -2,13 +2,9 @@ import { useSuspenseInfiniteQuery, useSuspenseQuery } from '@tanstack/react-quer
import { Suspense } from 'react'
import { ErrorAlert } from '../../../shared/ui/Alert.tsx'
import { Button } from '../../../shared/ui/Button.tsx'
+import { undivided } from '../../../shared/ui/divided-rows.ts'
import * as ItemList from '../../../shared/ui/ItemList.tsx'
-import {
- SettingsEmpty,
- SettingsGroup,
- SettingsPage,
- undivided,
-} from '../../../shared/ui/SettingsPage.tsx'
+import { SettingsEmpty, SettingsGroup, SettingsPage } from '../../../shared/ui/SettingsPage.tsx'
import { Invites } from '../components/Invites.tsx'
import { UserRow } from '../components/UserRow.tsx'
import { UserSearch } from '../components/UserSearch.tsx'
diff --git a/apps/web/src/features/settings/pages/ApiKeyModelSettings.tsx b/apps/web/src/features/settings/pages/ApiKeyModelSettings.tsx
index 213079a..084accb 100644
--- a/apps/web/src/features/settings/pages/ApiKeyModelSettings.tsx
+++ b/apps/web/src/features/settings/pages/ApiKeyModelSettings.tsx
@@ -9,6 +9,7 @@ import { ErrorAlert } from '../../../shared/ui/Alert.tsx'
import { Button, IconButton } from '../../../shared/ui/Button.tsx'
import { Checklist, ChecklistItem } from '../../../shared/ui/Checklist.tsx'
import { Input } from '../../../shared/ui/controls.tsx'
+import { undivided } from '../../../shared/ui/divided-rows.ts'
import * as ItemList from '../../../shared/ui/ItemList.tsx'
import {
backLink,
@@ -21,7 +22,6 @@ import {
SettingsEmpty,
SettingsGroup,
SettingsPage,
- undivided,
} from '../../../shared/ui/SettingsPage.tsx'
import { ToggleChip } from '../../../shared/ui/ToggleChip.tsx'
import { type Capabilities, capabilities, noCapabilities } from '../../models/capabilities.ts'
diff --git a/apps/web/src/features/settings/pages/SyncSettings.tsx b/apps/web/src/features/settings/pages/SyncSettings.tsx
index 3f2c3b3..d330763 100644
--- a/apps/web/src/features/settings/pages/SyncSettings.tsx
+++ b/apps/web/src/features/settings/pages/SyncSettings.tsx
@@ -8,10 +8,10 @@ import {
Callout,
ConfirmButton,
SettingRow,
- SettingRowSkeleton,
SettingsGroup,
SettingsPage,
} from '../../../shared/ui/SettingsPage.tsx'
+import { SettingRowSkeleton } from '../../../shared/ui/SettingsPageSkeleton.tsx'
import { useOpenStore } from '../../../store/react.tsx'
import { useMe } from '../../auth/session.ts'
import { accountQuery } from '../queries.ts'
diff --git a/apps/web/src/shared/route-states.tsx b/apps/web/src/shared/route-states.tsx
index 2e8440f..3ee0dcd 100644
--- a/apps/web/src/shared/route-states.tsx
+++ b/apps/web/src/shared/route-states.tsx
@@ -3,7 +3,7 @@ import { type ErrorComponentProps, useRouter } from '@tanstack/react-router'
import { useEffect } from 'react'
import { ErrorAlert } from './ui/Alert.tsx'
import { Button } from './ui/Button.tsx'
-import { SettingsPageSkeleton } from './ui/SettingsPage.tsx'
+import { SettingsPageSkeleton } from './ui/SettingsPageSkeleton.tsx'
/**
* What a route shows when its loader or a query it suspends on fails, in place of the route, so
diff --git a/apps/web/src/shared/schema-fields/SchemaFields.tsx b/apps/web/src/shared/schema-fields/SchemaFields.tsx
index 95d1647..027c012 100644
--- a/apps/web/src/shared/schema-fields/SchemaFields.tsx
+++ b/apps/web/src/shared/schema-fields/SchemaFields.tsx
@@ -4,8 +4,9 @@ import { splitLines } from '../lines.ts'
import type { Issue } from '../response.ts'
import { Alert } from '../ui/Alert.tsx'
import { Input, Switch, TextArea } from '../ui/controls.tsx'
+import { dividedRows } from '../ui/divided-rows.ts'
import { Select } from '../ui/Select.tsx'
-import { dividedRows, SettingRow } from '../ui/SettingsPage.tsx'
+import { SettingRow } from '../ui/SettingsPage.tsx'
import { applyRule, type FieldRule } from './field-rules.ts'
export type Property = {
diff --git a/apps/web/src/shared/ui/SettingsPage.tsx b/apps/web/src/shared/ui/SettingsPage.tsx
index a4d5e5f..28d08d4 100644
--- a/apps/web/src/shared/ui/SettingsPage.tsx
+++ b/apps/web/src/shared/ui/SettingsPage.tsx
@@ -7,8 +7,8 @@ import { CheckIcon } from '../icons.tsx'
import { ErrorAlert } from './Alert.tsx'
import { Button, IconButton } from './Button.tsx'
import { Radio } from './controls.tsx'
+import { dividedRows } from './divided-rows.ts'
import { FieldDescriptionContext } from './field-description.ts'
-import { Loading, Skeleton, SkeletonText } from './Skeleton.tsx'
/*
* The pieces settings and admin pages are built from: a page of cards, each holding rows of
@@ -96,16 +96,9 @@ interface CardProps {
children: ReactNode
}
-/** What a card holds after something it continues, such as a search's results, with no line between. */
-export const undivided = 'before:hidden'
-
/** A form of one field and its button across a card, such as a search or adding a person. */
export const inlineForm = 'flex gap-2 p-card-pad [&>input]:min-w-0 [&>input]:flex-1'
-/** Rows divided by lines inset to their text, for a card's rows or a set of rows within one. */
-export const dividedRows =
- '[&>*+*]:relative [&>*+*]:before:absolute [&>*+*]:before:inset-x-card-pad [&>*+*]:before:top-0 [&>*+*]:before:border-line [&>*+*]:before:border-t'
-
/** group/card lets what a card holds line up with the rest of it, as number fields do by their units. */
function SettingsCard(props: CardProps) {
return (
@@ -535,59 +528,3 @@ export function Callout(props: CalloutProps) {
)
}
-
-/** The widths of a page skeleton's rows, a setting's name over what it does, so they differ. */
-const skeletonRows = [
- { name: 'w-1/3', about: 'w-3/5' },
- { name: 'w-1/4', about: 'w-1/2' },
- { name: 'w-2/5', about: 'w-2/3' },
-]
-
-/**
- * A settings page while it loads, in the page's own shape: its title and what it is for, over a
- * card of rows, each a setting's name and description beside its control. It is a route's pending
- * page, which the router already holds back until loading takes a while, so it shows at once.
- */
-export function SettingsPageSkeleton() {
- return (
-