feat(directory): finish home page

This commit is contained in:
Haoyu Xu
2023-02-26 01:06:10 -05:00
parent b5f84c9380
commit 81ee2d2170
24 changed files with 652 additions and 214 deletions

View File

@@ -1,13 +1,20 @@
@import url('https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@400;500&family=Noto+Sans+SC&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap');
@import url('https://fonts.cdnfonts.com/css/bender');
@import url('https://fonts.cdnfonts.com/css/geometos');
:root {
--text-color: rgba(255, 255, 255, 0.87);
--date-color: rgba(255, 255, 255, 0.2);
--border-color: #707070;
--link-highlight-color: #33b5e5;
--drawer-background-color: rgba(0, 0, 0, 0.5);
--drawer-background-color: rgba(0, 0, 0, 0.88);
--root-background-color: #131313;
--home-item-hover-background-color: rgba(67, 67, 67, 0.3);
--home-item-background-linear-gradient-color: rgba(255, 255, 255, 0.1);
--home-item-outline-color: rgba(214, 214, 214, 0.3);
--button-color: #666;
font-family: "Josefin Sans", "Noto Sans SC", sans-serif;
font-family: "Geometos", "Noto Sans SC", sans-serif;
font-size: 16px;
line-height: 24px;
font-weight: 400;

View File

@@ -11,8 +11,9 @@ import ErrorPage from "@/routes/error-page";
import routes from "@/routes";
import '@/App.css';
import 'reset-css';
import { TitleProvider } from '@/context/useTitleContext';
import { LanguageProvider } from '@/context/useLanguageContext';
import { ConfigProvider } from '@/context/useConfigContext';
import { HeaderProvider } from '@/context/useHeaderContext';
const router = createBrowserRouter(
createRoutesFromElements(
@@ -40,10 +41,12 @@ const router = createBrowserRouter(
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<ConfigProvider>
<LanguageProvider>
<TitleProvider>
<HeaderProvider>
<RouterProvider router={router} />
</TitleProvider>
</HeaderProvider>
</LanguageProvider>
</ConfigProvider>
</React.StrictMode>
)

View File

@@ -0,0 +1,13 @@
export default function CharIcon(props) {
return (
<svg xmlns="http://www.w3.org/2000/svg" viewBox={props.viewBox}>
{
props.type === 'operator' ?
<g><path d="M89 17.5 30.4 57 24.3 71.4 82.9 32.6Z"></path><path d="M0 17.5 58.6 57 64.7 71.4 6.1 32.7Z"> </path><path d="M89 0 30.4 39.5 24.3 53.9 82.9 15.1Z"> </path><path d="M0 0 58.6 39.5 64.7 53.9 6.1 15.2Z"> </path></g>
:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 94.563 67.437"><path d="M90.4 50.6l-39.8-23.5v-4c0-4.5-5-6.5-5-6.5a5.4 5.4 0 012.2-10.1c2.7 0 5.3 1.5 5.5 4.8.4 5.3 6.4 3.9 6.4-.3a11.7 11.7 0 00-12-11c-9 0-11.6 8.8-11.6 11.6a11.5 11.5 0 001.6 6.2c2.2 3.8 6.6 4.3 6.6 6.8v2.5L4.2 50.7c-4 2.3-4.7 7.3-3.8 10.3a9.1 9.1 0 009.1 6.4h75.2c5.9 0 8.6-3.4 9.5-6.3C95 58.1 95 53.4 90.4 50.6Zm-5.6 10.3h-75.2c-2.4.1-4-3.3-1.5-4.8l39.2-22.9 39 22.8A2.7 2.7 0 0184.7 60.8Z" /></svg>
}
</svg>
)
}

View File

@@ -37,7 +37,7 @@
.dropdown .menu {
opacity: 0;
position: absolute;
background-color: var(--background-color);
background-color: var(--root-background-color);
color: var(--text-color);
width: max-content;
z-index: -1;

View File

@@ -28,7 +28,10 @@ export default function Dropdown(props) {
<li
key={item.name}
className={`item${item.name === props.text ? ' active' : ''}`}
onClick={() => props.onClick(item)}
onClick={() => {
props.onClick(item)
toggleDropdown()
}}
>
{item.name}
</li>

View File

@@ -0,0 +1,23 @@
.main-border {
position: relative;
bottom: 1px;
border-bottom: 1px solid var(--text-color);
}
.main-border::before, .main-border::after {
content: "";
display: block;
position: absolute;
width: 5px;
height: 5px;
top: -2px;
background-color: var(--text-color);
}
.main-border::before {
right: 100%;
}
.main-border::after {
left: 100%;
}

View File

@@ -0,0 +1,7 @@
import './main_border.css';
export default function MainBorder(props) {
return (
<section className="main-border"/>
)
}

View File

@@ -41,13 +41,18 @@
.popup .title {
font-size: 3rem;
font-weight: 700;
margin-bottom: 1rem;
border-bottom: 1px solid var(--border-color);
display: flex;
flex-direction: row;
justify-content: space-between;
align-content: center;
align-items: center;
padding-bottom: 1rem;
}
.popup .content {
line-height: 1.5rem;
padding: 1rem;
}
.popup .overlay {
@@ -66,3 +71,12 @@
opacity: 0.5;
visibility: visible;
}
.popup .return-button {
color: #666;
transition: color cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
}
.popup .return-button:hover {
color: var(--text-color);
}

View File

@@ -18,7 +18,7 @@ export default function Popup(props) {
<section className='wrapper'>
<section className='title'>
<span>{props.title}</span>
<ReturnButton onClick={toggle} />
<ReturnButton onClick={toggle} className="return-button"/>
</section>
<section className='content'>
{props.children}

View File

@@ -17,20 +17,20 @@
.return-button .bar {
width: 1rem;
height: 0.4rem;
background-color: var(--text-color);
background-color: currentColor;
transition: transform cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
}
.return-button .bar-arrow-left {
border-top: 0.24rem solid transparent;
border-bottom: 0.24rem solid transparent;
border-right: 0.3rem solid var(--text-color);
border-right: 0.3rem solid currentColor;
}
.return-button .bar-arrow-right {
border-top: 0.24rem solid transparent;
border-bottom: 0.24rem solid transparent;
border-left: 0.3rem solid var(--text-color);
border-left: 0.3rem solid currentColor;
}
.return-button .bar-wrapper:nth-child(1) {

View File

@@ -0,0 +1,19 @@
import { createContext, useState, useEffect } from "react"
export const ConfigContext = createContext()
export function ConfigProvider(props) {
const [config, setConfig] = useState(null)
useEffect(() => {
fetch("/_assets/directory.json").then(res => res.json()).then(data => {
setConfig(data)
})
}, [])
return (
<ConfigContext.Provider value={{ config }}>
{props.children}
</ConfigContext.Provider>
)
}

View File

@@ -0,0 +1,39 @@
import {
createContext,
useState,
useEffect,
useContext
} from "react"
import { LanguageContext } from "@/context/useLanguageContext"
export const HeaderContext = createContext()
export function HeaderProvider(props) {
const [key, setTitle] = useState('')
const [title, setRealTitle] = useState('')
const {
language,
i18n
} = useContext(LanguageContext)
const [tabs, setTabs] = useState(null)
const [currentTab, setCurrentTab] = useState(null)
useEffect(() => {
let newTitle = key
if (i18n.key[newTitle]) {
newTitle = i18n.key[newTitle][language]
}
document.title = `${newTitle} - ${import.meta.env.VITE_APP_TITLE}`;
setRealTitle(newTitle)
}, [key, language])
return (
<HeaderContext.Provider value={{
title, setTitle,
tabs, setTabs,
currentTab, setCurrentTab,
}}>
{props.children}
</HeaderContext.Provider>
)
}

View File

@@ -4,20 +4,20 @@ import i18n from '@/i18n'
export const LanguageContext = createContext()
export function LanguageProvider(props) {
const drawerTextDefaultLang = "en-US"
const textDefaultLang = "en-US"
const [language, setLanguage] = useState(i18n.available.includes(navigator.language) ? navigator.language : "en-US") // language will be default to en-US if not available
const [drawerAlternateLang, setDrawerAlternateLang] = useState(null) // drawerAlternateLang will be default to zh-CN if language is en-*
const [alternateLang, setAlternateLang] = useState(null) // drawerAlternateLang will be default to zh-CN if language is en-*
useEffect(() => {
setDrawerAlternateLang(language.startsWith("en") ? "zh-CN" : language)
setAlternateLang(language.startsWith("en") ? "zh-CN" : language)
}, [language])
return (
<LanguageContext.Provider
value={{
language, setLanguage,
drawerTextDefaultLang,
drawerAlternateLang,
textDefaultLang,
alternateLang,
i18n
}}
>

View File

@@ -1,25 +0,0 @@
import { createContext, useState, useEffect, useContext } from "react"
import { LanguageContext } from '@/context/useLanguageContext';
export const TitleContext = createContext()
export function TitleProvider(props) {
const { i18n, language } = useContext(LanguageContext)
const [fakeTitle, setTitle] = useState('dynamic_compile')
const [title, setActualTitle] = useState(null)
useEffect(() => {
let newTitle = fakeTitle
if (i18n.key[fakeTitle]) {
newTitle = i18n.key[fakeTitle][language]
}
document.title = `${newTitle} - ${import.meta.env.VITE_APP_TITLE}`;
setActualTitle(newTitle)
}, [fakeTitle, language])
return (
<TitleContext.Provider value={{ title, setTitle }}>
{props.children}
</TitleContext.Provider>
)
}

View File

@@ -11,14 +11,22 @@
"zh-CN": "首页",
"en-US": "Home"
},
"news": {
"zh-CN": "新闻",
"en-US": "News"
"changelogs": {
"zh-CN": "更新日志",
"en-US": "Changelogs"
},
"offical_page": {
"zh-CN": "官方页面",
"en-US": "Offical Page"
},
"disclaimer": {
"zh-CN": "免责声明",
"en-US": "Disclaimer"
},
"disclaimer_content": {
"zh-CN": "本网站由 Halyul 设立并为明日方舟社区服务Halyul 声明本网站完全独立运营,与 上海鹰角网络科技有限公司, Esoteric Software LLC 或其任何关联实体并无任何联系。",
"en-US": "This website is set up and operated by Halyul for the benefit of the Arknights Community. Halyul hereby states that this website is dedicated, but not related to Hypergryph Co., Ltd, Esoteric Software LLC or any of its affiliated entity."
},
"privacy_policy": {
"zh-CN": "隐私政策",
"en-US": "Privacy Policy"
@@ -27,6 +35,18 @@
"zh-CN": "联系我们",
"en-US": "Contact Us"
},
"all": {
"zh-CN": "综合",
"en-US": "All"
},
"elite2": {
"zh-CN": "干员晋升",
"en-US": "Elite 2"
},
"skin": {
"zh-CN": "干员时装",
"en-US": "Skin"
},
"zh-CN": {
"zh-CN": "简体中文",
"en-US": "Chinese (Simplified)"

View File

@@ -1,6 +1,6 @@
import Home from "@/routes/path/home";
import Operator from "@/routes/path/operator";
import News from "@/routes/path/news";
import Changelogs from "@/routes/path/changelogs";
export default [
{
@@ -16,10 +16,10 @@ export default [
element: <Operator />,
inDrawer: false
}, {
path: "news",
path: "changelogs",
index: false,
name: "news",
element: <News />,
name: "changelogs",
element: <Changelogs />,
inDrawer: true
}, {
path: "https://ak.hypergryph.com/archive/dynamicCompile/",

View File

@@ -0,0 +1,32 @@
import {
useState,
useEffect,
useContext
} from 'react'
import './changelogs.css'
import { HeaderContext } from '@/context/useHeaderContext';
import { LanguageContext } from '@/context/useLanguageContext';
import useUmami from '@parcellab/react-use-umami'
export default function Changelogs(props) {
const _trackEvt = useUmami('/changelogs')
const {
setTitle,
setTabs,
currentTab, setCurrentTab
} = useContext(HeaderContext)
const { language, i18n } = useContext(LanguageContext)
useEffect(() => {
setTitle('changelogs')
setTabs([])
}, [])
return (
<section>
<section>
Under Construction :(
</section>
</section>
)
}

View File

@@ -0,0 +1,126 @@
.home .item-group {
padding: 1rem;
display: flex;
align-items: flex-end;
flex-wrap: wrap;
}
.home .item-group-date {
margin: 1.5rem;
font-family: "Bender";
font-weight: bold;
text-align: right;
color: var(--date-color);
font-size: 1.5rem;
letter-spacing: 0.1rem;
flex: auto;
}
.home .item-group .item {
position: relative;
cursor: pointer;
width: 180px;
margin: 1.25rem;
background-image: repeating-linear-gradient(90deg, var(--home-item-background-linear-gradient-color) 0, var(--home-item-background-linear-gradient-color) 1px, transparent 1px, transparent 5px);
}
.home .item-group .item .item-outline {
content: "";
display: block;
position: absolute;
opacity: 0;
visibility: hidden;
transition: all cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
}
.home .item-group .item .item-outline{
width: 100%;
height: 100%;
left: -6px;
top: -6px;
border: var(--home-item-outline-color) 1px dashed;
padding: 6px;
}
.home .item-group .item .item-outline::before,
.home .item-group .item .item-outline::after {
content: "";
display: block;
position: absolute;
left: -3px;
height: 3px;
width: 100%;
border-left: var(--text-color) solid 3px;
border-right: var(--text-color) solid 3px;
}
.home .item-group .item .item-outline::before {
top: -3px;
}
.home .item-group .item .item-outline::after {
bottom: -3px;
}
.home .item-group .item:hover .item-outline,
.home .item-group .item:hover .item-info .item-info-background {
opacity: 1;
visibility: visible;
}
.home .item-group .item .item-img {
height: 360px;
width: 100%;
transition: background-color cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
}
.home .item-group .item:hover .item-img {
background-color: var(--home-item-hover-background-color);
}
.home .item-group .item .item-info {
white-space: nowrap;
position: relative;
padding: 0.8rem 0.4rem;
line-height: 1;
}
.home .item-group .item .item-info .item-title-container {
color: white;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 1.25rem;
font-weight: bold;
}
.home .item-group .item .item-info .item-title-container .item-title,
.home .item-group .item .item-info .item-text-wrapper {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
}
.home .item-group .item .item-info .item-title-container .item-type {
width: 1.5rem;
fill: var(--text-color)
}
.home .item-group .item .item-info .item-text {
color: var(--text-color);
font-size: 0.75rem;
font-family: "Geometos";
margin-top: 1rem;
}
.home .item-group .item .item-info .item-info-background {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
visibility: hidden;
transition: all cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
background-image: linear-gradient(70deg, transparent 40%, currentColor 150%);
}

View File

@@ -1,32 +1,115 @@
import {
useState,
useEffect,
useContext
useContext,
useMemo
} from 'react'
import {
Link,
} from "react-router-dom";
import './home.css'
import { TitleContext } from '@/context/useTitleContext';
import { ConfigContext } from '@/context/useConfigContext';
import { LanguageContext } from '@/context/useLanguageContext';
import { HeaderContext } from '@/context/useHeaderContext';
import CharIcon from '@/component/char_icon';
import MainBorder from '@/component/main_border';
import useUmami from '@parcellab/react-use-umami'
export default function Home(props) {
const { title, setTitle } = useContext(TitleContext)
useEffect(() => {
fetch("/_assets/directory.json").then(res => res.json()).then(data => {
console.log(data)
})
}, [])
export default function Home() {
const _trackEvt = useUmami('/')
const {
setTitle,
setTabs,
currentTab, setCurrentTab } = useContext(HeaderContext)
const { config } = useContext(ConfigContext)
const {
language,
textDefaultLang,
alternateLang,
i18n
} = useContext(LanguageContext)
useEffect(() => {
setTitle('dynamic_compile')
setTabs([
{
key: 'all',
text: i18n.key.all
}, {
key: 'operator',
text: i18n.key.elite2
}, {
key: 'skin',
text: i18n.key.skin
}
])
setCurrentTab('all')
}, [])
const renderContent = () => {
const list = config?.filter((v) => currentTab === 'all' || currentTab === v.type)
const content = []
if (list) {
console.log(list)
let items = {}
list.forEach(element => {
if (items[element.date]) {
items[element.date].push(toItemEl(element))
} else {
items[element.date] = [toItemEl(element)]
}
});
items = Object.keys(items).sort().reverse().reduce((r, k) => {
r[k] = items[k]
return r
}, {})
for (const [date, group] of Object.entries(items)) {
content.push(
<section className="item-group-wrapper" key={date}>
<section className="item-group">
{group.map((v) => v)}
<section className='item-group-date'>{date}</section>
</section>
<MainBorder />
</section>
)
}
}
return content
}
const toItemEl = (item) => {
return (
<section>
<section>
{title}
<button onClick={() => setTitle('123')}>123</button>
<Link reloadDocument to={`/${item.link}`} className="item" key={item.link}>
<section className="item-outline"/>
<section className="item-img">
<img src={`/${item.link}/assets/${item.fallback_name.replace("#", "%23")}_portrait.png`} alt={item.codename[language]} />
</section>
<section>
22s
<section className="item-info">
<section className="item-title-container">
<section className="item-title">{item.codename[language]}</section>
<section className="item-type">
<CharIcon
type={item.type}
viewBox={
item.type === 'operator' ? '0 0 88.969 71.469' : '0 0 94.563 67.437'
} />
</section>
</section>
<section className="item-text-wrapper">
<span className='item-text'>{item.codename[language.startsWith("en") ? alternateLang : textDefaultLang]}</span>
</section>
<section className="item-info-background" style={{
color: item.color
}} />
</section>
</Link>
)
}
const content = useMemo(() => renderContent(), [currentTab, config, language])
return (
<section className="home">
{content}
</section>
)
}

View File

@@ -1,27 +0,0 @@
import {
useState,
useEffect,
useContext
} from 'react'
import './news.css'
import { TitleContext } from '@/context/useTitleContext';
export default function News(props) {
const { title, setTitle } = useContext(TitleContext)
useEffect(() => {
setTitle('news')
}, [])
return (
<section>
<section>
1
<button onClick={() => setTitle('123')}>123</button>
</section>
<section>
2
</section>
</section>
)
}

View File

@@ -4,13 +4,15 @@ import {
useContext
} from 'react'
import './operator.css'
import { TitleContext } from '@/context/useTitleContext';
import { HeaderContext } from '@/context/useHeaderContext';
import useUmami from '@parcellab/react-use-umami'
export default function Operator(props) {
const { title, setTitle } = useContext(TitleContext)
const _trackEvt = useUmami('/operator/:key')
const { setTitle } = useContext(HeaderContext)
useEffect(() => {
setTitle('Chen')
setTitle('chen')
}, [])
return (

View File

@@ -1,5 +1,13 @@
.main {
flex-grow: 1;
display: flex;
flex-direction: column;
align-items: stretch;
justify-content: flex-start;
padding-bottom: 3rem;
margin: 0 auto;
width: 70%;
max-width: 100rem;
}
.header {
@@ -8,7 +16,7 @@
top: 0;
right: 0;
padding: 1rem;
z-index: 1;
z-index: 2;
height: 3rem;
display: flex;
flex-direction: row;
@@ -67,14 +75,13 @@
left: -15rem;
width: 15rem;
height: 100%;
z-index: 0;
z-index: 1;
pointer-events: none;
transition: left cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
text-align: center;
display: flex;
flex-direction: row;
align-items: flex-start;
gap: 1rem;
}
.drawer .links {
@@ -100,7 +107,7 @@
width: 100vw;
}
.drawer a {
.drawer .link {
display: flex;
flex-direction: column;
align-items: center;
@@ -112,14 +119,61 @@
text-transform: uppercase;
}
.drawer a:hover {
.drawer .link:hover {
color: var(--link-highlight-color);
}
.main {
margin: 0 auto;
width: 90%;
max-width: 100rem;
.drawer .link.active {
color: var(--link-highlight-color);
}
.main .main-header {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: flex-end;
flex-wrap: wrap;
position: relative;
}
.main .main-header .main-title {
font-size: 3rem;
font-weight: 700;
text-transform: uppercase;
}
.main .main-header .main-tab {
display: flex;
flex-direction: row;
align-items: center;
}
.main .main-header .main-tab .main-tab-item {
font-size: 1em;
line-height: 3rem;
font-weight: 700;
padding: 0 1rem;
text-transform: uppercase;
transition: all cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
cursor: pointer;
border-bottom: 0.3rem solid transparent;
}
.main .main-header .main-tab .main-tab-item.active {
color: var(--link-highlight-color);
border-bottom-color: var(--link-highlight-color);
}
.main .main-header .return-button {
position: absolute;
right: -4rem;
bottom: -1.5rem;
color: #666;
transition: color cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
}
.main .main-header .return-button:hover {
color: var(--text-color);
}
.footer .section {
@@ -130,6 +184,7 @@
justify-content: center;
align-items: center;
flex-wrap: nowrap;
font-family: "Noto Sans SC", sans-serif;
}
.footer .links {

View File

@@ -7,28 +7,47 @@ import {
Outlet,
Link,
NavLink,
useNavigation,
useLocation,
useNavigate,
} from "react-router-dom";
import './root.css'
import routes from '@/routes'
import { TitleContext } from '@/context/useTitleContext';
import { HeaderContext } from '@/context/useHeaderContext';
import { LanguageContext } from '@/context/useLanguageContext';
import Dropdown from '@/component/dropdown';
import Popup from '@/component/popup';
import ReturnButton from '@/component/return_button';
import MainBorder from '@/component/main_border';
export default function Root(props) {
const { title, setTitle } = useContext(TitleContext)
const navigate = useNavigate()
const [drawerHidden, setDrawerHidden] = useState(true)
const {
language, setLanguage,
drawerTextDefaultLang,
drawerAlternateLang,
textDefaultLang,
alternateLang,
i18n
} = useContext(LanguageContext)
const { title, tabs, currentTab, setCurrentTab } = useContext(HeaderContext)
const [drawerDestinations, setDrawerDestinations] = useState(null)
const currentYear = new Date().getFullYear()
const [headerTabs, setHeaderTabs] = useState(null)
const renderHeaderTabs = (tabs) => {
setHeaderTabs(tabs?.map((item) => {
return (
<section
key={item.key}
className={`main-tab-item ${currentTab === item.key ? 'active' : ''}`}
onClick={(e) => {
setCurrentTab(item.key)
item.onClick && item.onClick(e, item.key)
}}
>
{item.text[language]}
</section>
)
}))
}
const toggleDrawer = () => {
setDrawerHidden(!drawerHidden)
@@ -38,25 +57,34 @@ export default function Root(props) {
return routes.filter((item) => item.inDrawer).map((item) => {
if (typeof item.element.type === 'string') {
return (
<a key={item.name}
href={item.path}
target="_blank">
<Link reloadDocument
key={item.name}
to={item.path}
target="_blank"
className="link"
onClick={() => toggleDrawer()}
>
<section>
{i18n.key[item.name][drawerTextDefaultLang]}
{i18n.key[item.name][textDefaultLang]}
</section>
<section>
{i18n.key[item.name][drawerAlternateLang]}
{i18n.key[item.name][alternateLang]}
</section>
</a>
</Link>
)
} else {
return (
<NavLink to={item.path} key={item.name}>
<NavLink
to={item.path}
key={item.name}
className="link"
onClick={() => toggleDrawer()}
>
<section>
{i18n.key[item.name][drawerTextDefaultLang]}
{i18n.key[item.name][textDefaultLang]}
</section>
<section>
{i18n.key[item.name][drawerAlternateLang]}
{i18n.key[item.name][alternateLang]}
</section>
</NavLink>
)
@@ -66,7 +94,11 @@ export default function Root(props) {
useEffect(() => {
setDrawerDestinations(renderDrawerDestinations())
}, [drawerAlternateLang])
}, [alternateLang])
useEffect(() => {
renderHeaderTabs(tabs)
}, [tabs, currentTab, language])
return (
<>
@@ -104,21 +136,33 @@ export default function Root(props) {
/>
</nav>
<main className='main'>
<section>
<section>{title}</section>
<section>
{/* <NavLink to="/home">All</NavLink>
<NavLink to="/about">Operator</NavLink>
<NavLink to="/contact">Skill</NavLink> */}
<section className='main-header'>
<section className='main-title'>{title}</section>
<section className='main-tab'>
{headerTabs}
</section>
<ReturnButton
className='return-button'
onClick={() => {
navigate("/")
}}
/>
</section>
<MainBorder />
<Outlet />
</main>
<footer className='footer'>
<section className='links section'>
<a href="https://privacy.halyul.dev" target="_blank" className='item'>{i18n.key.privacy_policy[language]}</a>
<Popup
className='item'
title={i18n.key.disclaimer[language]}
>
{i18n.key.disclaimer_content[language]}
</Popup>
<span className='separator' />
<a href="https://github.com/Halyul/aklive2d" target="_blank" className='item'>Github</a>
<Link reloadDocument to="https://privacy.halyul.dev" target="_blank" className='item'>{i18n.key.privacy_policy[language]}</Link>
<span className='separator' />
<Link reloadDocument to="https://github.com/Halyul/aklive2d" target="_blank" className='item'>Github</Link>
<span className='separator'/>
<Popup
className='item'
@@ -128,9 +172,9 @@ export default function Root(props) {
</Popup>
</section>
<section className='copyright section'>
<span>Spine Runtimes © 2013 - 2019, Esoteric Software LLC</span>
<span>Assets © 2017 - 2023 上海鹰角网络科技有限公司</span>
<span>Source Code © 2021 - 2023 Halyul</span>
<span>Spine Runtimes © 2013 - 2019 Esoteric Software LLC</span>
<span>Assets © 2017 - {currentYear} Arknights/Hypergryph Co., Ltd</span>
<span>Source Code © 2021 - {currentYear} Halyul</span>
</section>
</footer>
</>