storybook
This commit is contained in:
parent
7c614c66d9
commit
33a81d8ee7
32
.storybook/main.ts
Normal file
32
.storybook/main.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import type { FrameworkOptions, StorybookConfig } from 'storybook-solidjs-vite'
|
||||||
|
|
||||||
|
const config: StorybookConfig = {
|
||||||
|
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
|
||||||
|
addons: [
|
||||||
|
'@storybook/addon-links',
|
||||||
|
'@storybook/addon-essentials',
|
||||||
|
'@storybook/addon-interactions',
|
||||||
|
'@storybook/addon-a11y',
|
||||||
|
'@storybook/addon-themes'
|
||||||
|
],
|
||||||
|
framework: {
|
||||||
|
name: 'storybook-solidjs-vite',
|
||||||
|
options: {
|
||||||
|
builder: {
|
||||||
|
viteConfigPath: './app.config.ts'
|
||||||
|
}
|
||||||
|
} as FrameworkOptions
|
||||||
|
},
|
||||||
|
docs: {
|
||||||
|
autodocs: 'tag'
|
||||||
|
},
|
||||||
|
previewHead: (head) => `
|
||||||
|
${head}
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
transition: none !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
export default config
|
34
.storybook/preview.ts
Normal file
34
.storybook/preview.ts
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import { withThemeByClassName } from '@storybook/addon-themes'
|
||||||
|
import '../src/styles/_imports.scss'
|
||||||
|
|
||||||
|
const preview = {
|
||||||
|
parameters: {
|
||||||
|
themes: {
|
||||||
|
default: 'light',
|
||||||
|
list: [
|
||||||
|
{ name: 'light', class: '', color: '#f8fafc' },
|
||||||
|
{ name: 'dark', class: 'dark', color: '#0f172a' }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
actions: { argTypesRegex: '^on[A-Z].*' },
|
||||||
|
controls: {
|
||||||
|
matchers: {
|
||||||
|
color: /(background|color)$/i,
|
||||||
|
date: /Date$/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default preview
|
||||||
|
|
||||||
|
export const decorators = [
|
||||||
|
withThemeByClassName({
|
||||||
|
themes: {
|
||||||
|
light: '',
|
||||||
|
dark: 'dark'
|
||||||
|
},
|
||||||
|
defaultTheme: 'light',
|
||||||
|
parentSelector: 'body'
|
||||||
|
})
|
||||||
|
]
|
22
.storybook/test-runner.ts
Normal file
22
.storybook/test-runner.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import type { TestRunnerConfig } from '@storybook/test-runner'
|
||||||
|
import { checkA11y, injectAxe } from 'axe-playwright'
|
||||||
|
|
||||||
|
/*
|
||||||
|
* See https://storybook.js.org/docs/react/writing-tests/test-runner#test-hook-api-experimental
|
||||||
|
* to learn more about the test-runner hooks API.
|
||||||
|
*/
|
||||||
|
const a11yConfig: TestRunnerConfig = {
|
||||||
|
async preRender(page) {
|
||||||
|
await injectAxe(page)
|
||||||
|
},
|
||||||
|
async postRender(page) {
|
||||||
|
await checkA11y(page, '#storybook-root', {
|
||||||
|
detailedReport: true,
|
||||||
|
detailedReportOptions: {
|
||||||
|
html: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = a11yConfig
|
|
@ -36,7 +36,8 @@ export default defineConfig({
|
||||||
devOverlay: true,
|
devOverlay: true,
|
||||||
build: {
|
build: {
|
||||||
chunkSizeWarningLimit: 1024,
|
chunkSizeWarningLimit: 1024,
|
||||||
target: 'esnext'
|
target: 'esnext',
|
||||||
|
sourcemap: true
|
||||||
},
|
},
|
||||||
vite: {
|
vite: {
|
||||||
envPrefix: 'PUBLIC_',
|
envPrefix: 'PUBLIC_',
|
||||||
|
|
38
package.json
38
package.json
|
@ -15,7 +15,10 @@
|
||||||
"fix": "npx @biomejs/biome check . --fix && stylelint **/*.{scss,css} --fix",
|
"fix": "npx @biomejs/biome check . --fix && stylelint **/*.{scss,css} --fix",
|
||||||
"format": "npx @biomejs/biome format src/. --write",
|
"format": "npx @biomejs/biome format src/. --write",
|
||||||
"postinstall": "npm run codegen && npx patch-package",
|
"postinstall": "npm run codegen && npx patch-package",
|
||||||
"typecheck": "tsc --noEmit"
|
"typecheck": "tsc --noEmit",
|
||||||
|
"storybook": "storybook dev -p 6006",
|
||||||
|
"storybook:test": "test-storybook",
|
||||||
|
"build-storybook": "storybook build"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@authorizerdev/authorizer-js": "^2.0.3",
|
"@authorizerdev/authorizer-js": "^2.0.3",
|
||||||
|
@ -37,6 +40,19 @@
|
||||||
"@solidjs/meta": "^0.29.4",
|
"@solidjs/meta": "^0.29.4",
|
||||||
"@solidjs/router": "^0.14.3",
|
"@solidjs/router": "^0.14.3",
|
||||||
"@solidjs/start": "^1.0.6",
|
"@solidjs/start": "^1.0.6",
|
||||||
|
"@storybook/addon-a11y": "^8.2.9",
|
||||||
|
"@storybook/addon-actions": "^8.2.9",
|
||||||
|
"@storybook/addon-controls": "^8.2.9",
|
||||||
|
"@storybook/addon-essentials": "^8.2.9",
|
||||||
|
"@storybook/addon-interactions": "^8.2.9",
|
||||||
|
"@storybook/addon-links": "^8.2.9",
|
||||||
|
"@storybook/addon-themes": "^8.2.9",
|
||||||
|
"@storybook/addon-viewport": "^8.2.9",
|
||||||
|
"@storybook/blocks": "^8.2.9",
|
||||||
|
"@storybook/html": "^8.2.9",
|
||||||
|
"@storybook/react": "^8.2.9",
|
||||||
|
"@storybook/test-runner": "^0.19.1",
|
||||||
|
"@storybook/testing-library": "^0.2.2",
|
||||||
"@tiptap/core": "^2.6.6",
|
"@tiptap/core": "^2.6.6",
|
||||||
"@tiptap/extension-blockquote": "^2.6.6",
|
"@tiptap/extension-blockquote": "^2.6.6",
|
||||||
"@tiptap/extension-bold": "^2.6.6",
|
"@tiptap/extension-bold": "^2.6.6",
|
||||||
|
@ -68,9 +84,10 @@
|
||||||
"@tiptap/extension-youtube": "^2.6.6",
|
"@tiptap/extension-youtube": "^2.6.6",
|
||||||
"@types/cookie": "^0.6.0",
|
"@types/cookie": "^0.6.0",
|
||||||
"@types/cookie-signature": "^1.1.2",
|
"@types/cookie-signature": "^1.1.2",
|
||||||
"@types/node": "^22.5.0",
|
"@types/node": "^22.5.2",
|
||||||
"@types/throttle-debounce": "^5.0.2",
|
"@types/throttle-debounce": "^5.0.2",
|
||||||
"@urql/core": "^5.0.6",
|
"@urql/core": "^5.0.6",
|
||||||
|
"axe-playwright": "^2.0.2",
|
||||||
"bootstrap": "^5.3.3",
|
"bootstrap": "^5.3.3",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cookie": "^0.6.0",
|
"cookie": "^0.6.0",
|
||||||
|
@ -83,29 +100,32 @@
|
||||||
"i18next-http-backend": "^2.6.1",
|
"i18next-http-backend": "^2.6.1",
|
||||||
"i18next-icu": "^2.3.0",
|
"i18next-icu": "^2.3.0",
|
||||||
"intl-messageformat": "^10.5.14",
|
"intl-messageformat": "^10.5.14",
|
||||||
"javascript-time-ago": "^2.5.10",
|
"javascript-time-ago": "^2.5.11",
|
||||||
"patch-package": "^8.0.0",
|
"patch-package": "^8.0.0",
|
||||||
"prosemirror-history": "^1.4.1",
|
"prosemirror-history": "^1.4.1",
|
||||||
"prosemirror-trailing-node": "^2.0.9",
|
"prosemirror-trailing-node": "^2.0.9",
|
||||||
"prosemirror-view": "^1.34.0",
|
"prosemirror-view": "^1.34.1",
|
||||||
"rollup-plugin-visualizer": "^5.12.0",
|
"rollup-plugin-visualizer": "^5.12.0",
|
||||||
"sass": "1.76.0",
|
"sass": "1.76.0",
|
||||||
"solid-js": "^1.8.21",
|
"solid-js": "^1.8.22",
|
||||||
"solid-popper": "^0.3.0",
|
"solid-popper": "^0.3.0",
|
||||||
"solid-tiptap": "0.7.0",
|
"solid-tiptap": "0.7.0",
|
||||||
"solid-transition-group": "^0.2.3",
|
"solid-transition-group": "^0.2.3",
|
||||||
"stylelint": "^16.8.2",
|
"storybook": "^8.2.9",
|
||||||
|
"storybook-solidjs": "^1.0.0-beta.2",
|
||||||
|
"storybook-solidjs-vite": "^1.0.0-beta.2",
|
||||||
|
"stylelint": "^16.9.0",
|
||||||
"stylelint-config-recommended": "^14.0.1",
|
"stylelint-config-recommended": "^14.0.1",
|
||||||
"stylelint-config-standard-scss": "^13.1.0",
|
"stylelint-config-standard-scss": "^13.1.0",
|
||||||
"stylelint-order": "^6.0.4",
|
"stylelint-order": "^6.0.4",
|
||||||
"stylelint-scss": "^6.5.0",
|
"stylelint-scss": "^6.5.1",
|
||||||
"swiper": "^11.1.10",
|
"swiper": "^11.1.12",
|
||||||
"throttle-debounce": "^5.0.2",
|
"throttle-debounce": "^5.0.2",
|
||||||
"tslib": "^2.7.0",
|
"tslib": "^2.7.0",
|
||||||
"typescript": "^5.5.4",
|
"typescript": "^5.5.4",
|
||||||
"typograf": "^7.4.1",
|
"typograf": "^7.4.1",
|
||||||
"uniqolor": "^1.1.1",
|
"uniqolor": "^1.1.1",
|
||||||
"vinxi": "^0.4.1",
|
"vinxi": "^0.4.2",
|
||||||
"vite-plugin-mkcert": "^1.17.6",
|
"vite-plugin-mkcert": "^1.17.6",
|
||||||
"vite-plugin-node-polyfills": "^0.22.0",
|
"vite-plugin-node-polyfills": "^0.22.0",
|
||||||
"vite-plugin-sass-dts": "^1.3.25",
|
"vite-plugin-sass-dts": "^1.3.25",
|
||||||
|
|
195
src/components/atoms/Button/Button.module.scss
Normal file
195
src/components/atoms/Button/Button.module.scss
Normal file
|
@ -0,0 +1,195 @@
|
||||||
|
.button {
|
||||||
|
border-radius: 2px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&.primary {
|
||||||
|
background: var(--background-color-invert);
|
||||||
|
color: var(--default-color-invert);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
color: #9fa1a7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.secondary {
|
||||||
|
border: 1px solid #f7f7f7;
|
||||||
|
background: #f7f7f7;
|
||||||
|
color: #141414;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #000;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.danger {
|
||||||
|
border: 3px solid var(--danger-color);
|
||||||
|
background: var(--background-color);
|
||||||
|
color: var(--danger-color);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--danger-color);
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.inline {
|
||||||
|
font-weight: 700;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 21px;
|
||||||
|
color: #696969;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:active {
|
||||||
|
text-decoration: underline;
|
||||||
|
color: #141414;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.light {
|
||||||
|
font-weight: inherit;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.outline,
|
||||||
|
&.bordered {
|
||||||
|
border: 3px solid #f2f2f2;
|
||||||
|
border-radius: 1.2em;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: 0.8em;
|
||||||
|
min-width: auto !important;
|
||||||
|
padding: 0;
|
||||||
|
transition:
|
||||||
|
border-color 0.3s,
|
||||||
|
background-color 0.3s,
|
||||||
|
color 0.3s;
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:active {
|
||||||
|
background: var(--link-color);
|
||||||
|
border-color: var(--link-color);
|
||||||
|
color: var(--link-hover-color);
|
||||||
|
|
||||||
|
:global(.icon) {
|
||||||
|
filter: var(--icon-filter-hover);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.icon) {
|
||||||
|
margin: 0 -0.5em;
|
||||||
|
filter: var(--icon-filter);
|
||||||
|
transition: filter 0.3s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.bordered {
|
||||||
|
border-radius: 2px;
|
||||||
|
border: 2px solid #000;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:disabled,
|
||||||
|
&:disabled:hover {
|
||||||
|
cursor: default;
|
||||||
|
color: #9fa1a7;
|
||||||
|
background: #f6f6f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.loading,
|
||||||
|
&.loading:hover {
|
||||||
|
background: #f6f6f6;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.L {
|
||||||
|
height: 56px;
|
||||||
|
min-width: 80px;
|
||||||
|
font-size: 20px;
|
||||||
|
padding: 16px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.M {
|
||||||
|
height: 40px;
|
||||||
|
min-width: 64px;
|
||||||
|
font-size: 17px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.S {
|
||||||
|
height: 32px;
|
||||||
|
min-width: 53px;
|
||||||
|
font-size: 15px;
|
||||||
|
padding: 1rem 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.subscribeButton {
|
||||||
|
aspect-ratio: auto;
|
||||||
|
background-color: #000;
|
||||||
|
border: 2px solid #000;
|
||||||
|
border-radius: 0.8rem;
|
||||||
|
color: #fff;
|
||||||
|
float: none;
|
||||||
|
padding-bottom: 0.6rem;
|
||||||
|
padding-top: 0.6rem;
|
||||||
|
width: 9em;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
img {
|
||||||
|
filter: invert(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
|
||||||
|
.icon img {
|
||||||
|
filter: invert(0) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonSubscribeLabel {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonSubscribeLabelHovered {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.buttonSubscribeLabelHovered {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
vertical-align: text-top;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.followed {
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
|
||||||
|
.icon img {
|
||||||
|
filter: invert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: #000;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
.icon img {
|
||||||
|
filter: invert(1) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
src/components/atoms/Button/Button.stories.tsx
Normal file
15
src/components/atoms/Button/Button.stories.tsx
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// src/components/atoms/Button/Button.stories.tsx
|
||||||
|
import type { Meta } from '@storybook/html'
|
||||||
|
import { Button } from './Button'
|
||||||
|
|
||||||
|
// Примените корректную типизацию для Storybook
|
||||||
|
const meta: Meta<typeof Button> = {
|
||||||
|
title: 'Atoms/Button',
|
||||||
|
argTypes: {
|
||||||
|
label: { control: 'text' },
|
||||||
|
primary: { control: 'boolean' },
|
||||||
|
onClick: { action: 'clicked' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default meta
|
50
src/components/atoms/Button/Button.tsx
Normal file
50
src/components/atoms/Button/Button.tsx
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import type { JSX } from 'solid-js'
|
||||||
|
|
||||||
|
import { clsx } from 'clsx'
|
||||||
|
|
||||||
|
import styles from './Button.module.scss'
|
||||||
|
|
||||||
|
export type ButtonVariant = 'primary' | 'secondary' | 'bordered' | 'inline' | 'light' | 'outline' | 'danger'
|
||||||
|
type Props = {
|
||||||
|
title?: string
|
||||||
|
value: string | JSX.Element
|
||||||
|
size?: 'S' | 'M' | 'L'
|
||||||
|
variant?: ButtonVariant
|
||||||
|
type?: 'submit' | 'button'
|
||||||
|
loading?: boolean
|
||||||
|
disabled?: boolean
|
||||||
|
onClick?: (event?: MouseEvent) => void
|
||||||
|
class?: string
|
||||||
|
ref?: HTMLButtonElement | ((el: HTMLButtonElement) => void)
|
||||||
|
isSubscribeButton?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Button = (props: Props) => {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
ref={(el) => {
|
||||||
|
if (typeof props.ref === 'function') {
|
||||||
|
props.ref(el)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
props.ref = el
|
||||||
|
}}
|
||||||
|
title={props.title || (typeof props.value === 'string' ? props.value : '')}
|
||||||
|
onClick={props.onClick}
|
||||||
|
type={props.type ?? 'button'}
|
||||||
|
disabled={props.loading || props.disabled}
|
||||||
|
class={clsx(
|
||||||
|
styles.button,
|
||||||
|
styles[props.size ?? 'M'],
|
||||||
|
styles[props.variant ?? 'primary'],
|
||||||
|
{
|
||||||
|
[styles.loading]: props.loading,
|
||||||
|
[styles.subscribeButton]: props.isSubscribeButton
|
||||||
|
},
|
||||||
|
props.class
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{props.value}
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
}
|
1
src/components/atoms/Button/index.ts
Normal file
1
src/components/atoms/Button/index.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export { Button } from './Button'
|
Loading…
Reference in New Issue
Block a user