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
5 changes: 5 additions & 0 deletions .changeset/full-papayas-press.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@solidmaterial/hero': minor
---

Add example app with one page for visual hero in README.md.
3 changes: 2 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
* text eol=lf
*.png binary
packages/**/*.d.ts -linguist-vendored
packages/icons/icons/** linguist-generated
packages/icons/icons/** linguist-generated
170 changes: 159 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,31 +1,179 @@
<h1 align="center">Solid Material</h1>
<div align="center">
<a href="https://solid-material.sites.deploybase.eu" target="_blank" rel="noreferrer">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="docs/images/logo-dark.svg" />
<source media="(prefers-color-scheme: light)" srcset="docs/images/logo-light.svg" />
<img alt="Solid Material logo" src="docs/images/logo-light.svg" />
</picture>
</a>
</div>

<br />

<div align="center">

[![NPM status](https://img.shields.io/npm/v/@solidmaterial/material.svg)](https://npmjs.com/package/@solidmaterial/material)
[![CI status](https://github.com/mprovok/solid-material/actions/workflows/ci.yml/badge.svg)](https://github.com/mprovok/solid-material/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/mprovok/solid-material/graph/badge.svg)](https://codecov.io/gh/mprovok/solid-material)

Material 3 Expressive for SolidJS
[![Storybook](https://img.shields.io/badge/%F0%9F%93%96%20Storybook-%236750a4)][url-storybook]

</div>

# Solid Material

> Material 3 Expressive components built for SolidJS

Solid Material is a component library implementing [Material 3 Expressive][url-m3] using [SolidJS][url-solid].
It provides components closely following the guidelines of Material 3 Expressive.

<div align="center">
<img width="40%" alt="Screenshot phone (light mode)" src="docs/images/screenshot-phone-light.png" />
<img width="40%" alt="Screenshot phone (dark mode)" src="docs/images/screenshot-phone-dark.png" />
</div>

## ✨ Features

- **Material 3 Expressive:** Components implementing the M3 Expressive spec

- **Layout Components:** Responsive components for navigation (rail and bar) and content in multiple panes

- **Dynamic Theming:** Baseline and dynamic color schemes based on a source color

- **Design Tokens:** Includes tokens for easings, springs, and static palette color tokens for 11 colors

- **View Transitions:** Animated transitions between pages using the View Transitions API

- **Few dependencies**: Avoids external dependencies as much as possible by making use of modern CSS features like
scroll-driven animations and anchor positioning

## 🚀 Quick Start

Add the components and icons to your SolidJS project:

```bash
pnpm add @solidmaterial/material @solidmaterial/icons
```

Add the Vite plugin to be able to import SVG files as SolidJS components:

```bash
pnpm add -D @solidmaterial/vite-plugin-solid-svg
```

vite.config.ts:

```ts
import solidSvg from '@solidmaterial/vite-plugin-solid-svg';
import { defineConfig } from 'vite';
import solidPlugin from 'vite-plugin-solid';

## Packages
export default defineConfig({
plugins: [solidPlugin(), solidSvg()]
});
```

| Package |
| --------------------------------------------------- |
| [@solidmaterial/material][url-sm-material] |
| [@solidmaterial/icons][url-sm-icons] |
| [@solidmaterial/vite-plugin-solid-svg][url-sm-vite] |
src/index.tsx:

## License
```tsx
import { MaterialButton } from '@solidmaterial/material/components/button';
import { MaterialCard, MaterialCardBody } from '@solidmaterial/material/components/card';
import { H1 } from '@solidmaterial/material/components/typography';
import { MaterialTheme } from '@solidmaterial/material/styling';
import { render } from 'solid-js/web';

import TotalDissolvedSolidsIcon from '@solidmaterial/icons/400/outlined/total_dissolved_solids.svg';

const App = () => {
return (
<MaterialTheme>
<main style={{ margin: '1rem' }}>
<MaterialCard variant="elevated" size="extra-large">
<MaterialCardBody>
<section style={{ display: 'flex', 'flex-direction': 'column', gap: '1rem', 'align-items': 'center' }}>
<TotalDissolvedSolidsIcon width={128} height={128} fill="var(--md-sys-color-on-surface)" />
<H1 role="headline" size="medium">
Material 3 Expressive with Solid Material
</H1>
<MaterialButton
variant="filled"
size="medium"
href="https://solid-material.sites.deploybase.eu/get-started"
>
Get started
</MaterialButton>
</section>
</MaterialCardBody>
</MaterialCard>
</main>
</MaterialTheme>
);
};

render(() => <App />, document.querySelector('#root')!);
```

## 📖 Documentation

You can read more detailed instructions on how to display navigation components (like the navigation rail and bar)
or how to put your content in flexible or fixed panes on the [Get Started][url-get-started] page.

To view all the components you can use, visit the [Storybook][url-storybook] site.

## 📦 Packages

| Package | Description |
| --------------------------------------------------- | --------------------------------------------------------------------------------- |
| [@solidmaterial/material][url-sm-material] | Core and layout components for M3 Expressive, design tokens, and view transitions |
| [@solidmaterial/icons][url-sm-icons] | Icons from Material Symbols as SVG files |
| [@solidmaterial/vite-plugin-solid-svg][url-sm-vite] | Vite plugin to import SVG files as SolidJS components |

## 🛠️ Development

```bash
pnpm install # Install dependencies
pnpm dev # Run development environment of the landing page

pnpm build # Create a production build of the packages
pnpm preview # View the production build of the landing page

pnpm lint # Run oxlint on all packages
pnpm format:check # Check formatting using oxfmt
pnpm format # Format all files using oxfmt

pnpm install:webkit # Install the WebKit browser needed to run the tests
pnpm test # Run the tests of all packages
```

## ❤️ Credits

This project uses the web components of [@material/web][url-material-web] for
the ripple, focus ring, and elevation effects, and for some of the components
often used in forms (like the checkbox, text field, etc.), these are mere bindings
around the respective web components.
See the [README.md][url-sm-material] file for the exact list.

The [Material Symbols][url-google-mdi] in [@solidmaterial/icons][url-sm-icons] were made by Google.

Many of the SolidJS components make use of the primitives from [Solid Primitives][url-solid-primitives].
Much thanks to their contributors.

## 🤖 AI?

The components (TypeScript and CSS) in [@solidmaterial/material][url-sm-material] were handcrafted,
but files which don't end up in its production build (like the calculator demo app) may
or may not have been partially assisted by small LLMs.

## 📜 License

This project is licensed under the Apache 2.0 license.

[url-get-started]: https://solid-material.sites.deploybase.eu/get-started
[url-google-mdi]: https://github.com/google/material-design-icons
[url-material-web]: https://material-web.dev/
[url-m3]: https://m3.material.io/
[url-solid]: https://www.solidjs.com/
[url-sm-material]: https://github.com/mprovok/solid-material/tree/main/packages/material#readme
[url-sm-icons]: https://github.com/mprovok/solid-material/tree/main/packages/icons#readme
[url-sm-vite]: https://github.com/mprovok/solid-material/tree/main/packages/vite-plugin-solid-svg#readme
[url-solid]: https://www.solidjs.com/
[url-solid-primitives]: https://primitives.solidjs.community/
[url-storybook]: https://solid-material.sites.deploybase.eu/storybook/
3 changes: 3 additions & 0 deletions apps/hero/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Example app using Solid Material for hero section of README.md

A small app used for a visual hero in the README.md in the root of the repository.
19 changes: 19 additions & 0 deletions apps/hero/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<meta name="description" content="Example app using Solid Material for hero section of README.md" />
<meta name="theme-color" content="#6750a4" />
<meta name="referrer" content="same-origin" />
<meta name="color-scheme" content="light dark" />
<style type="text/css">
@layer material.reset, material.theme, material.transitions, material.components;
</style>
</head>

<body>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>
32 changes: 32 additions & 0 deletions apps/hero/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"name": "@solidmaterial/hero",
"version": "1.0.0",
"private": true,
"description": "Example app using Solid Material for hero section of README.md",
"bugs": "https://github.com/mprovok/solid-material/issues",
"license": "Apache-2.0",
"author": "Mark Provo Kluit",
"repository": {
"type": "git",
"url": "git+https://github.com/mprovok/solid-material.git",
"directory": "apps/calculator"
},
"type": "module",
"scripts": {
"dev": "vite --host",
"lint": "oxlint --report-unused-disable-directives",
"lint:fix": "oxlint --fix --report-unused-disable-directives"
},
"dependencies": {
"@fontsource/google-sans-flex": "5.2.3",
"@solidjs/router": "catalog:solid",
"@solidmaterial/icons": "workspace:*",
"@solidmaterial/material": "workspace:*",
"solid-js": "catalog:solid"
},
"devDependencies": {
"@solidmaterial/vite-plugin-solid-svg": "workspace:*",
"vite": "catalog:vite",
"vite-plugin-solid": "catalog:vite"
}
}
56 changes: 56 additions & 0 deletions apps/hero/src/NavigationLayout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import type { MaterialNavigationItemType } from '@solidmaterial/material/components/navigation-item';
import type { FlowComponent } from 'solid-js';

import { MaterialNavigationLayout } from '@solidmaterial/material/layouts';

import HomeFillIcon from '@solidmaterial/icons/400/outlined/home-fill.svg';
import HomeIcon from '@solidmaterial/icons/400/outlined/home.svg';
import SettingsFillIcon from '@solidmaterial/icons/400/outlined/settings-fill.svg';
import SettingsIcon from '@solidmaterial/icons/400/outlined/settings.svg';
import ImageFillIcon from '@solidmaterial/icons/400/rounded/image-fill.svg';
import ImageIcon from '@solidmaterial/icons/400/rounded/image.svg';
import VideocamFillIcon from '@solidmaterial/icons/400/rounded/videocam-fill.svg';
import VideocamIcon from '@solidmaterial/icons/400/rounded/videocam.svg';

export const NavigationLayout: FlowComponent = props => {
const items: MaterialNavigationItemType[] = [
{
label: 'Label 1',
icon: HomeIcon,
activeIcon: HomeFillIcon,
href: '/',
end: true
},
{
label: 'Label 2',
icon: ImageIcon,
activeIcon: ImageFillIcon,
href: '/label-2'
},
{
label: 'Label 3',
icon: VideocamIcon,
activeIcon: VideocamFillIcon,
href: '/label-3'
},
{
label: 'Label 4',
icon: SettingsIcon,
activeIcon: SettingsFillIcon,
href: '/label-4'
}
];

return (
<MaterialNavigationLayout
items={items}
menuButton={{
title: 'Open menu',
titleSelected: 'Close menu'
}}
snackbarAlignment="start"
>
{props.children}
</MaterialNavigationLayout>
);
};
33 changes: 33 additions & 0 deletions apps/hero/src/components/examples/ExampleConnectedButtonGroup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import type { VoidComponent } from 'solid-js';

import { MaterialButton } from '@solidmaterial/material/components/button';
import { MaterialButtonGroup } from '@solidmaterial/material/components/button-group';
import { Breakpoints } from '@solidmaterial/material/utils';
import { Index, createSignal } from 'solid-js';

const LABELS = ['One', 'Two', 'Three'];
const LABELS_MOBILE = ['A', 'B', 'C'];

export const ExampleConnectedButtonGroup: VoidComponent = () => {
const [toggled, setToggled] = createSignal<number>(0);

const isMobile = () => Breakpoints.isCompactWidth();

return (
<MaterialButtonGroup variant="connected">
<Index each={Array.from({ length: 3 })}>
{(_, index) => (
<MaterialButton
variant="filled"
shape="round"
size="small"
toggle={toggled() === index}
onClick={() => setToggled(index)}
>
{isMobile() ? LABELS_MOBILE[index] : LABELS[index]}
</MaterialButton>
)}
</Index>
</MaterialButtonGroup>
);
};
27 changes: 27 additions & 0 deletions apps/hero/src/components/examples/ExampleList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { VoidComponent } from 'solid-js';

import { MaterialIcon } from '@solidmaterial/material/components/icon';
import { MaterialList, MaterialListItem } from '@solidmaterial/material/components/list';
import { Index } from 'solid-js';

import StarIcon from '@solidmaterial/icons/400/outlined/star.svg';

const LABELS = ['Segmented', 'Item', 'List'];

export const ExampleList: VoidComponent = () => (
<MaterialList segmented={true}>
<Index each={Array.from({ length: 3 })}>
{(_, index) => (
<MaterialListItem
start={
<MaterialIcon>
<StarIcon />
</MaterialIcon>
}
>
{LABELS[index]}
</MaterialListItem>
)}
</Index>
</MaterialList>
);
Loading
Loading