App refactoring (#257)
* add cache * update Panel * next app refacoring * app style refactoring * years refactroing
This commit is contained in:
1 parent
9ee9bce197
commit
0fd75a3b9a
10 files changed
+102
-88
No files matched your search
@@ -59,5 +59,15 @@ jobs:
|
|||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Cache Next.js build
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: .next/cache
|
||||||
|
key: nextjs-${{ hashFiles('package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx', '**/*.css') }}
|
||||||
|
restore-keys: nextjs-${{ hashFiles('package-lock.json') }}-
|
||||||
|
|
||||||
|
- name: Disable Next.js telemetry
|
||||||
|
run: npx next telemetry disable
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: npm run build
|
run: npm run build
|
||||||
+3
-2
@@ -1,7 +1,8 @@
|
|||||||
import type { NextPage } from "next"
|
import type { NextPage } from "next"
|
||||||
import { Wrapper } from "@/components/Wrapper"
|
import { Wrapper } from "@/components/Wrapper"
|
||||||
import { NotFound } from "@/components/NotFound"
|
import { NotFound } from "@/components/NotFound"
|
||||||
import Copyright from "@/components/Copyright"
|
import { Copyright } from "@/components/Copyright"
|
||||||
|
import { yearRange } from "@/const"
|
||||||
import { Spacer } from "@/components/Spacer"
|
import { Spacer } from "@/components/Spacer"
|
||||||
import { Box } from "@/ui/Box"
|
import { Box } from "@/ui/Box"
|
||||||
|
|
||||||
@@ -11,7 +12,7 @@ const Index: NextPage = () => (
|
|||||||
footer={(
|
footer={(
|
||||||
<Box as={"footer"}>
|
<Box as={"footer"}>
|
||||||
<Spacer />
|
<Spacer />
|
||||||
<Copyright />
|
<Copyright years={yearRange} />
|
||||||
<Spacer />
|
<Spacer />
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|||||||
+37
-41
@@ -4,56 +4,52 @@ import "src/style/article.css"
|
|||||||
import "src/style/marker/marker-table.css"
|
import "src/style/marker/marker-table.css"
|
||||||
import "src/style/kazimir/video.css"
|
import "src/style/kazimir/video.css"
|
||||||
|
|
||||||
import App from "next/app"
|
import type { AppProps } from "next/app"
|
||||||
import Head from "next/head"
|
import Head from "next/head"
|
||||||
import Script from "next/script"
|
import Script from "next/script"
|
||||||
import { YMetrika } from "@/components/YMetrika"
|
import { YMetrika } from "@/components/YMetrika"
|
||||||
import { ThemeColor } from "@/ui/ThemeColor"
|
import { ThemeColor } from "@/ui/ThemeColor"
|
||||||
|
|
||||||
export default class MyApp extends App {
|
export default function MyApp({ Component, pageProps }: AppProps) {
|
||||||
render() {
|
return (
|
||||||
const { Component, pageProps } = this.props
|
<>
|
||||||
|
<Head>
|
||||||
|
<meta charSet="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, maximum-scale=1.0" />
|
||||||
|
<meta name="referrer" content="unsafe-url" />
|
||||||
|
|
||||||
return (
|
<meta name="google-site-verification" content="8BxOTw-Q02DS2KAdcGcnIMwiPZ58DVB18XpOfRibCcg" />
|
||||||
<>
|
<meta name="google-site-verification" content="A-TEemUw4hHpULUDCd6xhxfHnyRbgKtss90JGKXnSpw" />
|
||||||
<Head>
|
<meta name='yandex-verification' content='643c7dac144b9dac' />
|
||||||
<meta charSet="utf-8" />
|
<meta name="msvalidate.01" content="E878301FE3E3F12D233A6B1156889601" />
|
||||||
<meta name="viewport" content="width=device-width, maximum-scale=1.0" />
|
<meta name="proculture-verification" content="79110940fd847c3cfe52392ed68f3210" />
|
||||||
<meta name="referrer" content="unsafe-url" />
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
|
|
||||||
<meta name="google-site-verification" content="8BxOTw-Q02DS2KAdcGcnIMwiPZ58DVB18XpOfRibCcg" />
|
<link rel="icon" type="image/png" href="/static/graphics/favicon-32.png" />
|
||||||
<meta name="google-site-verification" content="A-TEemUw4hHpULUDCd6xhxfHnyRbgKtss90JGKXnSpw" />
|
<link rel="apple-touch-icon" sizes="57x57" href="/static/graphics/favicon-57.png" />
|
||||||
<meta name='yandex-verification' content='643c7dac144b9dac' />
|
<link rel="apple-touch-icon" sizes="72x72" href="/static/graphics/favicon-72.png" />
|
||||||
<meta name="msvalidate.01" content="E878301FE3E3F12D233A6B1156889601" />
|
<link rel="apple-touch-icon" sizes="114x114" href="/static/graphics/favicon-114.png" />
|
||||||
<meta name="proculture-verification" content="79110940fd847c3cfe52392ed68f3210" />
|
<link rel="apple-touch-icon" sizes="144x144" href="/static/graphics/favicon-144.png" />
|
||||||
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
||||||
|
|
||||||
<link rel="icon" type="image/png" href="/static/graphics/favicon-32.png" />
|
<link
|
||||||
<link rel="apple-touch-icon" sizes="57x57" href="/static/graphics/favicon-57.png" />
|
rel="alternate"
|
||||||
<link rel="apple-touch-icon" sizes="72x72" href="/static/graphics/favicon-72.png" />
|
type="application/rss+xml"
|
||||||
<link rel="apple-touch-icon" sizes="114x114" href="/static/graphics/favicon-114.png" />
|
title="Шлиссельбургская Детская Художественная Школа"
|
||||||
<link rel="apple-touch-icon" sizes="144x144" href="/static/graphics/favicon-144.png" />
|
href="/feed.xml"
|
||||||
|
/>
|
||||||
|
|
||||||
<link
|
{process.env.NEXT_PUBLIC_YMETRIKA_ACCOUNT && (
|
||||||
rel="alternate"
|
<YMetrika account={Number(process.env.NEXT_PUBLIC_YMETRIKA_ACCOUNT)} />
|
||||||
type="application/rss+xml"
|
)}
|
||||||
title="Шлиссельбургская Детская Художественная Школа"
|
|
||||||
href="/feed.xml"
|
|
||||||
/>
|
|
||||||
|
|
||||||
{process.env.NEXT_PUBLIC_YMETRIKA_ACCOUNT && (
|
<ThemeColor
|
||||||
<YMetrika account={Number(process.env.NEXT_PUBLIC_YMETRIKA_ACCOUNT)} />
|
color="white"
|
||||||
)}
|
darkColor="hsl(240, 10%, 10%)"
|
||||||
|
/>
|
||||||
|
</Head>
|
||||||
|
<Script src="https://culturaltracking.ru/static/js/spxl.js?pixelId=27154" data-pixel-id="27154"></Script>
|
||||||
|
|
||||||
<ThemeColor
|
<Component {...pageProps} />
|
||||||
color="white"
|
</>
|
||||||
darkColor="hsl(240, 10%, 10%)"
|
)
|
||||||
/>
|
|
||||||
</Head>
|
|
||||||
<Script src="https://culturaltracking.ru/static/js/spxl.js?pixelId=27154" data-pixel-id="27154"></Script>
|
|
||||||
|
|
||||||
<Component {...pageProps} />
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
.navigation {
|
||||||
|
padding: var(--size-s);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerLinks {
|
||||||
|
margin-bottom: var(--size-l);
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerPanel {
|
||||||
|
align-items: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gosuslugi {
|
||||||
|
background-color: white;
|
||||||
|
padding: 10px;
|
||||||
|
border-radius: 10px;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import s from "./app.module.css"
|
||||||
|
|
||||||
import { Wrapper } from "../Wrapper"
|
import { Wrapper } from "../Wrapper"
|
||||||
import { MenuContext } from "@/context/MenuContext"
|
import { MenuContext } from "@/context/MenuContext"
|
||||||
import { Footer } from "../Footer"
|
import { Footer } from "../Footer"
|
||||||
@@ -9,7 +11,8 @@ import { useMobile } from "@/hooks/useMobile"
|
|||||||
import { Navigation } from "@/components/Navigation"
|
import { Navigation } from "@/components/Navigation"
|
||||||
import { Box } from "@/ui/Box"
|
import { Box } from "@/ui/Box"
|
||||||
import { AccessibilityButton } from "../AccessibilityButton"
|
import { AccessibilityButton } from "../AccessibilityButton"
|
||||||
import Copyright from "@/components/Copyright"
|
import { Copyright } from "@/components/Copyright"
|
||||||
|
import { yearRange } from "@/const"
|
||||||
import { Spacer } from "../Spacer"
|
import { Spacer } from "../Spacer"
|
||||||
import { Author } from "../Author"
|
import { Author } from "../Author"
|
||||||
import { Title } from "@/ui/Title"
|
import { Title } from "@/ui/Title"
|
||||||
@@ -18,7 +21,6 @@ import { Contacts } from "../Contacts"
|
|||||||
import dynamic from "next/dynamic"
|
import dynamic from "next/dynamic"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
|
|
||||||
import Image from "next/image"
|
|
||||||
import AccessibilityPanel from "../AccessibilityPanel"
|
import AccessibilityPanel from "../AccessibilityPanel"
|
||||||
import useAccessibility from "@/hooks/useAccessibility"
|
import useAccessibility from "@/hooks/useAccessibility"
|
||||||
|
|
||||||
@@ -34,13 +36,10 @@ export type AppProps = {
|
|||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export const App: React.FC<AppProps> = ({ showAuthor = false, menu, ...props }) => {
|
export function App({ showAuthor = false, menu, ...props }: AppProps) {
|
||||||
const hideBreadcrumbs = useMobile()
|
const hideBreadcrumbs = useMobile()
|
||||||
const accessibility = useAccessibility()
|
const accessibility = useAccessibility()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const blockStyle = {
|
|
||||||
justifyContent: "center",
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MenuContext.Provider value={menu}>
|
<MenuContext.Provider value={menu}>
|
||||||
@@ -51,11 +50,11 @@ export const App: React.FC<AppProps> = ({ showAuthor = false, menu, ...props })
|
|||||||
<AccessibilityPanel/>
|
<AccessibilityPanel/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Navigation style={{
|
<div className={s.navigation}>
|
||||||
padding: "var(--size-s)",
|
<Navigation />
|
||||||
}} />
|
</div>
|
||||||
{hideBreadcrumbs || !props.breadcrumbs ? null : (
|
{hideBreadcrumbs || !props.breadcrumbs ? null : (
|
||||||
<Box style={blockStyle}>
|
<Box center>
|
||||||
<Content>
|
<Content>
|
||||||
<Breadcrumbs
|
<Breadcrumbs
|
||||||
items={props.breadcrumbs}
|
items={props.breadcrumbs}
|
||||||
@@ -68,25 +67,19 @@ export const App: React.FC<AppProps> = ({ showAuthor = false, menu, ...props })
|
|||||||
)}
|
)}
|
||||||
footer={(
|
footer={(
|
||||||
<Footer>
|
<Footer>
|
||||||
<Box wrap gap={40} align={false} style={{
|
<Box wrap gap={40} align={false} className={s.footerLinks}>
|
||||||
marginBottom: "var(--size-l)",
|
|
||||||
}}>
|
|
||||||
<Panel ghost>
|
<Panel ghost>
|
||||||
<Contacts />
|
<Contacts />
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
||||||
<Panel ghost style={{
|
<Panel ghost className={s.footerPanel}>
|
||||||
alignItems: "baseline",
|
|
||||||
}}>
|
|
||||||
<Title level={3}>
|
<Title level={3}>
|
||||||
Версия для слабовидящих
|
Версия для слабовидящих
|
||||||
</Title>
|
</Title>
|
||||||
<AccessibilityButton />
|
<AccessibilityButton />
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
||||||
<Panel ghost style={{
|
<Panel ghost className={s.footerPanel}>
|
||||||
alignItems: "baseline",
|
|
||||||
}}>
|
|
||||||
<Title level={3}>
|
<Title level={3}>
|
||||||
Анкеты
|
Анкеты
|
||||||
</Title>
|
</Title>
|
||||||
@@ -113,17 +106,12 @@ export const App: React.FC<AppProps> = ({ showAuthor = false, menu, ...props })
|
|||||||
</Panel>
|
</Panel>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<div style={{
|
<div className={s.gosuslugi}>
|
||||||
backgroundColor: "white",
|
|
||||||
padding: 10,
|
|
||||||
borderRadius: 10,
|
|
||||||
marginBottom: 30,
|
|
||||||
}}>
|
|
||||||
<Gosuslugi />
|
<Gosuslugi />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Box>
|
<Box>
|
||||||
<Copyright />
|
<Copyright years={yearRange} />
|
||||||
|
|
||||||
{!showAuthor ? null : (
|
{!showAuthor ? null : (
|
||||||
<>
|
<>
|
||||||
@@ -135,7 +123,7 @@ export const App: React.FC<AppProps> = ({ showAuthor = false, menu, ...props })
|
|||||||
</Footer>
|
</Footer>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Box style={blockStyle}>
|
<Box center>
|
||||||
<Content style={props.contentStyle}>
|
<Content style={props.contentStyle}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</Content>
|
</Content>
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
import { state } from "@/store/config"
|
export type CopyrightProps = {
|
||||||
import { useSnapshot } from "valtio"
|
years: string
|
||||||
|
|
||||||
function Copyright() {
|
|
||||||
const { years } = useSnapshot(state)
|
|
||||||
const year = years.map(String).join("—")
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span>© {year} Шлиссельбургская детская художественная школа</span>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Copyright
|
export function Copyright({ years }: CopyrightProps) {
|
||||||
|
return (
|
||||||
|
<span>© {years} Шлиссельбургская детская художественная школа</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export const yearRange = [2012, 2026].join("—")
|
||||||
@@ -1,7 +1,5 @@
|
|||||||
import { proxy } from "valtio"
|
import { proxy } from "valtio"
|
||||||
|
|
||||||
const currentYear = () => (new Date()).getFullYear()
|
|
||||||
|
|
||||||
type Contact = {
|
type Contact = {
|
||||||
type: string
|
type: string
|
||||||
value: string
|
value: string
|
||||||
@@ -9,12 +7,10 @@ type Contact = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
years: [number, number]
|
|
||||||
contacts: Contact[]
|
contacts: Contact[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const state = proxy<State>({
|
export const state = proxy<State>({
|
||||||
years: [2012, currentYear()],
|
|
||||||
contacts: [
|
contacts: [
|
||||||
{
|
{
|
||||||
type: "link",
|
type: "link",
|
||||||
|
|||||||
@@ -20,4 +20,10 @@ describe("Panel", () => {
|
|||||||
expect(el.className).toMatch(/ghost/)
|
expect(el.className).toMatch(/ghost/)
|
||||||
expect(el.className).not.toMatch(/default/)
|
expect(el.className).not.toMatch(/default/)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("forwards a custom className", () => {
|
||||||
|
const { container } = render(<Panel className="custom">content</Panel>)
|
||||||
|
const el = container.firstElementChild!
|
||||||
|
expect(el.className).toContain("custom")
|
||||||
|
})
|
||||||
})
|
})
|
||||||
@@ -5,18 +5,20 @@ import { Box } from "../Box"
|
|||||||
export type PanelProps = {
|
export type PanelProps = {
|
||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
style?: React.CSSProperties
|
style?: React.CSSProperties
|
||||||
|
className?: string
|
||||||
ghost?: boolean
|
ghost?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Panel: React.FC<PanelProps> = ({
|
export function Panel({
|
||||||
style,
|
style,
|
||||||
|
className,
|
||||||
children,
|
children,
|
||||||
ghost = false,
|
ghost = false,
|
||||||
}) => {
|
}: PanelProps) {
|
||||||
const variant = ghost ? s.ghost : s.default
|
const variant = ghost ? s.ghost : s.default
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Box vertical align={false} className={`${s.panel} ${variant}`} style={style}>
|
<Box vertical align={false} className={`${s.panel} ${variant}${className ? ` ${className}` : ""}`} style={style}>
|
||||||
{children}
|
{children}
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in new issue
Block a user