refactor(miniapp): simplify dashboard layout and controls

This commit is contained in:
2026-03-11 20:57:44 +04:00
parent e36d3b5d66
commit 523b5144d8
7 changed files with 148 additions and 267 deletions

View File

@@ -1,4 +1,4 @@
import { Match, Switch, createMemo, createSignal, onMount } from 'solid-js' import { Match, Show, Switch, createMemo, createSignal, onMount } from 'solid-js'
import { dictionary, type Locale } from './i18n' import { dictionary, type Locale } from './i18n'
import { import {
@@ -38,10 +38,8 @@ import {
type MiniAppDashboard, type MiniAppDashboard,
type MiniAppPendingMember type MiniAppPendingMember
} from './miniapp-api' } from './miniapp-api'
import { Button, Field, Modal } from './components/ui' import { Button, Field, MiniChip, Modal } from './components/ui'
import { HeroBanner } from './components/layout/hero-banner'
import { NavigationTabs } from './components/layout/navigation-tabs' import { NavigationTabs } from './components/layout/navigation-tabs'
import { ProfileCard } from './components/layout/profile-card'
import { TopBar } from './components/layout/top-bar' import { TopBar } from './components/layout/top-bar'
import { BlockedState } from './components/session/blocked-state' import { BlockedState } from './components/session/blocked-state'
import { LoadingState } from './components/session/loading-state' import { LoadingState } from './components/session/loading-state'
@@ -2337,10 +2335,7 @@ function App() {
currentMemberLine={currentMemberLine()} currentMemberLine={currentMemberLine()}
utilityTotalMajor={utilityTotalMajor()} utilityTotalMajor={utilityTotalMajor()}
purchaseTotalMajor={purchaseTotalMajor()} purchaseTotalMajor={purchaseTotalMajor()}
memberBalanceVisuals={memberBalanceVisuals()}
purchaseChart={purchaseInvestmentChart()}
memberBaseDueMajor={memberBaseDueMajor} memberBaseDueMajor={memberBaseDueMajor}
memberRemainingClass={memberRemainingClass}
ledgerTitle={ledgerTitle} ledgerTitle={ledgerTitle}
ledgerPrimaryAmount={ledgerPrimaryAmount} ledgerPrimaryAmount={ledgerPrimaryAmount}
ledgerSecondaryAmount={ledgerSecondaryAmount} ledgerSecondaryAmount={ledgerSecondaryAmount}
@@ -2426,25 +2421,30 @@ function App() {
</Match> </Match>
<Match when={session().status === 'ready'}> <Match when={session().status === 'ready'}>
<HeroBanner <section class="app-context-row">
badges={[ <div class="app-context-meta">
readySession()?.mode === 'demo' ? copy().demoBadge : copy().liveBadge, <MiniChip>
readySession()?.member.isAdmin ? copy().adminTag : copy().residentTag, {readySession()?.mode === 'demo' ? copy().demoBadge : copy().liveBadge}
readySession()?.member.status </MiniChip>
<MiniChip muted>
{readySession()?.member.isAdmin ? copy().adminTag : copy().residentTag}
</MiniChip>
<MiniChip muted>
{readySession()?.member.status
? memberStatusLabel(readySession()!.member.status) ? memberStatusLabel(readySession()!.member.status)
: copy().memberStatusActive : copy().memberStatusActive}
]} </MiniChip>
title={`${copy().welcome}, ${readySession()?.telegramUser.firstName ?? readySession()?.member.displayName}`} </div>
body={copy().overviewBody} <Show when={readySession()?.mode === 'live'}>
action={ <Button
readySession()?.mode === 'live' variant="ghost"
? { class="app-context-row__action"
label: copy().manageProfileAction, onClick={() => setProfileEditorOpen(true)}
onClick: () => setProfileEditorOpen(true) >
} {copy().manageProfileAction}
: undefined </Button>
} </Show>
/> </section>
<NavigationTabs <NavigationTabs
items={ items={
@@ -2459,21 +2459,7 @@ function App() {
onChange={setActiveNav} onChange={setActiveNav}
/> />
<section class="content-grid"> <section class="content-stack">{renderPanel()}</section>
<ProfileCard
displayName={readySession()?.member.displayName ?? ''}
roleLabel={readySession()?.member.isAdmin ? copy().adminTag : copy().residentTag}
statusSummary={copy().memberStatusSummary.replace(
'{status}',
readySession()?.member.status
? memberStatusLabel(readySession()!.member.status)
: copy().memberStatusActive
)}
modeBadge={readySession()?.mode === 'demo' ? copy().demoBadge : copy().liveBadge}
localeBadge={locale().toUpperCase()}
/>
<div class="content-stack">{renderPanel()}</div>
</section>
<Modal <Modal
open={profileEditorOpen()} open={profileEditorOpen()}
title={copy().displayNameLabel} title={copy().displayNameLabel}

View File

@@ -13,7 +13,7 @@ type Props = {
export function TopBar(props: Props) { export function TopBar(props: Props) {
return ( return (
<section class="topbar"> <section class="topbar">
<div> <div class="topbar__copy">
<p class="eyebrow">{props.subtitle}</p> <p class="eyebrow">{props.subtitle}</p>
<h1>{props.title}</h1> <h1>{props.title}</h1>
</div> </div>

View File

@@ -1,6 +1,8 @@
import * as Dialog from '@kobalte/core/dialog' import * as Dialog from '@kobalte/core/dialog'
import { Show, type JSX, type ParentProps } from 'solid-js' import { Show, type JSX, type ParentProps } from 'solid-js'
import { XIcon } from './icons'
export function Modal( export function Modal(
props: ParentProps<{ props: ParentProps<{
open: boolean open: boolean
@@ -24,8 +26,8 @@ export function Modal(
{(description) => <Dialog.Description>{description()}</Dialog.Description>} {(description) => <Dialog.Description>{description()}</Dialog.Description>}
</Show> </Show>
</div> </div>
<Dialog.CloseButton class="ui-button ui-button--icon"> <Dialog.CloseButton class="ui-button ui-button--icon modal-close-button">
<span aria-hidden="true">x</span> <XIcon />
<span class="sr-only">{props.closeLabel}</span> <span class="sr-only">{props.closeLabel}</span>
</Dialog.CloseButton> </Dialog.CloseButton>
</header> </header>

View File

@@ -65,3 +65,12 @@ export function GlobeIcon(props: IconProps) {
</svg> </svg>
) )
} }
export function XIcon(props: IconProps) {
return (
<svg {...iconProps(props)}>
<path d="m6 6 12 12" />
<path d="M18 6 6 18" />
</svg>
)
}

View File

@@ -82,7 +82,12 @@ button {
display: flex; display: flex;
align-items: flex-start; align-items: flex-start;
justify-content: space-between; justify-content: space-between;
gap: 16px; gap: 12px;
margin-bottom: 10px;
}
.topbar__copy {
min-width: 0;
} }
.topbar h1, .topbar h1,
@@ -94,7 +99,8 @@ button {
} }
.topbar h1 { .topbar h1 {
font-size: clamp(2rem, 5vw, 3rem); font-size: clamp(1.55rem, 4.4vw, 2.35rem);
line-height: 0.96;
} }
.eyebrow { .eyebrow {
@@ -117,14 +123,15 @@ button {
.locale-switch--compact { .locale-switch--compact {
justify-items: end; justify-items: end;
min-width: 0; min-width: 0;
align-self: flex-start;
} }
.locale-switch__buttons { .locale-switch__buttons {
display: inline-grid; display: inline-grid;
grid-auto-flow: column; grid-auto-flow: column;
align-items: center; align-items: center;
gap: 6px; gap: 4px;
padding: 4px; padding: 3px;
border: 1px solid rgb(255 255 255 / 0.1); border: 1px solid rgb(255 255 255 / 0.1);
border-radius: 999px; border-radius: 999px;
background: rgb(255 255 255 / 0.04); background: rgb(255 255 255 / 0.04);
@@ -135,8 +142,8 @@ button {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 30px; width: 24px;
height: 30px; height: 24px;
color: rgb(247 179 137 / 0.88); color: rgb(247 179 137 / 0.88);
} }
@@ -154,13 +161,17 @@ button {
.locale-switch__buttons button { .locale-switch__buttons button {
border-radius: 999px; border-radius: 999px;
min-width: 42px; min-width: 36px;
padding: 7px 10px; padding: 6px 8px;
font-size: 0.78rem; font-size: 0.72rem;
font-weight: 700; font-weight: 700;
letter-spacing: 0.04em; letter-spacing: 0.04em;
} }
.locale-switch__buttons--inline {
margin-top: 6px;
}
.locale-switch__buttons button.is-active, .locale-switch__buttons button.is-active,
.nav-grid button.is-active { .nav-grid button.is-active {
border-color: rgb(247 179 137 / 0.7); border-color: rgb(247 179 137 / 0.7);
@@ -263,15 +274,22 @@ button {
} }
.ui-button--primary { .ui-button--primary {
border-color: rgb(247 179 137 / 0.42); border-color: rgb(247 179 137 / 0.52);
background: rgb(247 179 137 / 0.16); background: rgb(247 179 137 / 0.18);
color: #fff4ea; color: #fff4ea;
} }
.ui-button--secondary, .ui-button--secondary {
background: rgb(255 255 255 / 0.04);
}
.ui-button--ghost, .ui-button--ghost,
.ui-button--icon { .ui-button--icon {
background: rgb(255 255 255 / 0.04); background: transparent;
}
.ui-button--ghost {
border-color: rgb(255 255 255 / 0.08);
} }
.ui-button--danger { .ui-button--danger {
@@ -296,13 +314,19 @@ button {
.nav-grid { .nav-grid {
display: grid; display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr)); grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 10px; gap: 6px;
margin-top: 18px; margin-top: 12px;
padding: 4px;
border: 1px solid rgb(255 255 255 / 0.08);
border-radius: 18px;
background: rgb(255 255 255 / 0.03);
} }
.nav-grid button { .nav-grid button {
border-radius: 18px; border: none;
padding: 14px 8px; border-radius: 14px;
min-height: 38px;
padding: 9px 10px;
} }
.content-grid { .content-grid {
@@ -314,12 +338,13 @@ button {
.content-stack { .content-stack {
display: grid; display: grid;
gap: 12px; gap: 12px;
margin-top: 12px;
} }
.summary-card-grid { .summary-card-grid {
display: grid; display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 12px; gap: 10px;
} }
.panel { .panel {
@@ -342,9 +367,11 @@ button {
.stat-card, .stat-card,
.activity-row, .activity-row,
.utility-bill-row { .utility-bill-row {
display: grid;
gap: 10px;
border: 1px solid rgb(255 255 255 / 0.08); border: 1px solid rgb(255 255 255 / 0.08);
border-radius: 18px; border-radius: 18px;
padding: 14px; padding: 16px;
background: rgb(255 255 255 / 0.03); background: rgb(255 255 255 / 0.03);
} }
@@ -367,7 +394,7 @@ button {
grid-template-columns: minmax(0, 1fr) auto; grid-template-columns: minmax(0, 1fr) auto;
align-items: start; align-items: start;
gap: 12px; gap: 12px;
margin-bottom: 10px; margin-bottom: 0;
} }
.balance-item strong, .balance-item strong,
@@ -382,7 +409,7 @@ button {
.ledger-item p, .ledger-item p,
.activity-row p, .activity-row p,
.utility-bill-row p { .utility-bill-row p {
margin-top: 6px; margin: 0;
} }
.balance-status.is-credit { .balance-status.is-credit {
@@ -409,7 +436,6 @@ button {
.balance-breakdown { .balance-breakdown {
display: grid; display: grid;
gap: 10px; gap: 10px;
margin-top: 12px;
} }
.member-visual-list { .member-visual-list {
@@ -596,32 +622,8 @@ button {
margin-top: 12px; margin-top: 12px;
} }
.section-switch {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 8px;
}
.section-switch button {
border: 1px solid rgb(255 255 255 / 0.12);
border-radius: 16px;
min-height: 44px;
padding: 10px 12px;
background: rgb(255 255 255 / 0.04);
color: inherit;
}
.section-switch button.is-active {
border-color: rgb(247 179 137 / 0.7);
background: rgb(247 179 137 / 0.14);
}
.admin-layout { .admin-layout {
gap: 18px; gap: 12px;
}
.admin-hero {
gap: 16px;
} }
.admin-summary-grid, .admin-summary-grid,
@@ -636,24 +638,6 @@ button {
gap: 12px; gap: 12px;
} }
.admin-section__header {
display: flex;
align-items: end;
justify-content: space-between;
gap: 12px;
}
.admin-section__header h3 {
margin: 0;
font-family: 'Space Grotesk', 'IBM Plex Sans', sans-serif;
letter-spacing: -0.04em;
font-size: 1.15rem;
}
.admin-section__header p {
margin-top: 6px;
}
.admin-sublist { .admin-sublist {
margin-top: 12px; margin-top: 12px;
} }
@@ -728,10 +712,9 @@ button {
.panel-toolbar { .panel-toolbar {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: flex-end; justify-content: flex-start;
gap: 10px; gap: 10px;
margin-top: 14px; margin-top: 8px;
margin-bottom: 14px;
} }
.ledger-compact-card { .ledger-compact-card {
@@ -806,7 +789,7 @@ button {
overflow: auto; overflow: auto;
border: 1px solid rgb(255 255 255 / 0.1); border: 1px solid rgb(255 255 255 / 0.1);
border-radius: 24px; border-radius: 24px;
padding: 18px; padding: 16px;
background: background:
linear-gradient(180deg, rgb(255 255 255 / 0.07), rgb(255 255 255 / 0.03)), rgb(18 26 36 / 0.96); linear-gradient(180deg, rgb(255 255 255 / 0.07), rgb(255 255 255 / 0.03)), rgb(18 26 36 / 0.96);
box-shadow: 0 28px 80px rgb(0 0 0 / 0.35); box-shadow: 0 28px 80px rgb(0 0 0 / 0.35);
@@ -815,7 +798,7 @@ button {
.modal-sheet__header { .modal-sheet__header {
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr) auto; grid-template-columns: minmax(0, 1fr) auto;
gap: 12px; gap: 10px;
align-items: start; align-items: start;
} }
@@ -827,17 +810,25 @@ button {
} }
.modal-sheet__header p { .modal-sheet__header p {
margin-top: 8px; margin-top: 6px;
} }
.modal-sheet__body { .modal-sheet__body {
display: grid; display: grid;
gap: 16px; gap: 14px;
margin-top: 18px; margin-top: 14px;
} }
.modal-sheet__footer { .modal-sheet__footer {
margin-top: 18px; margin-top: 14px;
}
.modal-close-button {
align-self: start;
width: 36px;
min-width: 36px;
min-height: 36px;
border-color: rgb(255 255 255 / 0.08);
} }
.editor-grid { .editor-grid {
@@ -952,6 +943,29 @@ button {
overflow-wrap: anywhere; overflow-wrap: anywhere;
} }
.balance-item > p + .ledger-list,
.balance-item > p + .balance-list {
margin-top: 4px;
}
.app-context-row {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 10px;
}
.app-context-meta {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.app-context-row__action {
margin-left: auto;
}
@media (min-width: 760px) { @media (min-width: 760px) {
.shell { .shell {
max-width: 920px; max-width: 920px;
@@ -976,10 +990,6 @@ button {
align-self: stretch; align-self: stretch;
} }
.admin-summary-grid {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.admin-grid { .admin-grid {
grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-columns: repeat(2, minmax(0, 1fr));
} }
@@ -999,10 +1009,6 @@ button {
.balance-item--wide { .balance-item--wide {
grid-column: 1 / -1; grid-column: 1 / -1;
} }
.section-switch {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
} }
@media (min-width: 980px) { @media (min-width: 980px) {
@@ -1025,21 +1031,17 @@ button {
} }
.topbar { .topbar {
flex-direction: column; flex-direction: row;
align-items: flex-start;
} }
.locale-switch { .locale-switch {
justify-items: stretch; width: auto;
width: 100%;
min-width: 0; min-width: 0;
} }
.locale-switch--compact { .locale-switch--compact {
justify-items: start; justify-items: end;
}
.locale-switch__buttons {
justify-self: start;
} }
.nav-grid { .nav-grid {
@@ -1054,10 +1056,6 @@ button {
grid-template-columns: minmax(0, 1fr); grid-template-columns: minmax(0, 1fr);
} }
.admin-section__header {
align-items: start;
}
.activity-row header, .activity-row header,
.ledger-compact-card header, .ledger-compact-card header,
.ledger-item header, .ledger-item header,

View File

@@ -1,7 +1,6 @@
import { For, Show } from 'solid-js' import { For, Show } from 'solid-js'
import { FinanceSummaryCards } from '../components/finance/finance-summary-cards' import { FinanceSummaryCards } from '../components/finance/finance-summary-cards'
import { FinanceVisuals } from '../components/finance/finance-visuals'
import type { MiniAppDashboard } from '../miniapp-api' import type { MiniAppDashboard } from '../miniapp-api'
type Props = { type Props = {
@@ -12,32 +11,7 @@ type Props = {
currentMemberLine: MiniAppDashboard['members'][number] | null currentMemberLine: MiniAppDashboard['members'][number] | null
utilityTotalMajor: string utilityTotalMajor: string
purchaseTotalMajor: string purchaseTotalMajor: string
memberBalanceVisuals: {
member: MiniAppDashboard['members'][number]
totalMinor: bigint
barWidthPercent: number
segments: {
key: string
label: string
amountMajor: string
amountMinor: bigint
widthPercent: number
}[]
}[]
purchaseChart: {
totalMajor: string
slices: {
key: string
label: string
amountMajor: string
color: string
percentage: number
dasharray: string
dashoffset: string
}[]
}
memberBaseDueMajor: (member: MiniAppDashboard['members'][number]) => string memberBaseDueMajor: (member: MiniAppDashboard['members'][number]) => string
memberRemainingClass: (member: MiniAppDashboard['members'][number]) => string
ledgerTitle: (entry: MiniAppDashboard['ledger'][number]) => string ledgerTitle: (entry: MiniAppDashboard['ledger'][number]) => string
ledgerPrimaryAmount: (entry: MiniAppDashboard['ledger'][number]) => string ledgerPrimaryAmount: (entry: MiniAppDashboard['ledger'][number]) => string
ledgerSecondaryAmount: (entry: MiniAppDashboard['ledger'][number]) => string | null ledgerSecondaryAmount: (entry: MiniAppDashboard['ledger'][number]) => string | null
@@ -91,17 +65,7 @@ export function HomeScreen(props: Props) {
</Show> </Show>
</div> </div>
<Show <Show when={props.currentMemberLine}>
when={props.currentMemberLine}
fallback={
<article class="balance-item">
<header>
<strong>{props.copy.overviewTitle ?? ''}</strong>
</header>
<p>{props.copy.overviewBody ?? ''}</p>
</article>
}
>
{(member) => ( {(member) => (
<article class="balance-item balance-item--accent"> <article class="balance-item balance-item--accent">
<header> <header>
@@ -110,7 +74,6 @@ export function HomeScreen(props: Props) {
{member().remainingMajor} {props.dashboard!.currency} {member().remainingMajor} {props.dashboard!.currency}
</span> </span>
</header> </header>
<p>{props.copy.yourBalanceBody ?? ''}</p>
<p> <p>
{props.copy.shareRent ?? ''}: {props.dashboard!.rentSourceAmountMajor}{' '} {props.copy.shareRent ?? ''}: {props.dashboard!.rentSourceAmountMajor}{' '}
{props.dashboard!.rentSourceCurrency} {props.dashboard!.rentSourceCurrency}
@@ -154,23 +117,6 @@ export function HomeScreen(props: Props) {
)} )}
</Show> </Show>
<FinanceVisuals
dashboard={props.dashboard}
memberVisuals={props.memberBalanceVisuals}
purchaseChart={props.purchaseChart}
remainingClass={props.memberRemainingClass}
labels={{
financeVisualsTitle: props.copy.financeVisualsTitle ?? '',
financeVisualsBody: props.copy.financeVisualsBody ?? '',
membersCount: props.copy.membersCount ?? '',
purchaseInvestmentsTitle: props.copy.purchaseInvestmentsTitle ?? '',
purchaseInvestmentsBody: props.copy.purchaseInvestmentsBody ?? '',
purchaseInvestmentsEmpty: props.copy.purchaseInvestmentsEmpty ?? '',
purchaseTotalLabel: props.copy.purchaseTotalLabel ?? '',
purchaseShareLabel: props.copy.purchaseShareLabel ?? ''
}}
/>
<article class="balance-item balance-item--wide"> <article class="balance-item balance-item--wide">
<header> <header>
<strong>{props.copy.latestActivityTitle ?? ''}</strong> <strong>{props.copy.latestActivityTitle ?? ''}</strong>

View File

@@ -10,6 +10,7 @@ import {
PlusIcon, PlusIcon,
SettingsIcon SettingsIcon
} from '../components/ui' } from '../components/ui'
import { NavigationTabs } from '../components/layout/navigation-tabs'
import type { import type {
MiniAppAdminCycleState, MiniAppAdminCycleState,
MiniAppAdminSettingsPayload, MiniAppAdminSettingsPayload,
@@ -175,63 +176,21 @@ export function HouseScreen(props: Props) {
return ( return (
<div class="admin-layout"> <div class="admin-layout">
<article class="balance-item balance-item--accent admin-hero"> <NavigationTabs
<header> items={
<strong>{props.copy.householdSettingsTitle ?? ''}</strong>
<span>{props.adminSettings?.settings.settlementCurrency ?? '—'}</span>
</header>
<p>{props.copy.householdSettingsBody ?? ''}</p>
<div class="admin-summary-grid">
<article class="stat-card">
<span>{props.copy.billingCycleTitle ?? ''}</span>
<strong>{props.cycleState?.cycle?.period ?? props.copy.billingCycleEmpty ?? ''}</strong>
</article>
<article class="stat-card">
<span>{props.copy.settlementCurrency ?? ''}</span>
<strong>{props.adminSettings?.settings.settlementCurrency ?? '—'}</strong>
</article>
<article class="stat-card">
<span>{props.copy.membersCount ?? ''}</span>
<strong>{String(props.adminSettings?.members.length ?? 0)}</strong>
</article>
<article class="stat-card">
<span>{props.copy.pendingRequests ?? ''}</span>
<strong>{String(props.pendingMembers.length)}</strong>
</article>
</div>
</article>
<div class="section-switch">
<For
each={
[ [
['billing', props.copy.houseSectionBilling], { key: 'billing', label: props.copy.houseSectionBilling ?? '' },
['utilities', props.copy.houseSectionUtilities], { key: 'utilities', label: props.copy.houseSectionUtilities ?? '' },
['members', props.copy.houseSectionMembers], { key: 'members', label: props.copy.houseSectionMembers ?? '' },
['topics', props.copy.houseSectionTopics] { key: 'topics', label: props.copy.houseSectionTopics ?? '' }
] as const ] as const
} }
> active={props.activeHouseSection}
{([key, label]) => ( onChange={props.onChangeHouseSection}
<button />
classList={{ 'is-active': props.activeHouseSection === key }}
type="button"
onClick={() => props.onChangeHouseSection(key)}
>
{label}
</button>
)}
</For>
</div>
<Show when={props.activeHouseSection === 'billing'}> <Show when={props.activeHouseSection === 'billing'}>
<section class="admin-section"> <section class="admin-section">
<header class="admin-section__header">
<div>
<h3>{props.copy.billingCycleTitle ?? ''}</h3>
<p>{props.copy.billingSettingsTitle ?? ''}</p>
</div>
</header>
<div class="admin-grid"> <div class="admin-grid">
<article class="balance-item"> <article class="balance-item">
<header> <header>
@@ -310,8 +269,7 @@ export function HouseScreen(props: Props) {
<strong>{props.copy.householdLanguage ?? ''}</strong> <strong>{props.copy.householdLanguage ?? ''}</strong>
<span>{props.householdDefaultLocale.toUpperCase()}</span> <span>{props.householdDefaultLocale.toUpperCase()}</span>
</header> </header>
<p>{props.copy.householdSettingsBody ?? ''}</p> <div class="locale-switch__buttons locale-switch__buttons--inline">
<div class="locale-switch__buttons">
<button <button
classList={{ 'is-active': props.householdDefaultLocale === 'en' }} classList={{ 'is-active': props.householdDefaultLocale === 'en' }}
type="button" type="button"
@@ -530,12 +488,6 @@ export function HouseScreen(props: Props) {
<Show when={props.activeHouseSection === 'utilities'}> <Show when={props.activeHouseSection === 'utilities'}>
<section class="admin-section"> <section class="admin-section">
<header class="admin-section__header">
<div>
<h3>{props.copy.utilityCategoriesTitle ?? ''}</h3>
<p>{props.copy.utilityCategoriesBody ?? ''}</p>
</div>
</header>
<div class="admin-grid"> <div class="admin-grid">
<article class="balance-item"> <article class="balance-item">
<header> <header>
@@ -861,12 +813,6 @@ export function HouseScreen(props: Props) {
<Show when={props.activeHouseSection === 'members'}> <Show when={props.activeHouseSection === 'members'}>
<section class="admin-section"> <section class="admin-section">
<header class="admin-section__header">
<div>
<h3>{props.copy.adminsTitle ?? ''}</h3>
<p>{props.copy.adminsBody ?? ''}</p>
</div>
</header>
<div class="admin-grid"> <div class="admin-grid">
<article class="balance-item admin-card--wide"> <article class="balance-item admin-card--wide">
<header> <header>
@@ -1118,12 +1064,6 @@ export function HouseScreen(props: Props) {
<Show when={props.activeHouseSection === 'topics'}> <Show when={props.activeHouseSection === 'topics'}>
<section class="admin-section"> <section class="admin-section">
<header class="admin-section__header">
<div>
<h3>{props.copy.topicBindingsTitle ?? ''}</h3>
<p>{props.copy.topicBindingsBody ?? ''}</p>
</div>
</header>
<div class="admin-grid"> <div class="admin-grid">
<article class="balance-item admin-card--wide"> <article class="balance-item admin-card--wide">
<header> <header>