NEW: ESLint and gts added

This commit is contained in:
doryan04 2024-01-31 23:54:26 +04:00
parent d3edd23c57
commit e14630ab42
150 changed files with 24590 additions and 63 deletions

8
.editorconfig Normal file
View File

@ -0,0 +1,8 @@
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
insert_final_newline = true

1
.eslintignore Normal file
View File

@ -0,0 +1 @@
build/

3
.eslintrc.json Normal file
View File

@ -0,0 +1,3 @@
{
"extends": "./node_modules/gts/"
}

5
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
<excludeFolder url="file://$MODULE_DIR$/temp" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/google_m3_ui_kit.iml" filepath="$PROJECT_DIR$/.idea/google_m3_ui_kit.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

3
.prettierrc.js Normal file
View File

@ -0,0 +1,3 @@
module.exports = {
...require('gts/.prettierrc.json')
}

View File

@ -1,25 +1,40 @@
# Next.js + Turbopack
This example allows you to get started with `next dev --turbo` quicky.
## Deploy your own
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-turbopack&project-name=with-turbopack&repository-name=with-turbopack)
## How to use
Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init), [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/), or [pnpm](https://pnpm.io) to bootstrap the example:
```bash
npx create-next-app --example with-turbopack with-turbopack-app
```
```bash
yarn create next-app --example with-turbopack with-turbopack-app
```
```bash
pnpm create next-app --example with-turbopack with-turbopack-app
```
Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
# React/Next.js Material You UI kit (pre-alpha)
This repository is including and will be including components, enumerates in table:
- [x] Buttons
- [x] Default
- [x] Icon
- [x] FAB
- [x] Radio
- [ ] Segmented
- [x] Checkbox
- [x] Text fields
- [x] Switches
- [ ] Chips
- [x] Icon
- [x] Ripple Effect
- [x] Dividers
- [x] Badges
- [ ] Select field
- [ ] Bottom sheets
- [ ] Cards
- [ ] Menus
- [ ] Navigation
- [ ] Bars
- [ ] Drawer
- [ ] Rail
- [ ] Sliders
- [ ] Snackbar
- [ ] Tabs
- [ ] Bottom sheets
- [ ] Bottom app bars
~~and including preview page for test.~~
Preview page on stage WIP.
# Status
Nowadays, this UI kit have base kinds of components and you could make everything. For example - general forms (without select field and etc.)
# Roadmap
1. Full implementation components;
2. Release NPM package;
3. Custom theaming.
## Did you find the bug? Make sure to [leave an issue](https://github.com/doryan04/DSS/issues/new) in case of any problems.
## If you want help to the project, please, advise your idea in Pull request and don't forget [send issue](https://github.com/doryan04/DSS/issues/new)
### Check out actual news on Telegram. [https://t.me/doryanProjects](https://t.me/doryanProjects)

136
app/components/badges.tsx Normal file
View File

@ -0,0 +1,136 @@
import React from 'react';
import {Badge} from '../../src/primitive-components/badge/badge';
import {Divider} from '../../src/primitive-components/divider/divider';
export default function Badges() {
return (
<div
className={'m3 m3-wrapper'}
style={{display: 'flex', flexDirection: 'row'}}
>
<div>
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: '0.5em',
justifyContent: 'center',
alignItems: 'center',
}}
>
<div
style={{
width: '24px',
aspectRatio: 1,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Badge />
</div>
<Divider />
<div
style={{
width: '24px',
aspectRatio: 1,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Badge disableValue />
</div>
<Divider />
<div
style={{
width: '24px',
aspectRatio: 1,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Badge disableValue>3487</Badge>
</div>
<Divider />
<div
style={{
width: '24px',
aspectRatio: 1,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Badge>5</Badge>
</div>
<Divider />
<div
style={{
width: '24px',
aspectRatio: 1,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Badge>32</Badge>
</div>
<Divider />
<div
style={{
width: '24px',
aspectRatio: 1,
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Badge>322342</Badge>
</div>
</div>
</div>
{/*<Divider orientation={"vertical"} variant={"full-width"}/>*/}
{/*<div>*/}
{/* <div style={{*/}
{/* display: "flex",*/}
{/* flexDirection: "column",*/}
{/* gap: "0.5em",*/}
{/* justifyContent: "center",*/}
{/* alignItems: "center"*/}
{/* }}>*/}
{/* <div style={{*/}
{/* width: "24px",*/}
{/* aspectRatio: 1,*/}
{/* display: "flex",*/}
{/* justifyContent: "center",*/}
{/* alignItems: "center"*/}
{/* }}>*/}
{/* <Badge/>*/}
{/* </div>*/}
{/* <Divider variant={"inset"}/>*/}
{/* <div style={{*/}
{/* width: "24px",*/}
{/* aspectRatio: 1,*/}
{/* display: "flex",*/}
{/* justifyContent: "center",*/}
{/* alignItems: "center"*/}
{/* }}>*/}
{/* <Badge>5</Badge>*/}
{/* </div>*/}
{/* <Divider/>*/}
{/* <div style={{*/}
{/* width: "24px",*/}
{/* aspectRatio: 1,*/}
{/* display: "flex",*/}
{/* justifyContent: "center",*/}
{/* alignItems: "center"*/}
{/* }}>*/}
{/* <Badge>32</Badge>*/}
{/* </div>*/}
{/* </div>*/}
{/*</div>*/}
</div>
);
}

View File

@ -0,0 +1,71 @@
'use client';
import React, {useCallback, useState} from 'react';
import {Button} from '../../src/primitive-components/material-you-components';
export default function Buttons() {
const [state, setState] = useState(1);
const callback = useCallback(
() => setState(prevState => prevState + 1),
[state]
);
return (
<div className={'m3 m3-wrapper'}>
<h1> Buttons </h1>
<div style={{display: 'flex', flexDirection: 'row', gap: '2em'}}>
<div>
<h2> Default buttons </h2>
<div
style={{
display: 'flex',
flexDirection: 'column',
width: '150px',
gap: '0.5em',
}}
>
<Button
variant={'filled'}
onClick={callback}
centralRipple
>
Label + {state}
</Button>
<Button variant={'elevated'} />
<Button variant={'tonal'}>Label</Button>
<Button variant={'elevated'}>Label</Button>
<Button variant={'text'}>Label</Button>
</div>
</div>
<div>
<h2> Buttons with icon </h2>
<div
style={{
display: 'flex',
flexDirection: 'column',
width: '150px',
gap: '0.5em',
}}
>
<Button variant={'filled'} icon={'add'}>
Label
</Button>
<Button variant={'outlined'} icon={'add'}>
Label
</Button>
<Button variant={'tonal'} icon={'add'}>
Label
</Button>
<Button variant={'elevated'} icon={'add'}>
Label
</Button>
<Button variant={'text'} icon={'add'}>
Label
</Button>
</div>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,90 @@
'use client';
import React from 'react';
import {
Button,
Checkbox,
} from '../../src/primitive-components/material-you-components';
export default function Checkboxes() {
return (
<div className={'m3 m3-wrapper'}>
<h1> Checkboxes </h1>
<div
style={{
display: 'flex',
flexDirection: 'row',
width: '100%',
gap: '5em',
justifyContent: 'center',
}}
>
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: '2em',
}}
>
<div>
<h2> Default </h2>
<div style={{display: 'flex', gap: '2em'}}>
<Checkbox centralRipple />
<Checkbox defaultChecked />
<Checkbox indeterminate={true} />
</div>
</div>
<div>
<h2> Disabled </h2>
<div style={{display: 'flex', gap: '2em'}}>
<Checkbox disabled />
<Checkbox disabled defaultChecked />
</div>
</div>
</div>
<div>
<h2> Errored </h2>
<form
style={{
display: 'flex',
gap: '2em',
flexDirection: 'column',
}}
>
<div
style={{
display: 'flex',
gap: '2em',
flexDirection: 'row',
}}
>
<Checkbox required />
<Checkbox required defaultChecked />
<Checkbox required indeterminate={true} />
</div>
<div
style={{
display: 'flex',
gap: '2em',
flexDirection: 'row',
}}
>
<Checkbox required className={'m3-error'} />
<Checkbox
required
defaultChecked
className={'m3-error'}
/>
<Checkbox
required
indeterminate={true}
className={'m3-error'}
/>
</div>
<Button type={'submit'}>Send</Button>
</form>
</div>
</div>
</div>
);
}

220
app/components/fabs.tsx Normal file
View File

@ -0,0 +1,220 @@
import React from 'react';
import {FAB} from '../../src/primitive-components/material-you-components';
export default function Fabs() {
return (
<div className={'m3 m3-wrapper'}>
<div style={{display: 'flex', flexDirection: 'row', gap: '2em'}}>
<div>
<h1> FABs with elevation</h1>
<div
style={{
display: 'flex',
flexDirection: 'column',
width: '100%',
gap: '2em',
}}
>
<div>
<h2> Small </h2>
<div style={{display: 'flex', gap: '2em'}}>
<FAB
size={'small'}
icon={'edit'}
elevated
centralRipple
/>
<FAB
variant={'primary'}
size={'small'}
icon={'edit'}
elevated
/>
<FAB
variant={'secondary'}
size={'small'}
icon={'edit'}
elevated
/>
<FAB
variant={'tertiary'}
size={'small'}
icon={'edit'}
elevated
/>
</div>
</div>
<div>
<h2> Default </h2>
<div style={{display: 'flex', gap: '2em'}}>
<FAB icon={'edit'} elevated />
<FAB
variant={'primary'}
icon={'edit'}
elevated
/>
<FAB
variant={'secondary'}
icon={'edit'}
elevated
/>
<FAB
variant={'tertiary'}
icon={'edit'}
elevated
/>
</div>
</div>
<div>
<h2> Large </h2>
<div style={{display: 'flex', gap: '2em'}}>
<FAB size={'large'} icon={'edit'} />
<FAB
variant={'primary'}
size={'large'}
icon={'edit'}
elevated
/>
<FAB
variant={'secondary'}
size={'large'}
icon={'edit'}
elevated
/>
<FAB
variant={'tertiary'}
size={'large'}
icon={'edit'}
elevated
/>
</div>
</div>
<div>
<h2> Extended </h2>
<div style={{display: 'flex', gap: '2em'}}>
<FAB size={'extended'} icon={'edit'} elevated>
<span className={'label-large'}>Label</span>
</FAB>
<FAB
variant={'primary'}
size={'extended'}
icon={'edit'}
elevated
>
<span className={'label-large'}>Label</span>
</FAB>
<FAB
variant={'secondary'}
size={'extended'}
icon={'edit'}
elevated
>
<span className={'label-large'}>Label</span>
</FAB>
<FAB
variant={'tertiary'}
size={'extended'}
icon={'edit'}
elevated
>
<span className={'label-large'}>Label</span>
</FAB>
</div>
</div>
</div>
</div>
<div>
<h1> FABs without elevation</h1>
<div
style={{
display: 'flex',
flexDirection: 'column',
width: '100%',
gap: '2em',
}}
>
<div>
<h2> Small </h2>
<div style={{display: 'flex', gap: '2em'}}>
<FAB
size={'small'}
icon={'edit'}
variant={'primary'}
/>
<FAB
variant={'secondary'}
size={'small'}
icon={'edit'}
/>
<FAB
variant={'tertiary'}
size={'small'}
icon={'edit'}
/>
</div>
</div>
<div>
<h2> Default </h2>
<div style={{display: 'flex', gap: '2em'}}>
<FAB icon={'edit'} />
<FAB variant={'primary'} icon={'edit'} />
<FAB variant={'secondary'} icon={'edit'} />
<FAB variant={'tertiary'} icon={'edit'} />
</div>
</div>
<div>
<h2> Large </h2>
<div style={{display: 'flex', gap: '2em'}}>
<FAB size={'large'} icon={'edit'} />
<FAB
variant={'primary'}
size={'large'}
icon={'edit'}
/>
<FAB
variant={'secondary'}
size={'large'}
icon={'edit'}
/>
<FAB
variant={'tertiary'}
size={'large'}
icon={'edit'}
/>
</div>
</div>
<div>
<h2> Extended </h2>
<div style={{display: 'flex', gap: '2em'}}>
<FAB size={'extended'} icon={'edit'}>
<span className={'label-large'}>Label</span>
</FAB>
<FAB
variant={'primary'}
size={'extended'}
icon={'edit'}
>
<span className={'label-large'}>Label</span>
</FAB>
<FAB
variant={'secondary'}
size={'extended'}
icon={'edit'}
>
<span className={'label-large'}>Label</span>
</FAB>
<FAB
variant={'tertiary'}
size={'extended'}
icon={'edit'}
>
<span className={'label-large'}>Label</span>
</FAB>
</div>
</div>
</div>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,190 @@
'use client';
import React from 'react';
import {IconButton} from '../../src/primitive-components/material-you-components';
function IconButtons() {
return (
<div className={'m3 m3-wrapper'}>
<h1> Icon buttons </h1>
<div style={{display: 'flex', flexDirection: 'row', gap: '2em'}}>
<div>
<h2> Default buttons </h2>
<div
style={{
display: 'flex',
flexDirection: 'row',
gap: '0.5em',
}}
>
<IconButton icon={'settings'} centralRipple />
<IconButton icon={'settings'} variant={'filled'} />
<IconButton icon={'settings'} variant={'tonal'} />
<IconButton icon={'settings'} variant={'outlined'} />
</div>
<h2> Disabled default buttons </h2>
<div
style={{
display: 'flex',
flexDirection: 'row',
gap: '0.5em',
}}
>
<IconButton icon={'settings'} disabled />
<IconButton
icon={'settings'}
variant={'filled'}
disabled
/>
<IconButton
icon={'settings'}
variant={'tonal'}
disabled
/>
<IconButton
icon={'settings'}
variant={'outlined'}
disabled
/>
</div>
</div>
<div>
<h2> Toggle buttons </h2>
<div
style={{
display: 'flex',
flexDirection: 'row',
gap: '0.5em',
}}
>
<IconButton
icon={'settings'}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
/>
<IconButton
icon={'settings'}
variant={'filled'}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
/>
<IconButton
icon={'settings'}
variant={'tonal'}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
/>
<IconButton
icon={'settings'}
variant={'outlined'}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
/>
</div>
<h2> Disabled toggle buttons </h2>
<div
style={{
display: 'flex',
flexDirection: 'row',
gap: '0.5em',
}}
>
<IconButton
icon={'settings'}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
disabled
/>
<IconButton
icon={'settings'}
variant={'filled'}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
disabled
/>
<IconButton
icon={'settings'}
variant={'tonal'}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
disabled
/>
<IconButton
icon={'settings'}
variant={'outlined'}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
disabled
/>
</div>
<h2> Disabled selected toggle buttons </h2>
<div
style={{
display: 'flex',
flexDirection: 'row',
gap: '0.5em',
}}
>
<IconButton
icon={'settings'}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
disabled
selected
/>
<IconButton
icon={'settings'}
variant={'filled'}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
disabled
selected
/>
<IconButton
icon={'settings'}
variant={'tonal'}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
disabled
selected
/>
<IconButton
icon={'settings'}
variant={'outlined'}
toggled={{
selected: 'settings',
unselected: 'settings',
}}
disabled
selected
/>
</div>
</div>
</div>
</div>
);
}
export default IconButtons;

34
app/components/radios.tsx Normal file
View File

@ -0,0 +1,34 @@
import React from 'react';
import {Radio} from '../../src/primitive-components/material-you-components';
export default function Radios() {
return (
<div className={'m3 m3-wrapper'}>
<h1> Radio </h1>
<div
style={{
display: 'flex',
flexDirection: 'row',
width: '100%',
gap: '5em',
justifyContent: 'center',
}}
>
<div>
<h2> Default </h2>
<div style={{display: 'flex', gap: '2em'}}>
<Radio centralRipple />
<Radio defaultChecked />
</div>
</div>
<div>
<h2> Disabled </h2>
<div style={{display: 'flex', gap: '2em'}}>
<Radio disabled />
<Radio disabled defaultChecked />
</div>
</div>
</div>
</div>
);
}

View File

@ -0,0 +1,81 @@
import React from 'react';
import {Switch} from '../../src/primitive-components/material-you-components';
export default function Switches() {
return (
<div
className={'m3 m3-wrapper'}
style={{display: 'flex', flexDirection: 'column', gap: '1.5em'}}
>
<h1> Switches </h1>
<div style={{display: 'flex', flexDirection: 'row', gap: '2em'}}>
<div style={{display: 'flex', flexDirection: 'column'}}>
<h2 style={{margin: 0}}> Without icon </h2>
<div
style={{
display: 'flex',
flexDirection: 'row',
width: '100%',
gap: '2em',
}}
>
<div>
<h2> Default </h2>
<Switch />
<Switch defaultChecked />
</div>
<div>
<h2> Disabled </h2>
<Switch disabled />
<Switch disabled defaultChecked />
</div>
</div>
</div>
<div style={{display: 'flex', flexDirection: 'column'}}>
<h2 style={{margin: 0}}> With icon (both)</h2>
<div
style={{
display: 'flex',
flexDirection: 'row',
width: '100%',
gap: '2em',
}}
>
<div>
<h2> Default </h2>
<Switch icon />
<Switch defaultChecked icon />
</div>
<div>
<h2> Disabled </h2>
<Switch disabled icon />
<Switch disabled defaultChecked icon />
</div>
</div>
</div>
<div style={{display: 'flex', flexDirection: 'column'}}>
<h2 style={{margin: 0}}> With icon (selected)</h2>
<div
style={{
display: 'flex',
flexDirection: 'row',
width: '100%',
gap: '2em',
}}
>
<div>
<h2> Default </h2>
<Switch selected icon />
<Switch selected defaultChecked icon />
</div>
<div>
<h2> Disabled </h2>
<Switch selected disabled icon />
<Switch selected disabled defaultChecked icon />
</div>
</div>
</div>
</div>
</div>
);
}

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,24 @@
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
import '../src/styles/generics.css';
import '../src/styles/button.css';
import '../src/styles/ripple.css';
import {Metadata, Viewport} from 'next';
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
};
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
maximumScale: 1,
userScalable: false,
};
export default function RootLayout({children}: {children: React.ReactNode}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}

View File

@ -1,3 +1,46 @@
import {Fragment} from 'react';
import Fabs from './components/fabs';
import Badges from './components/badges';
import IconButtons from './components/icon-buttons';
import Buttons from './components/buttons';
import Switches from './components/switches';
import Checkboxes from './components/checkboxes';
import Radios from './components/radios';
import {TextFields} from './components/text-fields';
export default function Page() {
return <h1>Hello, Next.js!</h1>;
return (
<Fragment>
<div
style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
overflowX: 'auto',
gap: '0em',
}}
>
<h1>Google Material You UI kit</h1>
<div
style={{
display: 'flex',
flexDirection: 'column',
gap: '0.5em',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Buttons />
<IconButtons />
<Switches />
<Checkboxes />
<Radios />
<TextFields />
<Fabs />
<Badges />
</div>
</div>
</Fragment>
);
}

5511
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,17 +3,28 @@
"scripts": {
"dev": "next dev --turbo",
"build": "next build",
"start": "next start"
"start": "next start",
"lint": "gts lint",
"clean": "gts clean",
"compile": "tsc",
"fix": "gts fix",
"prepare": "npm run compile",
"pretest": "npm run compile",
"posttest": "npm run lint"
},
"dependencies": {
"install": "^0.13.0",
"next": "latest",
"npm": "^10.4.0",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/node": "20.8.10",
"@types/node": "20.8.2",
"@types/react": "18.2.33",
"@types/react-dom": "18.2.14",
"typescript": "^5.2.2"
"gts": "^5.2.0",
"typescript": "~5.2.0"
}
}

33
src/index.ts Normal file
View File

@ -0,0 +1,33 @@
console.log('Try npm run lint/fix!');
const longString =
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ut aliquet diam.';
const trailing = 'Semicolon';
const why = {am: 'I tabbed?'};
const iWish = "I didn't have a trailing space...";
const sicilian = true;
const vizzini = sicilian ? !sicilian : sicilian;
const re = /foo {3}bar/;
export function doSomeStuff(
withThis: string,
andThat: string,
andThose: string[]
) {
//function on one line
if (!andThose.length) {
return false;
}
console.log(withThis);
console.log(andThat);
console.dir(andThose);
console.log(longString, trailing, why, iWish, vizzini, re);
return;
}
// TODO: more examples

View File

@ -0,0 +1,43 @@
import React, {ForwardedRef, forwardRef, PropsWithChildren} from 'react';
import {bool, number, string} from 'prop-types';
interface BadgeProps extends PropsWithChildren<any> {
disableValue?: boolean;
}
const Badge = forwardRef(
({disableValue = false, ...props}: BadgeProps, ref: ForwardedRef<any>) => {
const digitLength = props.children
? 16 + (props.children.length - 1) * 6
: 6,
disableValueClassName =
disableValue || (!props.children ?? true)
? 'disable-value'
: '';
return (
<svg
{...props}
ref={ref}
width={`${digitLength}px`}
className={`m3 m3-badge ${
'' ?? props.className
}${disableValueClassName}`.trimEnd()}
>
{props.children && (
<text x={'50%'} y={'50%'}>
{props.children}
</text>
)}
</svg>
);
}
);
Badge.propTypes = {
children: number,
className: string,
disableValue: bool,
};
export {Badge};

View File

@ -0,0 +1,53 @@
'use client';
import {RippleArea} from '../ripple/ripple-area';
import React, {
forwardRef,
PropsWithChildren,
useId,
useRef,
useState,
} from 'react';
import useRippleEffect from '../ripple/hooks/useRippleEffect';
import {IRippleProps} from '../ripple/ripple.types';
const ButtonLayout = forwardRef(
(
{
centralRipple = false,
...props
}: PropsWithChildren<any> & IRippleProps,
ref
) => {
const [isActive, setIsActive] = useState<boolean>(false),
ripplesRef = useRef(null),
buttonId = useId(),
events = useRippleEffect(ripplesRef, setIsActive);
const {variant, disabled, className} = props;
const classes = className
? `m3 ${className} ${variant}${isActive ? ' is-active' : ''}`
: `m3 ${variant}${isActive ? ' is-active' : ''}`;
return (
<button
{...props}
{...events}
ref={ref}
id={buttonId}
className={classes}
disabled={disabled}
>
{props.children}
<RippleArea
ref={ripplesRef}
central={centralRipple}
callback={setIsActive}
/>
</button>
);
}
);
export {ButtonLayout};

View File

@ -0,0 +1,25 @@
import {PropsWithChildren} from 'react';
type toggleButtonType = {
selected: string;
unselected: string;
};
export interface buttonMainProps extends PropsWithChildren<any> {
disabled?: boolean;
variant?: 'filled' | 'outlined' | 'elevated' | 'tonal' | 'text';
}
export interface FABMainProps extends PropsWithChildren<any> {
icon: string;
disabled?: boolean;
size?: 'small' | 'default' | 'large' | 'extended';
variant?: 'surface' | 'primary' | 'secondary' | 'tertiary';
}
export interface iconButtonMainProps extends PropsWithChildren<any> {
icon: string;
toggled?: false | toggleButtonType;
disabled?: boolean;
variant?: 'default' | 'filled' | 'tonal' | 'outlined';
}

View File

@ -0,0 +1,34 @@
import {forwardRef} from 'react';
import {Icon} from '../material-you-components';
import {IRippleProps} from '../ripple/ripple.types';
import {ButtonLayout} from '../button-layout/button-layout';
import {buttonMainProps} from '../button-layout/button.types';
/**
* Button component
** description
*/
export const Button = forwardRef(
(
{
centralRipple = false,
variant,
disabled,
icon,
...props
}: buttonMainProps & IRippleProps,
ref
) => (
<ButtonLayout
{...props}
ref={ref}
disabled={disabled}
centralRipple={centralRipple}
variant={variant ? variant : 'filled'}
>
{icon ? <Icon iconSize={20}>{icon}</Icon> : <></>}
<span className={'label-large'}>{props.children}</span>
</ButtonLayout>
)
);

View File

@ -0,0 +1,35 @@
'use client';
import React, {forwardRef, useEffect, useImperativeHandle, useRef} from 'react';
import {CheckboxLayoutProps} from './checkbox-layout.types';
export const CheckBoxLayout = forwardRef(
(
{indeterminate, typeInput, type, ...props}: CheckboxLayoutProps,
ref
): JSX.Element => {
const checkboxRef = useRef<any>(null);
useEffect(() => {
checkboxRef.current.indeterminate = indeterminate === true;
}, []);
useImperativeHandle(ref, () => checkboxRef.current);
const classesType = typeInput || type;
const classes =
props.className !== undefined
? `m3 m3-${type} ${props.className}`
: `m3 m3-${classesType}`;
return (
<input
ref={checkboxRef}
{...props}
type={type}
className={classes.trimEnd()}
/>
);
}
);

View File

@ -0,0 +1,7 @@
import {PropsWithChildren} from 'react';
export interface CheckboxLayoutProps extends PropsWithChildren<any> {
indeterminate?: boolean;
typeInput?: string;
type?: string;
}

View File

@ -0,0 +1,56 @@
import {RippleArea} from '../ripple/ripple-area';
import {IRippleProps} from '../ripple/ripple.types';
import useRippleEffect from '../ripple/hooks/useRippleEffect';
import {CheckBoxLayout} from '../checkbox-layout/check-box-layout';
import {
forwardRef,
useEffect,
useImperativeHandle,
useRef,
useState,
} from 'react';
/**
* Checkbox component
** description
*/
export const Checkbox = forwardRef(
({centralRipple, ...props}: any & IRippleProps, ref) => {
const [isActive, setIsActive] = useState<boolean>(false),
[checked, setChecked] = useState<boolean>(props.checked ?? false),
ripplesRef = useRef(null),
checkboxRef = useRef(null),
events = useRippleEffect(ripplesRef, setIsActive);
const classes = `m3 m3-checkbox-label ${
isActive === true ? 'visible' : ''
}`.trimEnd();
const indeterminate = (props.indeterminate === true).toString();
useImperativeHandle(ref, () => checkboxRef.current);
useEffect(() => {
setChecked(!checked);
}, [checkboxRef.current?.checked]);
return (
<label {...events} className={classes}>
<CheckBoxLayout
{...props}
ref={checkboxRef}
indeterminate={indeterminate}
type={'checkbox'}
/>
<span className={'m3 m3-checkbox-state-layer'} />
<RippleArea
className={'m3-checkbox-ripple-layer'}
ref={ripplesRef}
central={centralRipple}
callback={setIsActive}
/>
{props.children}
</label>
);
}
);

View File

@ -0,0 +1,25 @@
import React, {ForwardedRef, forwardRef, PropsWithChildren} from 'react';
interface DividerProps extends PropsWithChildren<any> {
orientation?: 'vertical' | 'horizontal';
variant?: 'full-width' | 'inset' | 'middle-inset';
}
const Divider = forwardRef(
(
{orientation, variant, ...props}: DividerProps,
ref: ForwardedRef<any>
) => {
return (
<hr
{...props}
ref={ref}
className={`m3 m3-divider ${orientation ?? 'horizontal'} ${
variant ?? 'full-width'
}`.trimEnd()}
/>
);
}
);
export {Divider};

View File

@ -0,0 +1,51 @@
import {forwardRef} from 'react';
import {FABMainProps} from '../button-layout/button.types';
import {ButtonLayout} from '../button-layout/button-layout';
import {IRippleProps} from '../ripple/ripple.types';
import {Icon} from '../material-you-components';
/**
* FABs component
** description
*/
const sizes = {
small: 24,
default: 24,
large: 36,
extended: 24,
};
export const FAB = forwardRef(
(
{
variant,
disabled,
icon,
centralRipple = false,
size = 'default',
elevated,
...props
}: FABMainProps & IRippleProps,
ref
) => (
<ButtonLayout
{...props}
ref={ref}
centralRipple={centralRipple}
variant={variant ? variant : 'surface'}
className={`m3-fab m3-${size}-fab ${
!(elevated ?? false) && 'without-elevation'
}`}
>
<Icon iconSize={sizes[size]} svgSize={sizes[size]}>
{icon}
</Icon>
{size === 'extended' ? (
<span className={'label-large'}>{props.children}</span>
) : (
<></>
)}
</ButtonLayout>
)
);

View File

@ -0,0 +1,78 @@
import {ButtonLayout} from '../button-layout/button-layout';
import {iconButtonMainProps} from '../button-layout/button.types';
import {
forwardRef,
useCallback,
useImperativeHandle,
useRef,
useState,
} from 'react';
import {IRippleProps} from '../ripple/ripple.types';
import {Icon} from '../material-you-components';
/**
* Icon button-layout component
** description
*/
export const IconButton = forwardRef(
(
{
icon,
variant,
disabled,
selected = false,
toggled = false,
centralRipple,
...props
}: iconButtonMainProps & IRippleProps,
ref
) => {
const [toggleIcon, setToggleIcon] = useState<any>({
state: selected === true ? 'selected' : 'unselected',
icon: toggled ? toggled.unselected ?? 'add_circle' : 'add_circle',
});
const toggle = (classes: string, icon: string) => {
setToggleIcon(() => ({
state: classes,
icon: icon,
}));
};
const buttonRef = useRef<HTMLButtonElement>(null);
const callback = useCallback(() => {
if (toggled) {
if (toggleIcon.state === 'selected')
toggle('', toggled.unselected ?? 'add_circle');
else toggle('selected', toggled.selected ?? 'add_circle');
}
if (props.onClick) props.onClick();
}, [toggleIcon]);
useImperativeHandle(ref, () => buttonRef);
return (
<ButtonLayout
{...props}
ref={buttonRef}
onClick={callback}
centralRipple={centralRipple}
disabled={disabled}
className={`m3-icon-button ${toggleIcon.state} ${
toggled ? 'toggled' : ''
}`.trimEnd()}
variant={variant ? variant : 'default'}
>
<Icon
svgSize={40}
iconSize={28}
fill={toggleIcon.state === 'selected' ? 1 : 0}
>
{toggled ? toggleIcon.icon : icon ? icon : undefined}
</Icon>
</ButtonLayout>
);
}
);

View File

@ -0,0 +1,59 @@
import React, {ForwardedRef, forwardRef} from 'react';
import {IconProps} from './icon.types';
import {bool, number, string} from 'prop-types';
const Icon = forwardRef(
(
{
grade = 0,
weight = 500,
svgSize = 20,
fill = false,
iconSize = 20,
opticalSize = 24,
type = 'outlined',
...props
}: IconProps,
ref: ForwardedRef<any>
) => {
const fontVariation = {
fontVariationSettings: `'FILL' ${
fill ? 1 : 0
}, 'wght' ${weight}, 'GRAD' ${grade}, 'optz' ${opticalSize}`,
};
return (
<svg
{...props}
ref={ref}
className={`m3 m3-svg-icon ${props.className ?? ''}`.trim()}
width={svgSize}
height={svgSize}
>
<text
className={`m3-${
type[0].toUpperCase() + type.slice(1)
} m3-size-${iconSize}px`}
style={fontVariation}
x={'50%'}
y={'50%'}
>
{props.children ?? 'add_circle'}
</text>
</svg>
);
}
);
Icon.propTypes = {
fill: bool,
type: string,
grade: number,
weight: number,
svgSize: number,
iconSize: number,
children: string,
opticalSize: number,
};
export {Icon};

View File

@ -0,0 +1,11 @@
import {PropsWithChildren} from 'react';
export interface IconProps extends PropsWithChildren<any> {
fill?: boolean;
grade?: number;
svgSize?: number;
iconSize?: number;
opticalSize?: number;
type?: 'outlined' | 'rounded' | 'sharp';
weight?: 100 | 200 | 300 | 400 | 500 | 600 | 700;
}

View File

@ -0,0 +1,13 @@
export {FAB} from './fab/fab';
export {Icon} from './icon/icon';
export {Radio} from './radio/radio';
export {Badge} from './badge/badge';
export {Switch} from './switch/switch';
export {Button} from './button/button';
export {Divider} from './divider/divider';
export {Checkbox} from './checkbox/checkbox';
export {RippleArea} from './ripple/ripple-area';
export {Ripples, Ripple} from './ripple/ripple';
export {TextField} from './text-field/text-field';
export {IconButton} from './icon-button/icon-button';
export {ButtonLayout} from './button-layout/button-layout';

View File

@ -0,0 +1,36 @@
import {RippleArea} from '../ripple/ripple-area';
import {forwardRef, useRef, useState} from 'react';
import useRippleEffect from '../ripple/hooks/useRippleEffect';
import {CheckBoxLayout} from '../checkbox-layout/check-box-layout';
import {IRippleProps} from '../ripple/ripple.types';
/**
* Radio component
** description
*/
export const Radio = forwardRef(
({centralRipple, ...props}: any & IRippleProps, ref) => {
const [isActive, setIsActive] = useState<boolean>(false),
ripplesRef = useRef(null),
events = useRippleEffect(ripplesRef, setIsActive);
const classes = `m3 m3-radio-label ${
isActive === true ? 'visible' : ''
}`.trimEnd();
return (
<label {...events} className={classes}>
<CheckBoxLayout {...props} ref={ref} type={'radio'} />
<span className={'m3 m3-radio-state-layer'} />
<RippleArea
className={'m3-checkbox-ripple-layer'}
ref={ripplesRef}
central={centralRipple}
callback={setIsActive}
/>
{props.children}
</label>
);
}
);

View File

@ -0,0 +1,55 @@
import React, {useEffect, useState} from 'react';
interface RippleEventHandlers {
onBlur: React.FocusEventHandler;
onContextMenu: React.MouseEventHandler;
onDragLeave: React.DragEventHandler;
onMouseDown: React.MouseEventHandler;
onMouseLeave: React.MouseEventHandler;
onMouseUp: React.MouseEventHandler;
onTouchEnd: React.TouchEventHandler;
onTouchMove: React.TouchEventHandler;
onTouchStart: React.TouchEventHandler;
}
export type EventHandlerType<T> =
| React.FocusEvent<T>
| React.DragEvent<T>
| React.MouseEvent<T>
| React.TouchEvent<T>;
interface RefImperativeType {
current: {
start: (event: EventHandlerType<Element>, callback: () => void) => void;
stop: (event: EventHandlerType<Element>, callback: () => void) => void;
};
}
const UseRippleEffect = (
ref: RefImperativeType,
callback: () => void
): undefined | RippleEventHandlers => {
const [mounted, setMounted] = useState<boolean>(false);
useEffect(() => {
if (!mounted) setMounted(true);
});
if (!mounted) return;
const {start, stop} = ref.current;
return {
onBlur: event => stop(event, callback),
onContextMenu: event => start(event, callback),
onDragLeave: event => stop(event, callback),
onMouseDown: event => start(event, callback),
onMouseLeave: event => stop(event, callback),
onMouseUp: event => stop(event, callback),
onTouchEnd: event => stop(event, callback),
onTouchMove: event => stop(event, callback),
onTouchStart: event => stop(event, callback),
};
};
export default UseRippleEffect;

View File

@ -0,0 +1,133 @@
'use client';
import React, {
useId,
useRef,
useState,
forwardRef,
useCallback,
useImperativeHandle,
} from 'react';
import {Ripple} from './ripple';
import {Ripples} from './ripple';
import {RippleAreaProps} from './ripple.types';
const TIMEOUT = 550;
const rippleAreaContext = React.createContext(false);
const RippleArea = forwardRef(
({central = false, callback, ...props}: RippleAreaProps, ref) => {
const [ripples, setRipples] = useState<Array<JSX.Element>>([]),
rippleDomain = useRef<any>(null),
clicked = useRef<boolean>(false),
uniqueKey = useRef<number>(0),
uniqueId = useId();
const classes = props.className
? `m3 m3-ripple-domain ${props.className}`.trimEnd()
: 'm3 m3-ripple-domain';
const start = useCallback(
(event: any, cb: (state: boolean) => void): void => {
clicked.current = true;
cb(clicked.current);
const rippleDomainChar = rippleDomain.current
? rippleDomain.current.getBoundingClientRect()
: {
width: 0,
height: 0,
left: 0,
top: 0,
};
const rippleX: number = !central
? event.clientX - rippleDomainChar.left
: rippleDomainChar.width / 2,
rippleY: number = !central
? event.clientY - rippleDomainChar.top
: rippleDomainChar.height / 2,
rippleSizeX: number =
Math.max(
Math.abs(rippleDomainChar.width - rippleX),
rippleX
) *
2 +
2,
rippleSizeY: number =
Math.max(
Math.abs(rippleDomainChar.height - rippleY),
rippleY
) *
2 +
2,
rippleS: number =
(rippleSizeX ** 2 + rippleSizeY ** 2) ** 0.5;
setRipples((prevRipples: Array<JSX.Element>) => {
if (prevRipples.length === 0) {
return [
<Ripple
rippleX={rippleX}
rippleY={rippleY}
rippleS={rippleS}
key={uniqueKey.current}
lifetime={TIMEOUT}
/>,
];
} else {
const old = [...prevRipples];
old.push(
<Ripple
rippleX={rippleX}
rippleY={rippleY}
rippleS={rippleS}
key={uniqueKey.current}
lifetime={TIMEOUT}
/>
);
return old;
}
});
uniqueKey.current += 1;
},
[]
);
const stop = useCallback(
(_event: any, cb: (state: boolean) => void) => {
clicked.current = false;
cb(clicked.current);
setRipples((prevRipples: Array<JSX.Element>) => {
if (prevRipples.length > 0) {
const old = [...prevRipples];
old.shift();
return old;
}
return prevRipples;
});
},
[]
);
useImperativeHandle(
ref,
() => ({
start,
stop,
}),
[start, stop]
);
return (
<span className={classes} id={uniqueId} ref={rippleDomain}>
<rippleAreaContext.Provider value={clicked.current}>
<Ripples>{ripples}</Ripples>
</rippleAreaContext.Provider>
</span>
);
}
);
export {rippleAreaContext, RippleArea};

View File

@ -0,0 +1,80 @@
'use client';
import isEmpty from './utils/utils';
import {rippleProps} from './ripple.types';
import {rippleAreaContext} from './ripple-area';
import RippleEffectBuild from './utils/ripple-effect-builder';
import React, {
useRef,
useState,
useEffect,
forwardRef,
useContext,
useCallback,
ForwardedRef,
useTransition,
JSX,
} from 'react';
const Ripples = forwardRef((props: any, ref: ForwardedRef<any>) => {
const [ripples, setRipples] = useState({});
const firstRender = useRef<boolean>(true);
const [pending, startTransition] = useTransition();
const LifetimeEnd = useCallback((child: JSX.Element) => {
if (child.props.endLifetime) {
child.props.endLifetime();
}
setRipples(state => {
const children = {...state};
delete children[child.key];
return children;
});
}, []);
useEffect(() => {
if (props.children.length > 0) {
startTransition(() => {
if (firstRender.current || isEmpty(ripples)) {
setRipples(RippleEffectBuild(props.children, LifetimeEnd));
firstRender.current = false;
} else {
setRipples(
RippleEffectBuild(props.children, LifetimeEnd, ripples)
);
}
});
}
}, [props.children]);
return <>{Object.values(ripples)}</>;
});
const Ripple = forwardRef((props: rippleProps, ref: ForwardedRef<any>) => {
const {rippleX, rippleY, rippleS, endLifetime, lifetime} = props;
const clicked = useContext<boolean>(rippleAreaContext);
const [classes, setClasses] = useState<string>('m3 ripple visible');
useEffect(() => {
if (endLifetime !== null && !clicked) {
setClasses('m3 ripple');
setTimeout(endLifetime, lifetime);
}
}, [clicked, endLifetime]);
return (
<span
className={classes}
style={{
left: -(rippleS / 2) + rippleX,
top: -(rippleS / 2) + rippleY,
width: rippleS,
aspectRatio: 1,
}}
/>
);
});
export {Ripple, Ripples};

View File

@ -0,0 +1,19 @@
import {Dispatch, SetStateAction, PropsWithChildren} from 'react';
export interface IRippleProps {
centralRipple?: boolean;
}
export interface RippleAreaProps extends PropsWithChildren<any> {
callback: Dispatch<SetStateAction<boolean>>;
central?: boolean;
}
export type rippleProps = {
rippleX: number;
rippleY: number;
rippleS: number;
endLifetime?: any;
lifetime: number;
key?: number;
};

View File

@ -0,0 +1,15 @@
import {cloneElement, ReactElement} from 'react';
export default function ArrayConvertToObj(
obj: Object,
nextChildren: ReactElement[],
callback: (child: any) => void
): void {
Object.values(nextChildren).forEach(
(child: JSX.Element) =>
(obj[child.key] = cloneElement(child, {
...child.props,
endLifetime: callback.bind(null, child),
}))
);
}

View File

@ -0,0 +1,34 @@
import isEmpty from './utils';
import {cloneElement, ReactElement} from 'react';
import ArrayConvertToObj from './array-convert-to-obj';
export default function RippleEffectBuild(
nextRipples: ReactElement[],
callback: (child: any) => void,
prevRipples?: any | null
) {
const next: object = {};
const empty: boolean = isEmpty(prevRipples);
const preparedRipples: object = empty ? {} : prevRipples;
console.log(preparedRipples);
switch (empty) {
case true:
ArrayConvertToObj(preparedRipples, nextRipples, callback);
break;
case false:
ArrayConvertToObj(next, nextRipples, callback);
for (const rippleKey of Object.keys(next)) {
if (preparedRipples[rippleKey] === undefined) {
preparedRipples[rippleKey] = cloneElement(next[rippleKey], {
...next[rippleKey].props,
endLifetime: callback.bind(null, next[rippleKey]),
});
}
}
break;
}
return preparedRipples;
}

View File

@ -0,0 +1,4 @@
export default function isEmpty(obj: Object): boolean {
for (const _i in obj) return false;
return true;
}

View File

@ -0,0 +1,38 @@
import React, {ForwardedRef, forwardRef} from 'react';
import {switchMainProps} from './switch.types';
import {CheckBoxLayout} from '../checkbox-layout/check-box-layout';
/**
* Switch component
** description
*/
export const Switch = forwardRef(
(
{icon, disabled, selected = false, ...props}: switchMainProps,
ref: ForwardedRef<HTMLInputElement>
) => (
<div className={'m3 m3-switch-exp'}>
<CheckBoxLayout
{...props}
ref={ref}
type={'checkbox'}
disabled={disabled}
className={`m3 ${props.className ?? ''}`.trimEnd()}
/>
<svg>
<rect className={'m3 m3-switch-track'} />
<circle className={'m3 m3-switch-handler'} />
<circle className={'m3 m3-switch-handler-state-layer'} />
<g>
{icon && !selected && (
<text className={'m3 m3-icon-unchecked'}>close</text>
)}
{icon && (
<text className={'m3 m3-icon-checked'}>check</text>
)}
</g>
</svg>
</div>
)
);

View File

@ -0,0 +1,7 @@
import {PropsWithChildren} from 'react';
export interface switchMainProps extends PropsWithChildren<any> {
disabled?: boolean;
icon?: boolean;
selected?: boolean;
}

View File

@ -0,0 +1,89 @@
'use client';
import React, {useState} from 'react';
import {bool, string} from 'prop-types';
import {type TextFieldInterface} from './text-field.types';
export function TextField({
variant = 'filled',
withAfterIcon,
withBeforeIcon,
supportingText,
...props
}: TextFieldInterface) {
const [raised, setRaised] = useState<boolean>(props.placeholder ?? false);
const callback = (e: any) => {
if (
e.type === 'blur' &&
e.target.value.length === 0 &&
!props.placeholder
)
setRaised(false);
else if (e.type === 'focus') setRaised(true);
};
const iconStyles =
withBeforeIcon && withAfterIcon
? 'with-before-icon with-after-icon'
: withBeforeIcon
? 'with-before-icon'
: withAfterIcon
? 'with-after-icon'
: '';
return (
<span>
<div className={`m3 m3-text-field ${variant}`.trimEnd()}>
{variant === 'outlined' && (
<fieldset>
<legend className={raised && 'raised'}>
<span>Label</span>
</legend>
</fieldset>
)}
{withBeforeIcon && (
<span className={'m3-icon icon-before'}>
{withBeforeIcon && 'search'}
</span>
)}
<input
{...props}
className={`${props.className ?? ''} ${iconStyles}`.trim()}
onFocus={event => {
callback(event);
if (props.onFocus) props.onFocus(event);
}}
onBlur={event => {
callback(event);
if (props.onBlur) props.onBlur(event);
}}
/>
<label className={raised ? 'raised' : ''}>
{props.children ?? 'Label'}
</label>
<span className={'m3-text-field-state-layer'} />
{withAfterIcon && (
<span className={'m3-icon'}>
{withAfterIcon && 'cancel'}
</span>
)}
</div>
{supportingText && (
<span className={'m3-text-field-supporting-text'}>
{supportingText}
</span>
)}
</span>
);
}
TextField.propTypes = {
children: string,
withBeforeIcon: bool,
withAfterIcon: bool,
className: string,
variant: string,
placeholder: string,
supportingText: string,
};

View File

@ -0,0 +1,8 @@
import {PropsWithChildren} from 'react';
export interface TextFieldInterface extends PropsWithChildren<any> {
variant: 'filled' | 'outlined';
withAfterIcon?: boolean;
withBeforeIcon?: boolean;
supportingText?: string;
}

31
src/styles/badge.css Normal file
View File

@ -0,0 +1,31 @@
svg.m3.m3-badge {
position: absolute;
background-color: var(--md-sys-color-error);
}
svg.m3.m3-badge.disable-value {
padding: 0;
height: 6px;
width: 6px;
border-radius: 3px;
}
svg.m3.m3-badge.disable-value > text {
display: none;
}
svg.m3.m3-badge {
border-radius: 8px;
height: 16px;
}
svg.m3.m3-badge > text {
fill: var(--md-sys-color-on-error);
font-size: var(--md-sys-typescale-label-small-font-size);
font-weight: var(--md-sys-typescale-label-small-font-weight);
line-height: var(--md-sys-typescale-label-small-line-height);
font-optical-sizing: none;
alignment-baseline: central;
text-anchor: middle;
display: flex;
align-items: center;
justify-content: center;
}
/*# sourceMappingURL=badge.css.map */

1
src/styles/badge.css.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["badge.sass"],"names":[],"mappings":"AAAA;EACI;EACA;;AACA;EACI;EACA;EACA;EACA;;AACA;EACI;;AACR;EACI;EACA;;AAEJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA","file":"badge.css"}

25
src/styles/badge.sass Normal file
View File

@ -0,0 +1,25 @@
svg.m3.m3-badge
position: absolute
background-color: var(--md-sys-color-error)
&.disable-value
padding: 0
height: 6px
width: 6px
border-radius: 3px
& > text
display: none
&
border-radius: 8px
height: 16px
& > text
fill: var(--md-sys-color-on-error)
font-size: var(--md-sys-typescale-label-small-font-size)
font-weight: var(--md-sys-typescale-label-small-font-weight)
line-height: var(--md-sys-typescale-label-small-line-height)
font-optical-sizing: none
alignment-baseline: central
text-anchor: middle
display: flex
align-items: center
justify-content: center

132
src/styles/button.css Normal file
View File

@ -0,0 +1,132 @@
button:not(.m3-fab, .m3-icon-button) {
transition: background-color, box-shadow, 0.2s cubic-bezier(0.2, 0, 0, 1) !important;
font-family: var(--md-sys-typescale-label-large-font-family-name);
font-size: var(--md-sys-typescale-label-large-font-size);
font-weight: var(--md-sys-typescale-label-large-font-weight);
line-height: var(--md-sys-typescale-label-large-line-height);
box-sizing: border-box;
}
button:not(.m3-fab, .m3-icon-button).m3 {
contain: content;
box-sizing: border-box;
border-radius: 100px;
display: inline-flex;
flex-direction: row;
justify-content: center;
align-items: center;
text-align: center;
padding: 10px 24px;
border: none;
gap: 8px;
}
button:not(.m3-fab, .m3-icon-button).filled {
background-color: var(--md-sys-color-primary);
}
button:not(.m3-fab, .m3-icon-button).filled, button:not(.m3-fab, .m3-icon-button).filled > svg.m3-svg-icon {
color: var(--md-sys-color-on-primary);
fill: var(--md-sys-color-on-primary);
}
button:not(.m3-fab, .m3-icon-button).outlined {
outline-offset: -1px;
outline: 1px solid var(--md-sys-color-outline) !important;
background-color: rgba(0, 0, 0, 0);
color: var(--md-sys-color-primary);
}
button:not(.m3-fab, .m3-icon-button).outlined > svg.m3-svg-icon {
fill: var(--md-sys-color-primary);
}
button:not(.m3-fab, .m3-icon-button).text {
padding: 10px 12px !important;
background-color: rgba(0, 0, 0, 0);
color: var(--md-sys-color-primary);
}
button:not(.m3-fab, .m3-icon-button).text > svg.m3-svg-icon {
fill: var(--md-sys-color-primary);
}
button:not(.m3-fab, .m3-icon-button).elevated {
box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.15), 0 1px 2px 0 rgba(0, 0, 0, 0.3);
background-color: var(--md-sys-color-surface-container-low);
color: var(--md-sys-color-primary);
}
button:not(.m3-fab, .m3-icon-button).elevated > svg.m3-svg-icon {
fill: var(--md-sys-color-primary);
}
button:not(.m3-fab, .m3-icon-button).tonal {
background-color: var(--md-sys-color-secondary-container);
color: var(--md-sys-color-on-secondary-container);
}
button:not(.m3-fab, .m3-icon-button).tonal > svg.m3-svg-icon {
fill: var(--md-sys-color-on-secondary-container);
}
button:not(.m3-fab, .m3-icon-button)::before {
transition: background-color, box-shadow, 0.2s cubic-bezier(0.2, 0, 0, 1) !important;
content: "";
top: 0;
bottom: 0;
left: 0;
right: 0;
position: absolute;
background: rgba(0, 0, 0, 0);
}
button:not(.m3-fab, .m3-icon-button).filled > .m3.m3-ripple-domain > .m3.ripple {
background: color-mix(in srgb, var(--md-sys-color-on-primary) 12%, transparent);
}
button:not(.m3-fab, .m3-icon-button):is(.outlined, .text, .elevated) > .m3.m3-ripple-domain > .m3.ripple {
background: color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent);
}
button:not(.m3-fab, .m3-icon-button).tonal > .m3.m3-ripple-domain > .m3.ripple {
background: color-mix(in srgb, var(--md-sys-color-on-secondary-container) 12%, transparent);
}
button:not(.m3-fab, .m3-icon-button):active:is(.filled, .tonal) {
box-shadow: none !important;
}
button:not(.m3-fab, .m3-icon-button):active.elevated {
box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.15), 0 1px 2px 0 rgba(0, 0, 0, 0.3) !important;
}
button:not(.m3-fab, .m3-icon-button):active.tonal::before {
background-color: color-mix(in srgb, var(--md-sys-color-on-secondary-container) 12%, transparent);
}
button:not(.m3-fab, .m3-icon-button):focus-visible.outlined {
border-color: var(--md-sys-color-primary) !important;
}
button:not(.m3-fab, .m3-icon-button):focus-visible.filled::before {
background-color: color-mix(in srgb, var(--md-sys-color-on-primary) 12%, transparent);
}
button:not(.m3-fab, .m3-icon-button):focus-visible:is(.outlined, .text, .elevated)::before {
background-color: color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent);
}
button:not(.m3-fab, .m3-icon-button):focus-visible.tonal::before {
background-color: color-mix(in srgb, var(--md-sys-color-on-secondary-container) 12%, transparent);
}
button:not(.m3-fab, .m3-icon-button):hover:is(.filled, .tonal) {
box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.15), 0 1px 2px 0 rgba(0, 0, 0, 0.3);
}
button:not(.m3-fab, .m3-icon-button):hover.elevated {
box-shadow: 0 2px 6px 2px rgba(0, 0, 0, 0.15), 0 1px 2px 0 rgba(0, 0, 0, 0.3);
}
button:not(.m3-fab, .m3-icon-button):hover.filled::before {
background-color: color-mix(in srgb, var(--md-sys-color-on-primary) 8%, transparent);
}
button:not(.m3-fab, .m3-icon-button):hover:is(.outlined, .text, .elevated)::before {
background-color: color-mix(in srgb, var(--md-sys-color-primary) 8%, transparent);
}
button:not(.m3-fab, .m3-icon-button):hover.tonal::before {
background-color: color-mix(in srgb, var(--md-sys-color-on-secondary-container) 8%, transparent);
}
button:not(.m3-fab, .m3-icon-button):disabled {
pointer-events: none;
}
button:not(.m3-fab, .m3-icon-button):disabled:is(.filled, .elevated, .tonal, .outlined, .text) {
color: color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent);
}
button:not(.m3-fab, .m3-icon-button):disabled:is(.filled, .elevated, .tonal) {
background: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent);
}
button:not(.m3-fab, .m3-icon-button):disabled.elevated {
box-shadow: none;
}
button:not(.m3-fab, .m3-icon-button):disabled.outlined {
outline: 1px solid color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent) !important;
}
/*# sourceMappingURL=button.css.map */

View File

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["button.sass","mixins/m3-mixins.sass"],"names":[],"mappings":"AAEA;EACI;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEJ;EACI;;AACA;EACI;EACA;;AAER;EACI;EACA;EACA;EACA;;AAEA;EACI;;AAER;EACI;EACA;EACA;;AAEA;EACI;;AAER;ECNI;EDQA;EACA;;AAEA;EACI;;AAER;EACI;EACA;;AAEA;EACI;;AAER;ECMA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;ADVA;EACI;;AAGA;EACI;;AAER;EACI;;AAGA;EC3CA;;AD8CA;ECxCA;;AD2CA;EACI;;AAGJ;EACI;;AAEJ;EACI;;AAEJ;EACI;;AAEJ;EACI;;AAGJ;EC1DA;;AD6DA;ECvDA;;AD0DA;EACI;;AAEJ;EACI;;AAEJ;EACI;;AAER;EACI;;AAEA;EACI;;AAEJ;EACI;;AAEJ;EACI;;AAEJ;EACI","file":"button.css"}

