Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add vkui-nextra-theme #7067

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/pull_request_packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ jobs:
- name: Run Stylelint
run: yarn run lint:style

- name: Run build VKUI
run: yarn run build:vkui

- name: Run types checking
run: yarn run lint:types

Expand Down
6 changes: 6 additions & 0 deletions packages/vkui-nextra-theme/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"root": false,
"rules": {
"react/react-in-jsx-scope": "off"
}
}
73 changes: 73 additions & 0 deletions packages/vkui-nextra-theme/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Компоненты для документации

В данном пакете содержатся компоненты для документации

```sh
yarn add -D next nextra @vkontakte/vkui-nextra-theme
```

## Nextra

### Настройка Next.js

В конфигурации Next.js требуется подключить nextra и настроить транспиляцию
пакетов

**next.config.js**

```js
const isProd = process.env.NODE_ENV === 'production';

// Префикс для правильной работы на GitHub Pages
const assetPrefix = '/icons';

const withNextra = require('nextra')({
theme: '@vkontakte/vkui-nextra-theme',
themeConfig: './theme.config.tsx',
});

module.exports = withNextra({
transpilePackages: ['@vkontakte/vkui', '@vkontakte/vkui-nextra-theme'],

modularizeImports: {
'@vkontakte/vkui': {
transform: '@vkontakte/vkui/dist/cssm',
skipDefaultConversion: true,
},
},

assetPrefix: isProd ? assetPrefix : undefined,
output: 'export',
images: {
unoptimized: true,
},
});
```

### Настройка темы

**theme.config.tsx**

```tsx
import { DocsThemeConfig } from './vkui-nextra-theme';

const config: DocsThemeConfig = {
header: {
selectedHref: 'https://vkcom.github.io/icons/',
},
};

export default config;
```

### Подключение глобальных стилей

**pages/\_app.tsx**

