refactor(ui): migrate remaining inline pages to the concept design language (#1470)
* refactor(ui): migrate remaining inline pages to the concept design language Catch-up pass for surfaces the 2026-07 UI migration missed: - Bankavstämning: de-boxed toolbar, dry-table sections (preview, omatchade verifikationer, ignorerade, matchade), instructional copy moved behind the page "?" (HelpPopover via FocusedReport, sv+en), AttnLine for the dirty- dates hint, EmptyState for the blank page, space-y-8 rhythm. - Report detail views (trial balance, income statement, balance sheet, resultat-/balansrapport, reskontror, huvudbok, grundbok, dimension-P&L): shared Skeleton/Error/EmptyState shells, border-2 totals bands flattened to hairline cards with font-display tabular-nums headline numbers, ReportSectionTable rebuilt on the group-band idiom, font-mono money -> tabular-nums, house tablist for Förenklad/Detaljerad, GL filter de-boxed onto Input primitives, verdicts follow chips-mark-exceptions. - Extensions browse: PageHeader, locked section headers, rounded-lg secondary icon tiles, flat hover shift on cards, p-6 content. - Återkommande fakturor: page-level list moved off ui/table onto dry-table with hover-revealed quiet row actions; Skeleton loading. - Help: EmptyState for no search hits, flat hover shift on resource links. - Chart of accounts: spinner loading blocks -> Skeleton rows. - Kunskap graph + salary calendar popovers: rounded-lg, Input/Textarea primitives instead of hand-rolled shadow-sm controls. No logic, endpoint, or data changes. Verified via sandbox screenshots; lint 0 errors, 13214 tests green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ui): review triage: skip empty industry sectors, keyboard path to schedule edit Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
Jakob Wennberg
parent
645ed0a53e
commit
02a5d10538
@@ -72,8 +72,8 @@ export default async function ExtensionDetailPage({
|
||||
{/* Header */}
|
||||
<div className="flex items-start justify-between gap-4 mb-8">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="flex h-14 w-14 items-center justify-center rounded-xl bg-primary/10 flex-shrink-0">
|
||||
<Icon className="h-7 w-7 text-primary" />
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-secondary flex-shrink-0">
|
||||
<Icon className="h-6 w-6 text-foreground" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="font-display text-2xl leading-8 tracking-tight">{extensionName}</h1>
|
||||
@@ -95,14 +95,14 @@ export default async function ExtensionDetailPage({
|
||||
{/* Details */}
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h2 className="text-sm font-semibold mb-2">{t('description_heading')}</h2>
|
||||
<h2 className="text-sm font-medium uppercase tracking-wider text-muted-foreground mb-2">{t('description_heading')}</h2>
|
||||
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||
{extensionLongDescription}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h2 className="text-sm font-semibold mb-2">{t('data_source_heading')}</h2>
|
||||
<h2 className="text-sm font-medium uppercase tracking-wider text-muted-foreground mb-2">{t('data_source_heading')}</h2>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{dataPatternLabels[definition.dataPattern]}
|
||||
</p>
|
||||
|
||||
@@ -40,8 +40,8 @@ export default async function SectorExtensionsPage({
|
||||
|
||||
{/* Header */}
|
||||
<div className="flex items-start gap-4 mb-8">
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-xl bg-primary/10 flex-shrink-0">
|
||||
<Icon className="h-6 w-6 text-primary" />
|
||||
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-secondary flex-shrink-0">
|
||||
<Icon className="h-6 w-6 text-foreground" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="font-display text-2xl leading-8 tracking-tight">{sectorName}</h1>
|
||||
@@ -50,7 +50,7 @@ export default async function SectorExtensionsPage({
|
||||
</div>
|
||||
|
||||
{/* Extensions grid */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 stagger-enter">
|
||||
{sector.extensions.map(ext => (
|
||||
<ExtensionCard key={ext.slug} extension={ext} />
|
||||
))}
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { getTranslations } from 'next-intl/server'
|
||||
import { SECTORS } from '@/lib/extensions/sectors'
|
||||
import { sectorNameKey } from '@/lib/extensions/i18n'
|
||||
import { PageHeader } from '@/components/ui/page-header'
|
||||
import ExtensionCard from '@/components/extensions/ExtensionCard'
|
||||
import SectorCard from '@/components/extensions/SectorCard'
|
||||
|
||||
export default async function ExtensionsPage() {
|
||||
const t = await getTranslations('extensions')
|
||||
const generalSector = SECTORS.find(s => s.slug === 'general')
|
||||
const industrySectors = SECTORS.filter(s => s.slug !== 'general')
|
||||
// Only sectors that actually ship extensions: a shell with zero extensions
|
||||
// would render a dead card and an empty grid.
|
||||
const industrySectors = SECTORS.filter(s => s.slug !== 'general' && s.extensions.length > 0)
|
||||
|
||||
const generalSectorName = (() => {
|
||||
if (!generalSector) return ''
|
||||
@@ -16,21 +19,16 @@ export default async function ExtensionsPage() {
|
||||
})()
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-8">
|
||||
<h1 className="font-display text-2xl leading-8 tracking-tight">{t('page_title')}</h1>
|
||||
<p className="text-sm text-muted-foreground mt-1">
|
||||
{t('page_description')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-8">
|
||||
<PageHeader title={t('page_title')} />
|
||||
|
||||
{/* General extensions */}
|
||||
{generalSector && (
|
||||
<section className="mb-8">
|
||||
<h2 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider mb-4">
|
||||
<section>
|
||||
<h2 className="text-sm font-medium uppercase tracking-wider text-muted-foreground mb-4">
|
||||
{generalSectorName}
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 stagger-enter">
|
||||
{generalSector.extensions.map(ext => (
|
||||
<ExtensionCard key={ext.slug} extension={ext} />
|
||||
))}
|
||||
@@ -38,17 +36,19 @@ export default async function ExtensionsPage() {
|
||||
</section>
|
||||
)}
|
||||
|
||||
{/* Industry sectors */}
|
||||
<section>
|
||||
<h2 className="text-sm font-semibold text-muted-foreground uppercase tracking-wider mb-4">
|
||||
{t('industry_tools')}
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-3">
|
||||
{industrySectors.map(sector => (
|
||||
<SectorCard key={sector.slug} sector={sector} />
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
{/* Industry sectors (hidden while no industry sector ships extensions) */}
|
||||
{industrySectors.length > 0 && (
|
||||
<section>
|
||||
<h2 className="text-sm font-medium uppercase tracking-wider text-muted-foreground mb-4">
|
||||
{t('industry_tools')}
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 stagger-enter">
|
||||
{industrySectors.map(sector => (
|
||||
<SectorCard key={sector.slug} sector={sector} />
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user