127
src/styles/button.sass Normal file
View File

@ -0,0 +1,127 @@
@import "mixins/m3-mixins"
button:not(.m3-fab, .m3-icon-button)
transition: background-color, box-shadow, .2s cubic-bezier(0.2, 0, 0, 1) !important
font-family: var(--md-sys-typescale-label-large-font-family-name)
font-size: var(--md-sys-typescale-label-large-font-size)
font-weight: var(--md-sys-typescale-label-large-font-weight)
line-height: var(--md-sys-typescale-label-large-line-height)
box-sizing: border-box
&.m3
contain: content
box-sizing: border-box
border-radius: 100px
display: inline-flex
flex-direction: row
justify-content: center
align-items: center
text-align: center
padding: 10px 24px
border: none
gap: 8px
&.filled
background-color: var(--md-sys-color-primary)
&, & > svg.m3-svg-icon
color: var(--md-sys-color-on-primary)
fill: var(--md-sys-color-on-primary)
&.outlined
outline-offset: -1px
outline: 1px solid var(--md-sys-color-outline) !important
background-color: #00000000
color: var(--md-sys-color-primary)
& > svg.m3-svg-icon
fill: var(--md-sys-color-primary)
&.text
padding: 10px 12px !important
background-color: #00000000
color: var(--md-sys-color-primary)
& > svg.m3-svg-icon
fill: var(--md-sys-color-primary)
&.elevated
@include elevation-1(false)
background-color: var(--md-sys-color-surface-container-low)
color: var(--md-sys-color-primary)
& > svg.m3-svg-icon
fill: var(--md-sys-color-primary)
&.tonal
background-color: var(--md-sys-color-secondary-container)
color: var(--md-sys-color-on-secondary-container)
& > svg.m3-svg-icon
fill: var(--md-sys-color-on-secondary-container)
&::before
@include state-layer
&.filled > .m3.m3-ripple-domain > .m3.ripple
background: color-mix(in srgb, var(--md-sys-color-on-primary) 12%, transparent)
&:is(.outlined, .text, .elevated)
& > .m3.m3-ripple-domain > .m3.ripple
background: color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent)
&.tonal > .m3.m3-ripple-domain > .m3.ripple
background: color-mix(in srgb, var(--md-sys-color-on-secondary-container) 12%, transparent)
&:active
&:is(.filled, .tonal)
@include elevation-0(true)
&.elevated
@include elevation-1(true)
&.tonal::before
background-color: color-mix(in srgb, var(--md-sys-color-on-secondary-container) 12%, transparent)
&:focus-visible
&.outlined
border-color: var(--md-sys-color-primary) !important
&.filled::before
background-color: color-mix(in srgb, var(--md-sys-color-on-primary) 12%, transparent)
&:is(.outlined, .text, .elevated)::before
background-color: color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent)
&.tonal::before
background-color: color-mix(in srgb, var(--md-sys-color-on-secondary-container) 12%, transparent)
&:hover
&:is(.filled, .tonal)
@include elevation-1(false)
&.elevated
@include elevation-2(false)
&.filled::before
background-color: color-mix(in srgb, var(--md-sys-color-on-primary) 8%, transparent)
&:is(.outlined, .text, .elevated)::before
background-color: color-mix(in srgb, var(--md-sys-color-primary) 8%, transparent)
&.tonal::before
background-color: color-mix(in srgb, var(--md-sys-color-on-secondary-container) 8%, transparent)
&:disabled
pointer-events: none
&:is(.filled, .elevated, .tonal, .outlined, .text)
color: color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent)
&:is(.filled, .elevated, .tonal)
background: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent)
&.elevated
box-shadow: none
&.outlined
outline: 1px solid color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent) !important