```tsx
import '@vkontakte/vkui-nextra-theme/styles.css';

export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />;
}
```
29 changes: 29 additions & 0 deletions packages/vkui-nextra-theme/components/NavHeader/Logo/Logo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
export function Logo(props: React.ComponentProps<'svg'>) {
return (
<svg
width="65"
height="36"
viewBox="0 0 65 36"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden
{...props}
>
<g>
<path
d="M0 17.28C0 9.13413 0 5.06119 2.5306 2.5306C5.06119 0 9.13413 0 17.28 0H18.72C26.8659 0 30.9388 0 33.4694 2.5306C36 5.06119 36 9.13413 36 17.28V18.72C36 26.8659 36 30.9388 33.4694 33.4694C30.9388 36 26.8659 36 18.72 36H17.28C9.13413 36 5.06119 36 2.5306 33.4694C0 30.9388 0 26.8659 0 18.72V17.28Z"
fill="#0077FF"
/>
<path
d="M19.1542 25.9342C10.9492 25.9342 6.26922 20.3092 6.07422 10.9492H10.1842C10.3192 17.8192 13.3491 20.7292 15.7491 21.3292V10.9492H19.6193V16.8742C21.9893 16.6192 24.479 13.9192 25.319 10.9492H29.1891C28.5441 14.6092 25.8441 17.3092 23.9241 18.4192C25.8441 19.3192 28.9192 21.6742 30.0892 25.9342H25.8291C24.9141 23.0842 22.6343 20.8792 19.6193 20.5792V25.9342H19.1542Z"
fill="white"
/>
</g>
<path
d="M53.8507 25C52.7245 25 51.7151 24.765 50.8224 24.2951C49.9434 23.8121 49.2498 23.1399 48.7416 22.2783C48.2472 21.4168 48 20.4443 48 19.3608V11H50.4721V19.3608C50.4721 20.3921 50.7812 21.234 51.3992 21.8867C52.031 22.5263 52.8481 22.8462 53.8507 22.8462C54.8671 22.8462 55.6911 22.5263 56.3229 21.8867C56.9546 21.234 57.2705 20.3921 57.2705 19.3608V11H59.7427V19.3608C59.7427 20.4443 59.4886 21.4168 58.9804 22.2783C58.486 23.1399 57.7924 23.8121 56.8997 24.2951C56.007 24.765 54.9907 25 53.8507 25Z"
fill="currentColor"
/>
<path d="M65 24.8042H62.5279V11H65V24.8042Z" fill="currentColor" />
</svg>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.host {
padding-block: 8px;
padding-inline: 16px;
border-radius: 8px;
text-decoration: none;
color: var(--vkui--color_text_primary);
}

.active,
.host:hover {
background: var(--vkui--color_field_background);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { classNames, Paragraph } from '@vkontakte/vkui';
import styles from './Chip.module.css';

interface ChipProps extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
active?: boolean;
}

export function Chip({ active, className, ...props }: ChipProps) {
return (
<Paragraph
Component="a"
className={classNames(className, styles.host, active && styles.active)}
{...props}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.host {
display: flex;
}

/* stylelint-disable-next-line selector-max-universal -- gap */
.host > * {
margin-inline-end: 8px;
}

/* stylelint-disable-next-line selector-max-universal -- gap */
.host > *:last-child {
margin-inline-end: 0;
}
22 changes: 22 additions & 0 deletions packages/vkui-nextra-theme/components/NavHeader/Menu/Menu.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Chip } from './Chip/Chip';
import styles from './Menu.module.css';

interface MenuPage {
href: string;
children: string;
}

export interface MenuProps {
pages: MenuPage[];
selectedHref?: string;
}

export function Menu({ pages, selectedHref }: MenuProps) {
return (
<nav className={styles.host}>
{pages.map((props, i) => (
<Chip key={i} active={selectedHref === props.href} {...props} />
))}
</nav>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.host {
inline-size: 100%;
border-block-end: 1px solid var(--vkui--color_image_border_alpha);
}

.inner {
margin-block: 0;
margin-inline: auto;
max-inline-size: 1440px;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
padding-block: 24px;
padding-inline: 40px;
color: var(--vkui--color_text_primary);
}

.before,
.after {
display: flex;
}

/* stylelint-disable-next-line selector-max-universal */
.after > * {
margin-inline-end: 8px;
}

/* stylelint-disable-next-line selector-max-universal */
.after > *:last-child {
margin-inline-end: 0;
}
31 changes: 31 additions & 0 deletions packages/vkui-nextra-theme/components/NavHeader/NavHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { AdaptivityProvider } from '@vkontakte/vkui';
import { Logo } from './Logo/Logo';
import { Menu, MenuProps } from './Menu/Menu';
import { ThemeSelect } from './ThemeSelect/ThemeSelect';
import styles from './NavHeader.module.css';

export interface NavHeaderProps {
before?: React.ReactNode;
after?: React.ReactNode;
menu?: MenuProps;
}

export function NavHeader({ before, after, menu }: NavHeaderProps) {
return (
<header className={styles.host}>
<AdaptivityProvider sizeY="compact">
<div className={styles.inner}>
<div className={styles.before}>
<Logo />
{before}
</div>
{menu && <Menu {...menu} />}
<div className={styles.after}>
{after}
<ThemeSelect />
</div>
</div>
</AdaptivityProvider>
</header>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.host {
inline-size: 94px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
'use client';

import * as React from 'react';
import { Icon20MoonOutline, Icon20SunOutline } from '@vkontakte/icons';
import { noop } from '@vkontakte/vkjs';
import { SegmentedControl, Skeleton } from '@vkontakte/vkui';
import styles from './ThemeSelect.module.css';

const LIGHT_CLASS_NAME = 'vkui--vkBase--light';
const DARK_CLASS_NAME = 'vkui--vkBase--dark';

function removeAppearanceClassNames() {
// eslint-disable-next-line no-restricted-globals
document.documentElement.classList.remove(LIGHT_CLASS_NAME, DARK_CLASS_NAME);
}

export function ThemeSelect() {
const [appearance, setAppearance] = React.useState<undefined | 'light' | 'dark'>(undefined);
const autoAppearance = React.useRef(true);

const onClick = () => {
autoAppearance.current = false;

const newAppearance = appearance === 'light' ? 'dark' : 'light';

setAppearance(newAppearance);

const appearanceClassName = newAppearance === 'dark' ? DARK_CLASS_NAME : LIGHT_CLASS_NAME;

removeAppearanceClassNames();
// eslint-disable-next-line no-restricted-globals
document.documentElement.classList.add(appearanceClassName);
};

React.useEffect(() => {
// eslint-disable-next-line no-restricted-globals
const mediaQuery = window ? window.matchMedia('(prefers-color-scheme: dark)') : undefined;

if (!mediaQuery) {
return noop;
}

const check = (event: MediaQueryList | MediaQueryListEvent) => {
removeAppearanceClassNames();
setAppearance(event.matches ? 'dark' : 'light');
};

check(mediaQuery);

mediaQuery.addEventListener('change', check);

Check failure on line 50 in packages/vkui-nextra-theme/components/NavHeader/ThemeSelect/ThemeSelect.tsx

View workflow job for this annotation

GitHub Actions / Run linters

Cannot invoke an object which is possibly 'undefined'.
return () => mediaQuery.removeEventListener('change', check);

Check failure on line 51 in packages/vkui-nextra-theme/components/NavHeader/ThemeSelect/ThemeSelect.tsx

View workflow job for this annotation

GitHub Actions / Run linters

Cannot invoke an object which is possibly 'undefined'.
}, []);

if (appearance === undefined) {
return <Skeleton className={styles.host} />;
}

return (
<SegmentedControl
className={styles.host}
value={appearance}
options={[
{
'label': <Icon20SunOutline />,
'value': 'light',
'aria-label': 'Светлая тема',
onClick,
},
{
'label': <Icon20MoonOutline />,
'value': 'dark',
'aria-label': 'Темная тема',
onClick,
},
]}
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.host {
padding-block: 36px;
padding-inline: 40px;
margin-block: 0;
margin-inline: auto;
max-inline-size: 1440px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { classNames } from '@vkontakte/vkjs';
import styles from './OneColumn.module.css';

export function OneColumn({ className, ...props }: React.ComponentProps<'main'>) {
return <main className={classNames(className, styles.host)} {...props} />;
}
34 changes: 34 additions & 0 deletions packages/vkui-nextra-theme/icons/Icon20Figma.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export function Icon20Figma(props: React.ComponentProps<'svg'>) {
return (
<svg
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
xmlns="http://www.w3.org/2000/svg"
aria-hidden
{...props}
>
<path
d="M7.66668 18C9.13868 18 10.3334 16.8053 10.3334 15.3333V12.6666H7.66668C6.19467 12.6666 5 13.8613 5 15.3333C5 16.8053 6.19467 18 7.66668 18Z"
fill="#E8E8E8"
/>
<path
d="M5 10.0001C5 8.52809 6.19467 7.33342 7.66668 7.33342H10.3334V12.6666H7.66668C6.19467 12.6666 5 11.4721 5 10.0001Z"
fill="white"
/>
<path
d="M5.00004 4.66668C5.00004 3.19467 6.19471 2 7.66672 2H10.3334L10.3334 7.33342H7.66668C6.19467 7.33342 5.00004 6.13868 5.00004 4.66668Z"
fill="#F6F6F6"
/>
<path
d="M10.3334 2H12.9995C14.4715 2 15.6662 3.19467 15.6662 4.66668C15.6662 6.13868 14.4715 7.33335 12.9995 7.33335L10.3334 7.33342L10.3334 2Z"
fill="white"
/>
<path
d="M15.6662 10.0001C15.6662 11.4721 14.4715 12.6668 12.9995 12.6668C11.5275 12.6668 10.3328 11.4721 10.3328 10.0001C10.3328 8.52809 11.5275 7.33335 12.9995 7.33335C14.4715 7.33335 15.6662 8.52809 15.6662 10.0001Z"
fill="#F6F6F6"
/>
</svg>
);
}
Loading
Loading