Skip to content

Theme Development ​

mineproj themes are npm packages that control the look and feel of your site.

Theme Contract ​

A theme is an object with the following properties:

PropertyTypeRequiredDescription
namestring✅Unique theme name
layoutsRecord<string, Component>✅Layouts for each route type
componentsRecord<string, Component>OptionalReusable components
slotsstring[]OptionalNamed insertion points
configSchemaZodSchemaOptionalSchema for themeConfig
localesRecord<string, Record<string, string>>OptionalUI translation dictionaries
stylesstring[]OptionalCSS strings inlined into every page head
headScriptsstring[]OptionalInline scripts injected into page head
islandsRecord<string, Component>OptionalInteractive components hydrated on the client
extendsTheme | stringOptionalParent theme to inherit from

Example ​

ts
import { defineTheme } from '@mineproj/core';

const theme = defineTheme({
  name: 'my-theme',
  layouts: {
    home: ({ data, config }) => (
      <main>
        <h1>{config.title}</h1>
        <ul>
          {data.projects.map(p => <li key={p.slug}>{p.name}</li>)}
        </ul>
      </main>
    ),
  },
  styles: [`:root { --mp-color-accent: #ff5500; }`],
});

export default theme;

Using a local theme ​

Create .mineproj/theme/index.mts:

ts
import { defineTheme } from '@mineproj/core';
export default defineTheme({ ... });

Then set theme: '.mineproj/theme' in your config.

Layouts ​

The seven required layout types:

LayoutRoutePurpose
home/Landing page with hero, featured projects, grid
list/projects/Filterable project grid
detail/projects/<slug>/Project detail with sidebar
tag/tags/<name>/Projects filtered by tag
collection/collections/<slug>/Curated collection
about/about/Author profile
notFound404.htmlCustom 404 page

Islands ​

Interactive components are marked as islands:

tsx
export function MyCounter({ start }: { start: number }) {
  const [count, setCount] = useState(start);
  return <button onClick={() => setCount(c => c + 1)}>{count}</button>;
}

Register in theme:

ts
const theme = defineTheme({
  name: 'my-theme',
  layouts: { ... },
  islands: { 'my-counter': MyCounter },
  islandsImport: 'my-theme/islands',
});

Contract Testing ​

ts
import { runThemeContract } from '@mineproj/test-utils';
const result = runThemeContract(myTheme, { requireAllLayouts: true });
console.log(result.errors); // [] if valid

Publishing ​

  1. Name your package mineproj-theme-* or @scope/mineproj-theme-*
  2. Add "keywords": ["mineproj-theme"] to package.json
  3. Run runThemeContract to validate
  4. Publish to npm

Released under the Apache-2.0 License.