5.0 KiB
File: COMMIT_02_THEME.md
Commit 2: Global UI & Theme Setup
Objective
Integrate the Mantine UI library and configure the global grayscale, minimalist theme. This addresses the "stunningly-beautiful" and "minimal, grayscale" requirements.
Implementation Specification
1. Create postcss.config.mjs
Create a file at /postcss.config.mjs to enable Mantine's PostCSS features:
JavaScript
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
'postcss-preset-mantine': {},
'postcss-simple-vars': {
variables: {
'mantine-breakpoint-xs': '36em',
'mantine-breakpoint-sm': '48em',
'mantine-breakpoint-md': '62em',
'mantine-breakpoint-lg': '75em',
'mantine-breakpoint-xl': '88em',
},
},
},
};
export default config;
2. Create app/theme.ts
Create a file at /app/theme.ts to define the app's aesthetic:
TypeScript
'use client';
import { createTheme, MantineColorsTuple } from '@mantine/core';
// Define a rich 10-shade grayscale palette
const ponderGray: MantineColorsTuple =;
export const theme = createTheme({
primaryColor: 'gray',
// Use our custom gray palette
colors: {
gray: ponderGray,
},
// Set default dark mode and grayscale for the "minimalist" look
defaultRadius: 'md',
fontFamily: 'Inter, sans-serif',
// Enforce dark mode
forceColorscheme: 'dark',
// Set default component props for a consistent look
components: {
Button: {
defaultProps: {
variant: 'filled',
color: 'gray',
radius: 'xl',
},
},
Paper: {
defaultProps: {
shadow: 'xs',
p: 'md',
radius: 'md',
withBorder: true,
},
styles: {
root: {
backgroundColor: '#212529', // gray
borderColor: '#495057', // gray
},
},
},
TextInput: {
defaultProps: {
variant: 'filled',
radius: 'xl',
},
},
Textarea: {
defaultProps: {
variant: 'filled',
radius: 'lg',
},
},
},
});
3. Update app/globals.css
Update /app/globals.css to import Mantine's core styles:
CSS
@import '@mantine/core/styles.css';
body {
margin: 0;
padding: 0;
background-color: #181a1d; /* Our darkest gray */
color: #e9ecef; /* Our lightest gray */
}
4. Update Root Layout (app/layout.tsx)
Update /app/layout.tsx to apply the MantineProvider:
TypeScript
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import { MantineProvider, ColorSchemeScript } from "@mantine/core";
import { theme } from "./theme";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Ponderants",
description: "Your AI Thought Partner",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<head>
{/* Enforce dark scheme as per our theme */}
<ColorSchemeScript forceColorscheme="dark" />
</head>
<body className={inter.className}>
<MantineProvider theme={theme} forceColorscheme="dark">
{children}
</MantineProvider>
</body>
</html>
);
}
5. Update Homepage (app/page.tsx)
Update /app/page.tsx to use Mantine components, confirming the theme is applied:
TypeScript
import { Stack, Title, Paper, Button, Center } from '@mantine/core';
export default function Home() {
return (
<Center h="100vh">
<Paper w={400} p="xl">
<Stack align="center">
<Title order={1}>Ponderants</Title>
<Button>Test Button</Button>
</Stack>
</Paper>
</Center>
);
}
Test Specification
1. Create Test File (tests/magnitude/02-theme.mag.ts)
Create a file at /tests/magnitude/02-theme.mag.ts:
TypeScript
import { test } from 'magnitude-test';
test('Mantine theme is applied correctly', async (agent) => {
// Act: Navigate to the homepage
await agent.act('Navigate to the homepage');
// Check: Verify the Mantine components are rendered
await agent.check('The text "Ponderants" is visible as a title');
await agent.check('A "Test Button" is visible on the screen');
// Check: Verify the theme is applied.
// We check that the button has the specific visual properties
// defined in our theme (gray color, xl radius).
await agent.check(
'The "Test Button" has a gray background, indicating the theme\'s primaryColor is active'
);
await agent.check(
'The "Test Button" has rounded corners, indicating the theme\'s defaultRadius is active'
);
// Check: Verify the Paper component is rendered with its themed styles
await agent.check(
'The page content is inside a "Paper" component with a border'
);
});