103
src/styles/checkbox.css Normal file
View File

@ -0,0 +1,103 @@
label.m3.m3-checkbox-label {
display: flex;
position: relative;
align-items: center;
justify-content: center;
aspect-ratio: 1;
}
label.m3.m3-checkbox-label > span.m3.m3-checkbox-state-layer {
position: absolute;
width: 2.5rem;
aspect-ratio: inherit;
border-radius: 50%;
transition: background-color 0.2s cubic-bezier(0.2, 0, 0, 1);
}
span.m3.m3-checkbox-ripple-layer {
z-index: 20;
contain: content;
border-radius: 50%;
position: absolute;
width: 2.5rem;
height: 2.5rem;
}
input[type=checkbox].m3.m3-checkbox {
appearance: none;
display: flex;
align-items: center;
justify-content: center;
box-sizing: content-box;
z-index: 10;
width: 1.125rem;
height: 1.125rem;
margin: 0;
outline-offset: -0.14rem;
border-radius: 0.14rem;
outline: 0.14rem solid var(--md-sys-color-on-surface-variant);
transition: background-color 0.2s cubic-bezier(0.2, 0, 0, 1);
}
input[type=checkbox].m3.m3-checkbox:is(:user-invalid:is(:checked, :indeterminate), .m3.m3-error:is(:checked, :indeterminate)) {
outline-color: var(--md-sys-color-error);
background-color: var(--md-sys-color-error);
}
input[type=checkbox].m3.m3-checkbox:is(.m3.m3-error, :user-invalid) {
outline-color: var(--md-sys-color-error);
}
input[type=checkbox].m3.m3-checkbox:is(:checked:is(:hover, input[type=checkbox].m3.m3-checkbox):not(.m3.m3-error, :disabled), :indeterminate:is(:hover, input[type=checkbox].m3.m3-checkbox):not(.m3.m3-error, :disabled)) {
outline-color: var(--md-sys-color-primary);
background-color: var(--md-sys-color-primary);
}
input[type=checkbox].m3.m3-checkbox:disabled:is(:hover, input[type=checkbox].m3.m3-checkbox:disabled) {
opacity: 38%;
border: 2px solid var(--md-sys-color-on-surface);
}
input[type=checkbox].m3.m3-checkbox:disabled:checked:is(:hover, input[type=checkbox].m3.m3-checkbox:disabled) {
opacity: 38%;
background-color: var(--md-sys-color-on-surface);
}
input[type=checkbox].m3.m3-checkbox::after {
line-height: 1.125rem;
font-family: Material-Symbols-Outlined-Regular, sans-serif;
font-weight: 700;
font-size: 1.125rem;
color: var(--md-sys-color-on-primary);
}
input[type=checkbox].m3.m3-checkbox:checked::after {
content: "done";
}
input[type=checkbox].m3.m3-checkbox:indeterminate::after {
content: "check_indeterminate_small";
}
input[type=checkbox].m3.m3-checkbox:hover {
outline-color: var(--md-sys-color-on-surface);
}
input[type=checkbox].m3.m3-checkbox:not(:disabled):is(:user-invalid:is(:hover, :indeterminate:hover), .m3.m3-error:hover) + span.m3.m3-checkbox-state-layer {
background-color: color-mix(in srgb, var(--md-sys-color-error) 8%, transparent);
}
input[type=checkbox].m3.m3-checkbox:not(:disabled):is(:user-invalid:is(:active, :indeterminate:active), .m3.m3-error:active) + span.m3.m3-checkbox-state-layer {
background-color: color-mix(in srgb, var(--md-sys-color-error) 12%, transparent);
}
input[type=checkbox].m3.m3-checkbox:not(:disabled):is(:user-invalid:is(:active, :indeterminate:active), .m3.m3-error:active) + span.m3.m3-checkbox-state-layer + span.m3-ripple-domain > .m3.ripple {
background-color: color-mix(in srgb, var(--md-sys-color-error) 20%, transparent);
}
input[type=checkbox].m3.m3-checkbox:not(:disabled):is(:checked:hover, :indeterminate:hover) + span.m3.m3-checkbox-state-layer {
background-color: color-mix(in srgb, var(--md-sys-color-primary) 8%, transparent);
}
input[type=checkbox].m3.m3-checkbox:not(:disabled):is(:checked:active, :indeterminate:active) + span.m3.m3-checkbox-state-layer {
background-color: color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent);
}
input[type=checkbox].m3.m3-checkbox:not(:disabled):is(:checked:active, :indeterminate:active) + span.m3.m3-checkbox-state-layer + span.m3-ripple-domain > .m3.ripple {
background-color: color-mix(in srgb, var(--md-sys-color-on-surface) 20%, transparent);
}
input[type=checkbox].m3.m3-checkbox:not(:disabled):hover + span.m3-checkbox-state-layer {
background-color: color-mix(in srgb, var(--md-sys-color-on-surface) 8%, transparent);
}
input[type=checkbox].m3.m3-checkbox:not(:disabled):active + span.m3.m3-checkbox-state-layer {
background-color: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent);
}
input[type=checkbox].m3.m3-checkbox:not(:disabled):active + span.m3.m3-checkbox-state-layer + span.m3-ripple-domain > .m3.ripple {
background-color: color-mix(in srgb, var(--md-sys-color-primary) 20%, transparent);
}
/*# sourceMappingURL=checkbox.css.map */

