Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/cockpit/src/components/Breadcrumb/Breadcrumb.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function Breadcrumb() {
const matches = useMatches().filter((m) => m.staticData?.crumb);

return (
<div className="w-full flex flex-row flex-nowrap gap-2 items-center">
<div className="w-full h-8 flex flex-row flex-nowrap gap-2 items-center">
{matches.map((item, index) => {
if (!item.staticData?.crumb) return null;
return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { type PropsWithChildren } from 'react';
import { Breadcrumb } from '@/components/Breadcrumb/Breadcrumb.tsx';

export function ContentLayout({ children }: PropsWithChildren) {
export function ContentArea({ children }: PropsWithChildren) {
return (
<main className="w-full min-h-0 flex flex-col lg:flex-row gap-4 overflow-hidden py-4">
<div className="h-full flex flex-1 flex-col gap-4 overflow-auto md:rounded-l-2xl md:bg-(--color-content-bg) @container p-4 transition-all">
<main className="w-full min-h-0 flex flex-col lg:flex-row overflow-hidden lg:py-4">
<div className="h-full flex flex-1 flex-col gap-4 overflow-hidden md:rounded-l-2xl md:bg-(--color-content-bg) @container py-4 pl-4 transition-all">
<div className="flex flex-row items-center">
<Breadcrumb />
</div>
Expand Down
5 changes: 5 additions & 0 deletions apps/cockpit/src/components/ContentLayout/GridLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { PropsWithChildren } from 'react';

export function GridLayout({ children }: PropsWithChildren) {
return <div className="pr-4 overflow-auto grid-layout">{children}</div>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ interface Props {

export function KPISection({ label, value, tone }: Props) {
return (
<Section>
<Section className="col-span-1">
<div className="w-full h-full flex flex-col gap-1 text-center">
<div className="text-xs text-(--color-txt-sec) uppercase">{label}</div>
<div
Expand Down
13 changes: 7 additions & 6 deletions apps/cockpit/src/components/Section/Section.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { PropsWithChildren } from 'react';
import { cx } from '@/utils/styles.ts';

export function Section({ children }: PropsWithChildren) {
return (
<div className="self-start w-full bg-(--color-bg) flex p-4 rounded-lg border border-(--color-section-border)">
{children}
</div>
);
interface Props {
className?: string;
}

export function Section({ children, className }: PropsWithChildren<Props>) {
return <div className={cx('section-base', className)}>{children}</div>;
}
7 changes: 6 additions & 1 deletion apps/cockpit/src/components/Transition/FadeTransition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,12 @@ export function FadeTransition({ children, transitionKey, durationMs = 300, clas

return (
<div
className={cx('transition-opacity', phase === 'entered' ? 'opacity-100' : 'opacity-0', className)}
className={cx(
'w-full h-full',
'transition-opacity',
phase === 'entered' ? 'opacity-100' : 'opacity-0',
className,
)}
style={{ transitionDuration: `${durationMs}ms` }}
>
{visibleChildren}
Expand Down
52 changes: 22 additions & 30 deletions apps/cockpit/src/domain/finance/transactions/Transactions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
} from 'src/domain/finance/transactions/model.ts';
import { useTransactions } from '@/domain/finance/transactions/data.ts';
import { useDateRange } from '@/utils/useDateRange.ts';
import { Grid } from '@/components/Grid/Grid.tsx';
import { SummaryStrip } from '@/domain/finance/transactions/SummaryStrip.tsx';
import { Section } from '@/components/Section/Section.tsx';
import { Input } from '@/components/Input/Input.tsx';
Expand Down Expand Up @@ -99,41 +98,34 @@ export function Transactions() {
};

return (
<div className="w-full min-w-0 transition-all flex flex-col gap-4">
{data && (
<>
{data?.summary && (
<Grid>
<SummaryStrip summary={data.summary} />
</Grid>
)}
{error && (
<div className="rounded-md border border-red-500/40 bg-red-500/10 px-3 py-2 text-sm text-red-400 dark:text-red-300">
{error.message}
</div>
)}
<TransactionForm
categories={data?.categories ?? []}
editing={Boolean(editingTransactionId)}
error={formError}
form={form}
isSubmitting={isSubmitting}
onCancel={resetForm}
onChange={setForm}
onSubmit={submitForm}
/>
{loading && <p className="text-sm text-(--color-txt-sec)">Loading transactions...</p>}
{/* Transaction list should have kind of toolbar
<>
{data?.summary && <SummaryStrip summary={data.summary} />}
{error && (
<div className="col-span-full rounded-md border border-red-500/40 bg-red-500/10 px-3 py-2 text-sm text-red-400 dark:text-red-300">
{error.message}
</div>
)}

<TransactionForm
categories={data?.categories ?? []}
editing={Boolean(editingTransactionId)}
error={formError}
form={form}
isSubmitting={isSubmitting}
onCancel={resetForm}
onChange={setForm}
onSubmit={submitForm}
/>
{loading && <p className="col-span-full text-sm text-(--color-txt-sec)">Loading transactions...</p>}
{/* Transaction list should have kind of toolbar
<input type="month" value={month} className="rounded-md border border-(--color-section-border) bg-(--color-bg) px-3 py-2 text-(--color-txt)" onChange={(event) => setDateRangeMonth(event.target.value)} />
<label className="flex flex-col gap-1 text-sm text-(--color-txt-sec)"></label>
<button type="button" aria-label="Refresh transactions" title="Refresh" className="mt-6 rounded-md border border-(--color-section-border) p-2 text-(--color-txt-sec) hover:bg-(--color-pri)/10 hover:text-(--color-pri)" onClick={reload} >
<RefreshIcon className="h-5 w-5" />
</button>
*/}
{data && <TransactionList transactions={data.transactions} onDelete={deleteTransaction} onEdit={startEdit} />}
</>
)}
</div>
{data && <TransactionList transactions={data.transactions} onDelete={deleteTransaction} onEdit={startEdit} />}
</>
);
}

Expand Down
37 changes: 25 additions & 12 deletions apps/cockpit/src/domain/weather/WeatherWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { FadeTransition } from '@/components/Transition/FadeTransition.tsx';
import { Section } from '@/components/Section/Section.tsx';
import { WeatherCurrentSummary } from '@/domain/weather/WeatherCurrentSummary.tsx';
import type { WeatherDataLoaded, WeatherLocation } from '@/domain/weather/model/model.ts';
import { Header } from '@/domain/weather/Header.tsx';
Expand All @@ -12,16 +10,11 @@ type WeatherWidgetProps = {
export function WeatherWidget({ location }: WeatherWidgetProps) {
const weather = useWeatherSnapshot(location);

return (
<FadeTransition transitionKey={weather.status}>
{weather.status === 'error' && <Section>{weather.errorMessage}</Section>}
{weather.status === 'loaded' && (
<Section>
<WeatherWidgetContent location={location} weather={weather} />
</Section>
)}
</FadeTransition>
);
if (weather.status === 'loading') return <Skeleton />;

if (weather.status === 'error') return weather.errorMessage;

return <WeatherWidgetContent location={location} weather={weather} />;
}

type WeatherWidgetContentProps = {
Expand All @@ -37,3 +30,23 @@ function WeatherWidgetContent({ location, weather }: WeatherWidgetContentProps)
</div>
);
}

function Skeleton() {
return (
<div className="w-full flex flex-col gap-2">
<div className="flex flex-row gap-2 items-center justify-between">
<div className="h-4 w-2/5 rounded bg-(--color-skeleton) animate-pulse" />
<div className="h-4 w-1/10 rounded bg-(--color-skeleton) animate-pulse" />
</div>
<div className="flex flex-row gap-2 items-center justify-between">
<div className="h-20 w-2/5 rounded bg-(--color-skeleton) animate-pulse" />
<div className="w-2/5 flex flex-col gap-2">
<div className="h-4 rounded bg-(--color-skeleton) animate-pulse" />
<div className="h-4 rounded bg-(--color-skeleton) animate-pulse" />
<div className="h-4 rounded bg-(--color-skeleton) animate-pulse" />
<div className="h-4 rounded bg-(--color-skeleton) animate-pulse" />
</div>
</div>
</div>
);
}
8 changes: 8 additions & 0 deletions apps/cockpit/src/domain/weather/model/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ export const LOCATION_OBERNHEIM: WeatherLocation = {
timezone: 'Europe/Berlin',
};

export const LOCATION_TUEBINGEN: WeatherLocation = {
id: 'tuebingen',
label: 'Tübingen',
latitude: 48.52,
longitude: 9.06,
timezone: 'Europe/Berlin',
};

export interface HourlyTemperaturePoint {
timeIso: string;
temperatureC: number;
Expand Down
4 changes: 2 additions & 2 deletions apps/cockpit/src/routes/__root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createRootRoute, HeadContent, Scripts } from '@tanstack/react-router';
import appCss from '../styles.css?url';
import { PageLayout } from '@/components/PageLayout/PageLayout.tsx';
import { Section } from '@/components/Section/Section.tsx';
import { ContentLayout } from '@/components/ContentLayout/ContentLayout.tsx';
import { ContentArea } from '@/components/ContentArea/ContentArea.tsx';
import { Navigation } from '@/components/Navigation/Navigation.tsx';
import { MdOutlineHome as HomeIcon } from 'react-icons/md';

Expand Down Expand Up @@ -33,7 +33,7 @@ function RootDocument({ children }: PropsWithChildren) {
<body>
<PageLayout>
<Navigation />
<ContentLayout>{children}</ContentLayout>
<ContentArea>{children}</ContentArea>
</PageLayout>
{Devtools ? <Devtools /> : null}
<Scripts />
Expand Down
7 changes: 6 additions & 1 deletion apps/cockpit/src/routes/finance/transactions.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createFileRoute } from '@tanstack/react-router';
import { Transactions } from '@/domain/finance/transactions/Transactions.tsx';
import { GridLayout } from '@/components/ContentLayout/GridLayout.tsx';

export const Route = createFileRoute('/finance/transactions')({
component: TransactionsRoute,
Expand All @@ -9,5 +10,9 @@ export const Route = createFileRoute('/finance/transactions')({
});

function TransactionsRoute() {
return <Transactions />;
return (
<GridLayout>
<Transactions />

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Make the transactions page span the grid

When /finance/transactions renders at md and above, GridLayout creates 4/6/12 columns but Transactions is the only direct grid item and has no col-span-* class. That leaves the whole form and table squeezed into a single narrow column instead of the full content area it occupied before this change; wrap it in a full-span item or avoid the card grid for this route.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will be reworked anyways. Ok for now.

</GridLayout>
);
}
26 changes: 16 additions & 10 deletions apps/cockpit/src/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import { createFileRoute } from '@tanstack/react-router';
import { WeatherWidget } from '@/domain/weather/WeatherWidget.tsx';
import { LOCATION_MOESSINGEN, LOCATION_OBERNHEIM } from '@/domain/weather/model/model.ts';
import { LOCATION_MOESSINGEN, LOCATION_OBERNHEIM, LOCATION_TUEBINGEN } from '@/domain/weather/model/model.ts';
import { GridLayout } from '@/components/ContentLayout/GridLayout.tsx';
import { Section } from '@/components/Section/Section.tsx';

export const Route = createFileRoute('/')({
component: App,
component: Overview,
});

function App() {
function Overview() {
return (
<>
<WeatherWidget location={LOCATION_MOESSINGEN} />
<WeatherWidget location={LOCATION_OBERNHEIM} />
{/*
<VoiceWidget />
*/}
</>
<GridLayout>
<Section className="col-span-2 md:col-span-2 lg:col-span-2 2xl:col-span-2">
<WeatherWidget location={LOCATION_MOESSINGEN} />
</Section>
<Section className="col-span-2 md:col-span-2 lg:col-span-2 2xl:col-span-2">
<WeatherWidget location={LOCATION_OBERNHEIM} />
</Section>
<Section className="col-span-2 md:col-span-2 lg:col-span-2 2xl:col-span-2">
<WeatherWidget location={LOCATION_TUEBINGEN} />
</Section>
</GridLayout>
);
}
10 changes: 10 additions & 0 deletions apps/cockpit/src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
--color-section-border: #d6dde6;
--color-sem-positive: oklch(59.6% 0.145 163.225);
--color-sem-negative: oklch(58.6% 0.253 17.585);
--color-skeleton: #e6e6e6;
}

@media (prefers-color-scheme: dark) {
Expand All @@ -25,6 +26,7 @@
--color-section-border: #272727;
--color-sem-positive: oklch(84.5% 0.143 164.978);
--color-sem-negative: oklch(71.2% 0.194 13.428);
--color-skeleton: #272727;
}
}

Expand Down Expand Up @@ -53,3 +55,11 @@ code {
.animate-rainbow {
animation: rainbow 30s linear infinite;
}

.grid-layout {
@apply grid gap-4 grid-cols-2 md:grid-cols-4 lg:grid-cols-6 2xl:grid-cols-12;
}

.section-base {
@apply transition-all self-start w-full h-full bg-(--color-bg) flex p-4 rounded-lg border border-(--color-section-border) @container;
}