View File

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["checkbox.sass","mixins/m3-mixins.sass"],"names":[],"mappings":"AAEA;ECDI;EACA;EACA;EACA;EACA;;ADDA;ECIA;EACA;EACA;EACA;EACA;;;ADLJ;EACI;EACA;EACA;EACA;EACA;EACA;;;AAEJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;;AAEJ;EACI;;AAEJ;EACI;EACA;;AAGA;EACI;EACA;;AAEJ;EACI;EACA;;AAER;EACI;EACA;EACA;EACA;EACA;;AAEJ;EACI;;AAEJ;EACI;;AAEJ;EACI;;AAII;EACI;;AAER;EACI;;AACA;EACI;;AAER;EACI;;AAEJ;EACI;;AACA;EACI;;AAGJ;EACI;;AAER;EACI;;AACA;EACI","file":"checkbox.css"}

93
src/styles/checkbox.sass Normal file
View File

@ -0,0 +1,93 @@
@import "mixins/m3-mixins"
label.m3.m3-checkbox-label
@include m3-label-mixin
& > span.m3.m3-checkbox-state-layer
@include m3-state-layer-mixin
span.m3.m3-checkbox-ripple-layer
z-index: 20
contain: content
border-radius: 50%
position: absolute
width: 2.5rem
height: 2.5rem
input[type="checkbox"].m3.m3-checkbox
appearance: none
display: flex
align-items: center
justify-content: center
box-sizing: content-box
z-index: 10
width: 1.125rem
height: 1.125rem
margin: 0
outline-offset: -.14rem
border-radius: .14rem
outline: .14rem solid var(--md-sys-color-on-surface-variant)
transition: background-color .2s cubic-bezier(0.2, 0, 0, 1)
&:is(:user-invalid:is(:checked, :indeterminate), .m3.m3-error:is(:checked, :indeterminate))
outline-color: var(--md-sys-color-error)
background-color: var(--md-sys-color-error)
&:is(.m3.m3-error, :user-invalid)
outline-color: var(--md-sys-color-error)
&:is(:checked:is(:hover, &):not(.m3.m3-error, :disabled), :indeterminate:is(:hover, &):not(.m3.m3-error, :disabled))
outline-color: var(--md-sys-color-primary)
background-color: var(--md-sys-color-primary)
&:disabled
&:is(:hover, &)
opacity: 38%
border: 2px solid var(--md-sys-color-on-surface)
&:checked:is(:hover, &)
opacity: 38%
background-color: var(--md-sys-color-on-surface)
&::after
line-height: 1.125rem
font-family: Material-Symbols-Outlined-Regular, sans-serif
font-weight: 700
font-size: 1.125rem
color: var(--md-sys-color-on-primary)
&:checked::after
content: "done"
&:indeterminate::after
content: "check_indeterminate_small"
&:hover
outline-color: var(--md-sys-color-on-surface)
&:not(:disabled)
&:is(:user-invalid:is(:hover, :indeterminate:hover), .m3.m3-error:hover)
& + span.m3.m3-checkbox-state-layer
background-color: color-mix(in srgb, var(--md-sys-color-error) 8%, transparent)
&:is(:user-invalid:is(:active, :indeterminate:active), .m3.m3-error:active) + span.m3.m3-checkbox-state-layer
background-color: color-mix(in srgb, var(--md-sys-color-error) 12%, transparent)
& + span.m3-ripple-domain > .m3.ripple
background-color: color-mix(in srgb, var(--md-sys-color-error) 20%, transparent)
&:is(:checked:hover, :indeterminate:hover) + span.m3.m3-checkbox-state-layer
background-color: color-mix(in srgb, var(--md-sys-color-primary) 8%, transparent)
&:is(:checked:active, :indeterminate:active) + span.m3.m3-checkbox-state-layer
background-color: color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent)
& + span.m3-ripple-domain > .m3.ripple
background-color: color-mix(in srgb, var(--md-sys-color-on-surface) 20%, transparent)
&:hover
& + span.m3-checkbox-state-layer
background-color: color-mix(in srgb, var(--md-sys-color-on-surface) 8%, transparent)
&:active + span.m3.m3-checkbox-state-layer
background-color: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent)
& + span.m3-ripple-domain > .m3.ripple
background-color: color-mix(in srgb, var(--md-sys-color-primary) 20%, transparent)

View File

@ -0,0 +1,51 @@
.dark-high-contrast {
--md-sys-color-primary: rgb(255 249 251);
--md-sys-color-surface-tint: rgb(227 183 244);
--md-sys-color-on-primary: rgb(0 0 0);
--md-sys-color-primary-container: rgb(231 187 248);
--md-sys-color-on-primary-container: rgb(0 0 0);
--md-sys-color-secondary: rgb(255 249 251);
--md-sys-color-on-secondary: rgb(0 0 0);
--md-sys-color-secondary-container: rgb(216 196 220);
--md-sys-color-on-secondary-container: rgb(0 0 0);
--md-sys-color-tertiary: rgb(255 249 249);
--md-sys-color-on-tertiary: rgb(0 0 0);
--md-sys-color-tertiary-container: rgb(249 187 186);
--md-sys-color-on-tertiary-container: rgb(0 0 0);
--md-sys-color-error: rgb(255 249 249);
--md-sys-color-on-error: rgb(0 0 0);
--md-sys-color-error-container: rgb(255 186 177);
--md-sys-color-on-error-container: rgb(0 0 0);
--md-sys-color-background: rgb(22 18 23);
--md-sys-color-on-background: rgb(233 224 231);
--md-sys-color-surface: rgb(22 18 23);
--md-sys-color-on-surface: rgb(255 255 255);
--md-sys-color-surface-variant: rgb(76 68 77);
--md-sys-color-on-surface-variant: rgb(255 249 251);
--md-sys-color-outline: rgb(210 199 210);
--md-sys-color-outline-variant: rgb(210 199 210);
--md-sys-color-shadow: rgb(0 0 0);
--md-sys-color-scrim: rgb(0 0 0);
--md-sys-color-inverse-surface: rgb(233 224 231);
--md-sys-color-inverse-on-surface: rgb(0 0 0);
--md-sys-color-inverse-primary: rgb(60 27 77);
--md-sys-color-primary-fixed: rgb(248 222 255);
--md-sys-color-on-primary-fixed: rgb(0 0 0);
--md-sys-color-primary-fixed-dim: rgb(231 187 248);
--md-sys-color-on-primary-fixed-variant: rgb(39 5 56);
--md-sys-color-secondary-fixed: rgb(245 224 248);
--md-sys-color-on-secondary-fixed: rgb(0 0 0);
--md-sys-color-secondary-fixed-dim: rgb(216 196 220);
--md-sys-color-on-secondary-fixed-variant: rgb(29 18 34);
--md-sys-color-tertiary-fixed: rgb(255 224 222);
--md-sys-color-on-tertiary-fixed: rgb(0 0 0);
--md-sys-color-tertiary-fixed-dim: rgb(249 187 186);
--md-sys-color-on-tertiary-fixed-variant: rgb(44 11 13);
--md-sys-color-surface-dim: rgb(22 18 23);
--md-sys-color-surface-bright: rgb(61 55 61);
--md-sys-color-surface-container-lowest: rgb(17 13 18);
--md-sys-color-surface-container-low: rgb(30 26 31);
--md-sys-color-surface-container: rgb(35 30 35);
--md-sys-color-surface-container-high: rgb(45 40 46);
--md-sys-color-surface-container-highest: rgb(56 51 57);
}

View File

@ -0,0 +1,51 @@
.dark-medium-contrast {
--md-sys-color-primary: rgb(231 187 248);
--md-sys-color-surface-tint: rgb(227 183 244);
--md-sys-color-on-primary: rgb(39 5 56);
--md-sys-color-primary-container: rgb(170 130 187);
--md-sys-color-on-primary-container: rgb(0 0 0);
--md-sys-color-secondary: rgb(216 196 220);
--md-sys-color-on-secondary: rgb(29 18 34);
--md-sys-color-secondary-container: rgb(156 139 161);
--md-sys-color-on-secondary-container: rgb(0 0 0);
--md-sys-color-tertiary: rgb(249 187 186);
--md-sys-color-on-tertiary: rgb(44 11 13);
--md-sys-color-tertiary-container: rgb(186 131 130);
--md-sys-color-on-tertiary-container: rgb(0 0 0);
--md-sys-color-error: rgb(255 186 177);
--md-sys-color-on-error: rgb(55 0 1);
--md-sys-color-error-container: rgb(255 84 73);
--md-sys-color-on-error-container: rgb(0 0 0);
--md-sys-color-background: rgb(22 18 23);
--md-sys-color-on-background: rgb(233 224 231);
--md-sys-color-surface: rgb(22 18 23);
--md-sys-color-on-surface: rgb(255 249 251);
--md-sys-color-surface-variant: rgb(76 68 77);
--md-sys-color-on-surface-variant: rgb(210 199 210);
--md-sys-color-outline: rgb(170 160 170);
--md-sys-color-outline-variant: rgb(137 128 138);
--md-sys-color-shadow: rgb(0 0 0);
--md-sys-color-scrim: rgb(0 0 0);
--md-sys-color-inverse-surface: rgb(233 224 231);
--md-sys-color-inverse-on-surface: rgb(45 40 46);
--md-sys-color-inverse-primary: rgb(93 58 109);
--md-sys-color-primary-fixed: rgb(246 217 255);
--md-sys-color-on-primary-fixed: rgb(33 0 50);
--md-sys-color-primary-fixed-dim: rgb(227 183 244);
--md-sys-color-on-primary-fixed-variant: rgb(74 40 90);
--md-sys-color-secondary-fixed: rgb(240 220 244);
--md-sys-color-on-secondary-fixed: rgb(24 13 29);
--md-sys-color-secondary-fixed-dim: rgb(212 192 216);
--md-sys-color-on-secondary-fixed-variant: rgb(63 49 68);
--md-sys-color-tertiary-fixed: rgb(255 218 217);
--md-sys-color-on-tertiary-fixed: rgb(37 7 8);
--md-sys-color-tertiary-fixed-dim: rgb(245 183 182);
--md-sys-color-on-tertiary-fixed-variant: rgb(83 43 43);
--md-sys-color-surface-dim: rgb(22 18 23);
--md-sys-color-surface-bright: rgb(61 55 61);
--md-sys-color-surface-container-lowest: rgb(17 13 18);
--md-sys-color-surface-container-low: rgb(30 26 31);
--md-sys-color-surface-container: rgb(35 30 35);
--md-sys-color-surface-container-high: rgb(45 40 46);
--md-sys-color-surface-container-highest: rgb(56 51 57);
}

51
src/styles/css/dark.css Normal file
View File

@ -0,0 +1,51 @@
.dark {
--md-sys-color-primary: rgb(227 183 244);
--md-sys-color-surface-tint: rgb(227 183 244);
--md-sys-color-on-primary: rgb(67 34 84);
--md-sys-color-primary-container: rgb(92 57 108);
--md-sys-color-on-primary-container: rgb(246 217 255);
--md-sys-color-secondary: rgb(212 192 216);
--md-sys-color-on-secondary: rgb(57 44 62);
--md-sys-color-secondary-container: rgb(80 66 85);
--md-sys-color-on-secondary-container: rgb(240 220 244);
--md-sys-color-tertiary: rgb(245 183 182);
--md-sys-color-on-tertiary: rgb(76 37 37);
--md-sys-color-tertiary-container: rgb(102 59 59);
--md-sys-color-on-tertiary-container: rgb(255 218 217);
--md-sys-color-error: rgb(255 180 171);
--md-sys-color-on-error: rgb(105 0 5);
--md-sys-color-error-container: rgb(147 0 10);
--md-sys-color-on-error-container: rgb(255 218 214);
--md-sys-color-background: rgb(22 18 23);
--md-sys-color-on-background: rgb(233 224 231);
--md-sys-color-surface: rgb(22 18 23);
--md-sys-color-on-surface: rgb(233 224 231);
--md-sys-color-surface-variant: rgb(76 68 77);
--md-sys-color-on-surface-variant: rgb(206 195 206);
--md-sys-color-outline: rgb(151 142 151);
--md-sys-color-outline-variant: rgb(76 68 77);
--md-sys-color-shadow: rgb(0 0 0);
--md-sys-color-scrim: rgb(0 0 0);
--md-sys-color-inverse-surface: rgb(233 224 231);
--md-sys-color-inverse-on-surface: rgb(52 47 52);
--md-sys-color-inverse-primary: rgb(117 80 134);
--md-sys-color-primary-fixed: rgb(246 217 255);
--md-sys-color-on-primary-fixed: rgb(45 11 62);
--md-sys-color-primary-fixed-dim: rgb(227 183 244);
--md-sys-color-on-primary-fixed-variant: rgb(92 57 108);
--md-sys-color-secondary-fixed: rgb(240 220 244);
--md-sys-color-on-secondary-fixed: rgb(35 23 40);
--md-sys-color-secondary-fixed-dim: rgb(212 192 216);
--md-sys-color-on-secondary-fixed-variant: rgb(80 66 85);
--md-sys-color-tertiary-fixed: rgb(255 218 217);
--md-sys-color-on-tertiary-fixed: rgb(51 17 18);
--md-sys-color-tertiary-fixed-dim: rgb(245 183 182);
--md-sys-color-on-tertiary-fixed-variant: rgb(102 59 59);
--md-sys-color-surface-dim: rgb(22 18 23);
--md-sys-color-surface-bright: rgb(61 55 61);
--md-sys-color-surface-container-lowest: rgb(17 13 18);
--md-sys-color-surface-container-low: rgb(30 26 31);
--md-sys-color-surface-container: rgb(35 30 35);
--md-sys-color-surface-container-high: rgb(45 40 46);
--md-sys-color-surface-container-highest: rgb(56 51 57);
}

View File

@ -0,0 +1,51 @@
.light-high-contrast {
--md-sys-color-primary: rgb(52 19 69);
--md-sys-color-surface-tint: rgb(117 80 134);
--md-sys-color-on-primary: rgb(255 255 255);
--md-sys-color-primary-container: rgb(87 53 104);
--md-sys-color-on-primary-container: rgb(255 255 255);
--md-sys-color-secondary: rgb(42 30 47);
--md-sys-color-on-secondary: rgb(255 255 255);
--md-sys-color-secondary-container: rgb(76 62 81);
--md-sys-color-on-secondary-container: rgb(255 255 255);
--md-sys-color-tertiary: rgb(59 23 24);
--md-sys-color-on-tertiary: rgb(255 255 255);
--md-sys-color-tertiary-container: rgb(98 55 55);
--md-sys-color-on-tertiary-container: rgb(255 255 255);
--md-sys-color-error: rgb(78 0 2);
--md-sys-color-on-error: rgb(255 255 255);
--md-sys-color-error-container: rgb(140 0 9);
--md-sys-color-on-error-container: rgb(255 255 255);
--md-sys-color-background: rgb(255 247 252);
--md-sys-color-on-background: rgb(30 26 31);
--md-sys-color-surface: rgb(255 247 252);
--md-sys-color-on-surface: rgb(0 0 0);
--md-sys-color-surface-variant: rgb(235 223 234);
--md-sys-color-on-surface-variant: rgb(40 34 42);
--md-sys-color-outline: rgb(72 65 73);
--md-sys-color-outline-variant: rgb(72 65 73);
--md-sys-color-shadow: rgb(0 0 0);
--md-sys-color-scrim: rgb(0 0 0);
--md-sys-color-inverse-surface: rgb(52 47 52);
--md-sys-color-inverse-on-surface: rgb(255 255 255);
--md-sys-color-inverse-primary: rgb(251 229 255);
--md-sys-color-primary-fixed: rgb(87 53 104);
--md-sys-color-on-primary-fixed: rgb(255 255 255);
--md-sys-color-primary-fixed-dim: rgb(63 30 80);
--md-sys-color-on-primary-fixed-variant: rgb(255 255 255);
--md-sys-color-secondary-fixed: rgb(76 62 81);
--md-sys-color-on-secondary-fixed: rgb(255 255 255);
--md-sys-color-secondary-fixed-dim: rgb(53 40 58);
--md-sys-color-on-secondary-fixed-variant: rgb(255 255 255);
--md-sys-color-tertiary-fixed: rgb(98 55 55);
--md-sys-color-on-tertiary-fixed: rgb(255 255 255);
--md-sys-color-tertiary-fixed-dim: rgb(72 33 34);
--md-sys-color-on-tertiary-fixed-variant: rgb(255 255 255);
--md-sys-color-surface-dim: rgb(225 215 223);
--md-sys-color-surface-bright: rgb(255 247 252);
--md-sys-color-surface-container-lowest: rgb(255 255 255);
--md-sys-color-surface-container-low: rgb(251 241 248);
--md-sys-color-surface-container: rgb(245 235 243);
--md-sys-color-surface-container-high: rgb(239 229 237);
--md-sys-color-surface-container-highest: rgb(233 224 231);
}

View File

@ -0,0 +1,51 @@
.light-medium-contrast {
--md-sys-color-primary: rgb(87 53 104);
--md-sys-color-surface-tint: rgb(117 80 134);
--md-sys-color-on-primary: rgb(255 255 255);
--md-sys-color-primary-container: rgb(140 102 157);
--md-sys-color-on-primary-container: rgb(255 255 255);
--md-sys-color-secondary: rgb(76 62 81);
--md-sys-color-on-secondary: rgb(255 255 255);
--md-sys-color-secondary-container: rgb(127 111 132);
--md-sys-color-on-secondary-container: rgb(255 255 255);
--md-sys-color-tertiary: rgb(98 55 55);
--md-sys-color-on-tertiary: rgb(255 255 255);
--md-sys-color-tertiary-container: rgb(154 103 103);
--md-sys-color-on-tertiary-container: rgb(255 255 255);
--md-sys-color-error: rgb(140 0 9);
--md-sys-color-on-error: rgb(255 255 255);
--md-sys-color-error-container: rgb(218 52 46);
--md-sys-color-on-error-container: rgb(255 255 255);
--md-sys-color-background: rgb(255 247 252);
--md-sys-color-on-background: rgb(30 26 31);
--md-sys-color-surface: rgb(255 247 252);
--md-sys-color-on-surface: rgb(30 26 31);
--md-sys-color-surface-variant: rgb(235 223 234);
--md-sys-color-on-surface-variant: rgb(72 65 73);
--md-sys-color-outline: rgb(100 93 101);
--md-sys-color-outline-variant: rgb(129 120 129);
--md-sys-color-shadow: rgb(0 0 0);
--md-sys-color-scrim: rgb(0 0 0);
--md-sys-color-inverse-surface: rgb(52 47 52);
--md-sys-color-inverse-on-surface: rgb(248 238 246);
--md-sys-color-inverse-primary: rgb(227 183 244);
--md-sys-color-primary-fixed: rgb(140 102 157);
--md-sys-color-on-primary-fixed: rgb(255 255 255);
--md-sys-color-primary-fixed-dim: rgb(114 78 131);
--md-sys-color-on-primary-fixed-variant: rgb(255 255 255);
--md-sys-color-secondary-fixed: rgb(127 111 132);
--md-sys-color-on-secondary-fixed: rgb(255 255 255);
--md-sys-color-secondary-fixed-dim: rgb(102 87 107);
--md-sys-color-on-secondary-fixed-variant: rgb(255 255 255);
--md-sys-color-tertiary-fixed: rgb(154 103 103);
--md-sys-color-on-tertiary-fixed: rgb(255 255 255);
--md-sys-color-tertiary-fixed-dim: rgb(127 79 79);
--md-sys-color-on-tertiary-fixed-variant: rgb(255 255 255);
--md-sys-color-surface-dim: rgb(225 215 223);
--md-sys-color-surface-bright: rgb(255 247 252);
--md-sys-color-surface-container-lowest: rgb(255 255 255);
--md-sys-color-surface-container-low: rgb(251 241 248);
--md-sys-color-surface-container: rgb(245 235 243);
--md-sys-color-surface-container-high: rgb(239 229 237);
--md-sys-color-surface-container-highest: rgb(233 224 231);
}

51
src/styles/css/light.css Normal file
View File

@ -0,0 +1,51 @@
.light {
--md-sys-color-primary: rgb(117 80 134);
--md-sys-color-surface-tint: rgb(117 80 134);
--md-sys-color-on-primary: rgb(255 255 255);
--md-sys-color-primary-container: rgb(246 217 255);
--md-sys-color-on-primary-container: rgb(45 11 62);
--md-sys-color-secondary: rgb(104 89 109);
--md-sys-color-on-secondary: rgb(255 255 255);
--md-sys-color-secondary-container: rgb(240 220 244);
--md-sys-color-on-secondary-container: rgb(35 23 40);
--md-sys-color-tertiary: rgb(129 82 81);
--md-sys-color-on-tertiary: rgb(255 255 255);
--md-sys-color-tertiary-container: rgb(255 218 217);
--md-sys-color-on-tertiary-container: rgb(51 17 18);
--md-sys-color-error: rgb(186 26 26);
--md-sys-color-on-error: rgb(255 255 255);
--md-sys-color-error-container: rgb(255 218 214);
--md-sys-color-on-error-container: rgb(65 0 2);
--md-sys-color-background: rgb(255 247 252);
--md-sys-color-on-background: rgb(30 26 31);
--md-sys-color-surface: rgb(255 247 252);
--md-sys-color-on-surface: rgb(30 26 31);
--md-sys-color-surface-variant: rgb(235 223 234);
--md-sys-color-on-surface-variant: rgb(76 68 77);
--md-sys-color-outline: rgb(125 116 126);
--md-sys-color-outline-variant: rgb(206 195 206);
--md-sys-color-shadow: rgb(0 0 0);
--md-sys-color-scrim: rgb(0 0 0);
--md-sys-color-inverse-surface: rgb(52 47 52);
--md-sys-color-inverse-on-surface: rgb(248 238 246);
--md-sys-color-inverse-primary: rgb(227 183 244);
--md-sys-color-primary-fixed: rgb(246 217 255);
--md-sys-color-on-primary-fixed: rgb(45 11 62);
--md-sys-color-primary-fixed-dim: rgb(227 183 244);
--md-sys-color-on-primary-fixed-variant: rgb(92 57 108);
--md-sys-color-secondary-fixed: rgb(240 220 244);
--md-sys-color-on-secondary-fixed: rgb(35 23 40);
--md-sys-color-secondary-fixed-dim: rgb(212 192 216);
--md-sys-color-on-secondary-fixed-variant: rgb(80 66 85);
--md-sys-color-tertiary-fixed: rgb(255 218 217);
--md-sys-color-on-tertiary-fixed: rgb(51 17 18);
--md-sys-color-tertiary-fixed-dim: rgb(245 183 182);
--md-sys-color-on-tertiary-fixed-variant: rgb(102 59 59);
--md-sys-color-surface-dim: rgb(225 215 223);
--md-sys-color-surface-bright: rgb(255 247 252);
--md-sys-color-surface-container-lowest: rgb(255 255 255);
--md-sys-color-surface-container-low: rgb(251 241 248);
--md-sys-color-surface-container: rgb(245 235 243);
--md-sys-color-surface-container-high: rgb(239 229 237);
--md-sys-color-surface-container-highest: rgb(233 224 231);
}

33
src/styles/divider.css Normal file
View File

@ -0,0 +1,33 @@
hr.m3.m3-divider {
display: flex;
align-items: end;
box-sizing: border-box;
border: none;
outline: 0.5px solid var(--md-sys-color-outline-variant);
margin: 4px;
}
hr.m3.m3-divider.vertical {
writing-mode: tb-rl;
}
hr.m3.m3-divider.vertical, hr.m3.m3-divider.vertical.full-width {
height: 100%;
}
hr.m3.m3-divider.vertical.inset {
align-self: end;
height: calc(100% - 16px);
}
hr.m3.m3-divider.vertical.middle-inset {
height: calc(100% - 32px);
}
hr.m3.m3-divider.horizontal, hr.m3.m3-divider.horizontal.full-width {
width: 100%;
}
hr.m3.m3-divider.horizontal.inset {
align-self: end;
width: calc(100% - 16px);
}
hr.m3.m3-divider.horizontal.middle-inset {
width: calc(100% - 32px);
}
/*# sourceMappingURL=divider.css.map */

View File

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["divider.sass"],"names":[],"mappings":"AAAA;EACI;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;;AACA;EACI;;AACJ;EACI;EACA;;AACJ;EACI;;AAGJ;EACI;;AACJ;EACI;EACA;;AACJ;EACI","file":"divider.css"}

26
src/styles/divider.sass Normal file
View File

@ -0,0 +1,26 @@
hr.m3.m3-divider
display: flex
align-items: end
box-sizing: border-box
border: none
outline: 0.5px solid var(--md-sys-color-outline-variant)
margin: 4px
&.vertical
writing-mode: tb-rl
&, &.full-width
height: 100%
&.inset
align-self: end
height: calc(100% - 16px)
&.middle-inset
height: calc(100% - (2 * 16px))
&.horizontal
&, &.full-width
width: 100%
&.inset
align-self: end
width: calc(100% - 16px)
&.middle-inset
width: calc(100% - (2 * 16px))

21
src/styles/elevation.css Normal file
View File

@ -0,0 +1,21 @@
.elevation-1 {
box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.15), 0 1px 2px 0 rgba(0, 0, 0, 0.3);
}
.elevation-2 {
box-shadow: 0 2px 6px 2px rgba(0, 0, 0, 0.15), 0 1px 2px 0 rgba(0, 0, 0, 0.3);
}
.elevation-3 {
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), 0 4px 8px 3px rgba(0, 0, 0, 0.15);
}
.elevation-4 {
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.3), 0 6px 10px 4px rgba(0, 0, 0, 0.15);
}
.elevation-5 {
box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.3), 0 8px 12px 6px rgba(0, 0, 0, 0.15);
}
/*# sourceMappingURL=elevation.css.map */

View File

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["elevation.sass"],"names":[],"mappings":"AAAA;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE;;;AAEF;EACE","file":"elevation.css"}

14
src/styles/elevation.sass Normal file
View File

@ -0,0 +1,14 @@
.elevation-1
box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.15), 0 1px 2px 0 rgba(0, 0, 0, 0.30)
.elevation-2
box-shadow: 0 2px 6px 2px rgba(0, 0, 0, 0.15), 0 1px 2px 0 rgba(0, 0, 0, 0.30)
.elevation-3
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.30), 0 4px 8px 3px rgba(0, 0, 0, 0.15)
.elevation-4
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.30), 0 6px 10px 4px rgba(0, 0, 0, 0.15)
.elevation-5
box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.30), 0 8px 12px 6px rgba(0, 0, 0, 0.15)

139
src/styles/fabs.css Normal file
View File

@ -0,0 +1,139 @@
button.m3.m3-fab {
transition: background-color, box-shadow, 0.2s cubic-bezier(0.2, 0, 0, 1) !important;
}
button.m3.m3-fab > span.m3-icon {
font-family: Material-Symbols-Outlined-Regular, sans-serif;
}
button.m3.m3-fab.m3 {
contain: content;
box-sizing: border-box;
display: inline-flex;
flex-direction: row;
justify-content: center;
align-items: center;
text-align: center;
border: none;
gap: 12px;
}
button.m3.m3-fab::before {
transition: background-color, box-shadow, 0.2s cubic-bezier(0.2, 0, 0, 1) !important;
content: "";
top: 0;
bottom: 0;
left: 0;
right: 0;
position: absolute;
background: rgba(0, 0, 0, 0);
}
button.m3.m3-fab.surface {
background-color: var(--md-sys-color-surface-container-high);
color: var(--md-sys-color-primary);
}
button.m3.m3-fab.surface:not(.without-elevation) {
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), 0 4px 8px 3px rgba(0, 0, 0, 0.15);
}
button.m3.m3-fab.surface > svg.m3-svg-icon {
fill: var(--md-sys-color-primary);
}
button.m3.m3-fab.surface > .m3.m3-ripple-domain > .m3.ripple {
background: color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent);
}
button.m3.m3-fab.primary {
background-color: var(--md-sys-color-primary-container);
color: var(--md-sys-color-on-primary-container);
}
button.m3.m3-fab.primary:not(.without-elevation) {
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), 0 4px 8px 3px rgba(0, 0, 0, 0.15);
}
button.m3.m3-fab.primary > svg.m3-svg-icon {
fill: var(--md-sys-color-on-primary-container);
}
button.m3.m3-fab.primary > .m3.m3-ripple-domain > .m3.ripple {
background: color-mix(in srgb, var(--md-sys-color-on-primary-container) 12%, transparent);
}
button.m3.m3-fab.secondary {
background-color: var(--md-sys-color-secondary-container);
color: var(--md-sys-color-on-secondary-container);
}
button.m3.m3-fab.secondary:not(.without-elevation) {
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), 0 4px 8px 3px rgba(0, 0, 0, 0.15);
}
button.m3.m3-fab.secondary > svg.m3-svg-icon {
fill: var(--md-sys-color-on-secondary-container);
}
button.m3.m3-fab.secondary > .m3.m3-ripple-domain > .m3.ripple {
background: color-mix(in srgb, var(--md-sys-color-on-secondary-container) 12%, transparent);
}
button.m3.m3-fab.tertiary {
background-color: var(--md-sys-color-tertiary-container);
color: var(--md-sys-color-on-tertiary-container);
}
button.m3.m3-fab.tertiary:not(.without-elevation) {
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), 0 4px 8px 3px rgba(0, 0, 0, 0.15);
}
button.m3.m3-fab.tertiary > svg.m3-svg-icon {
fill: var(--md-sys-color-on-tertiary-container);
}
button.m3.m3-fab.tertiary > .m3.m3-ripple-domain > .m3.ripple {
background: color-mix(in srgb, var(--md-sys-color-on-tertiary-container) 12%, transparent);
}
button.m3.m3-fab.m3-small-fab {
width: 40px;
height: 40px;
border-radius: 12px;
padding: 11px;
font-size: 24px;
}
button.m3.m3-fab.m3-default-fab {
width: 56px;
height: 56px;
border-radius: 16px;
padding: 19px;
font-size: 24px;
}
button.m3.m3-fab.m3-large-fab {
width: 96px;
height: 96px;
border-radius: 28px;
padding: 34.5px;
font-size: 36px;
}
button.m3.m3-fab.m3-extended-fab {
width: auto;
height: 56px;
border-radius: 16px;
padding: 19px;
font-size: 24px;
}
button.m3.m3-fab:not(.without-elevation):is(.surface, .primary, .secondary, .tertiary):hover {
box-shadow: 0 2px 3px 0 rgba(0, 0, 0, 0.3), 0 6px 10px 4px rgba(0, 0, 0, 0.15);
}
button.m3.m3-fab:not(.without-elevation):is(.surface, .primary, .secondary, .tertiary):active {
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.3), 0 4px 8px 3px rgba(0, 0, 0, 0.15) !important;
}
button.m3.m3-fab:hover.surface::before {
background-color: color-mix(in srgb, var(--md-sys-color-primary) 8%, transparent);
}
button.m3.m3-fab:hover.primary::before {
background-color: color-mix(in srgb, var(--md-sys-color-on-primary-container) 8%, transparent);
}
button.m3.m3-fab:hover.secondary::before {
background-color: color-mix(in srgb, var(--md-sys-color-on-secondary-container) 8%, transparent);
}
button.m3.m3-fab:hover.tertiary::before {
background-color: color-mix(in srgb, var(--md-sys-color-on-tertiary-container) 8%, transparent);
}
button.m3.m3-fab:focus-visible.surface::before {
background-color: color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent);
}
button.m3.m3-fab:focus-visible.primary::before {
background-color: color-mix(in srgb, var(--md-sys-color-on-primary-container) 12%, transparent);
}
button.m3.m3-fab:focus-visible.secondary::before {
background-color: color-mix(in srgb, var(--md-sys-color-on-secondary-container) 12%, transparent);
}
button.m3.m3-fab:focus-visible.tertiary::before {
background-color: color-mix(in srgb, var(--md-sys-color-on-tertiary-container) 12%, transparent);
}
/*# sourceMappingURL=fabs.css.map */

1
src/styles/fabs.css.map Normal file
View File

@ -0,0 +1 @@
{"version":3,"sourceRoot":"","sources":["fabs.sass","mixins/m3-mixins.sass"],"names":[],"mappings":"AAEA;EACI;;AAEA;EACI;;AAEJ;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEJ;ECgDA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;ADpDA;ECCA;EACA;;AAHA;EA+BI;;AA3BJ;EACI;;AACJ;EACI;;ADHJ;ECFA;EACA;;AAHA;EA+BI;;AA3BJ;EACI;;AACJ;EACI;;ADAJ;ECLA;EACA;;AAHA;EA+BI;;AA3BJ;EACI;;AACJ;EACI;;ADGJ;ECRA;EACA;;AAHA;EA+BI;;AA3BJ;EACI;;AACJ;EACI;;ADMJ;ECnBA,ODoBkC;ECnBlC,QDmBwC;EClBxC,eDkB4B;ECjB5B,SDiB8C;EAC1C;;AAEJ;ECvBA,ODwBkC;ECvBlC,QDuBwC;ECtBxC,eDsB4B;ECrB5B,SDqB8C;EAC1C;;AAEJ;EC3BA,OD4BkC;EC3BlC,QD2BwC;EC1BxC,eD0B4B;ECzB5B,SDyB8C;EAC1C;;AAEJ;EC/BA,ODgCkC;EC/BlC,QD+BwC;EC9BxC,eD8B4B;EC7B5B,SD6B8C;EAC1C;;AAEJ;ECQI;;ADLJ;ECHI;;ADOA;EACI;;AAEJ;EACI;;AAEJ;EACI;;AAEJ;EACI;;AAGJ;EACI;;AAEJ;EACI;;AAEJ;EACI;;AAEJ;EACI","file":"fabs.css"}

81
src/styles/fabs.sass Normal file
View File

@ -0,0 +1,81 @@
@import "mixins/m3-mixins"
button.m3.m3-fab
transition: background-color, box-shadow, .2s cubic-bezier(0.2, 0, 0, 1) !important
& > span.m3-icon
font-family: Material-Symbols-Outlined-Regular, sans-serif
&.m3
contain: content
box-sizing: border-box
display: inline-flex
flex-direction: row
justify-content: center
align-items: center
text-align: center
border: none
gap: 12px
&::before
@include state-layer
&.surface
@include m3-fab-colors-palette(--md-sys-color-surface-container-high, --md-sys-color-primary)
&.primary
@include m3-fab-colors-palette(--md-sys-color-primary-container, --md-sys-color-on-primary-container)
&.secondary
@include m3-fab-colors-palette(--md-sys-color-secondary-container, --md-sys-color-on-secondary-container)
&.tertiary
@include m3-fab-colors-palette(--md-sys-color-tertiary-container, --md-sys-color-on-tertiary-container)
&.m3-small-fab
@include m3-fab-default(12px, 40px, 40px, 11px)
font-size: 24px
&.m3-default-fab
@include m3-fab-default(16px, 56px, 56px, 19px)
font-size: 24px
&.m3-large-fab
@include m3-fab-default(28px, 96px, 96px, 34.5px)
font-size: 36px
&.m3-extended-fab
@include m3-fab-default(16px, auto, 56px, 19px)
font-size: 24px
&:not(.without-elevation):is(.surface, .primary, .secondary, .tertiary):hover
@include elevation-4(false)
&:not(.without-elevation):is(.surface, .primary, .secondary, .tertiary):active
@include elevation-3(true)
&:hover
&.surface::before
background-color: color-mix(in srgb, var(--md-sys-color-primary) 8%, transparent)
&.primary::before
background-color: color-mix(in srgb, var(--md-sys-color-on-primary-container) 8%, transparent)
&.secondary::before
background-color: color-mix(in srgb, var(--md-sys-color-on-secondary-container) 8%, transparent)
&.tertiary::before
background-color: color-mix(in srgb, var(--md-sys-color-on-tertiary-container) 8%, transparent)
&:focus-visible
&.surface::before
background-color: color-mix(in srgb, var(--md-sys-color-primary) 12%, transparent)
&.primary::before
background-color: color-mix(in srgb, var(--md-sys-color-on-primary-container) 12%, transparent)
&.secondary::before
background-color: color-mix(in srgb, var(--md-sys-color-on-secondary-container) 12%, transparent)
&.tertiary::before
background-color: color-mix(in srgb, var(--md-sys-color-on-tertiary-container) 12%, transparent)

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More