feat(directory): add voice
This commit is contained in:
11
aklive2d.js
11
aklive2d.js
@@ -5,20 +5,18 @@ import { fork } from 'child_process';
|
|||||||
import getConfig from './libs/config.js'
|
import getConfig from './libs/config.js'
|
||||||
import ProjectJson from './libs/project_json.js'
|
import ProjectJson from './libs/project_json.js'
|
||||||
import EnvGenerator from './libs/env_generator.js'
|
import EnvGenerator from './libs/env_generator.js'
|
||||||
import { write, rmdir, copy, writeSync, copyDir, readSync } from './libs/file.js'
|
import { write, rmdir, copy, writeSync, copyDir } from './libs/file.js'
|
||||||
import AssetsProcessor from './libs/assets_processor.js'
|
import AssetsProcessor from './libs/assets_processor.js'
|
||||||
import init from './libs/initializer.js'
|
import init from './libs/initializer.js'
|
||||||
import directory from './libs/directory.js'
|
import directory from './libs/directory.js'
|
||||||
import { appendReadme } from './libs/append.js'
|
import { appendReadme } from './libs/append.js'
|
||||||
|
import { increase } from './libs/version.js';
|
||||||
import Background from './libs/background.js'
|
import Background from './libs/background.js'
|
||||||
import CharwordTable from './libs/charword_table.js';
|
import CharwordTable from './libs/charword_table.js';
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
global.__projetRoot = path.dirname(fileURLToPath(import.meta.url))
|
global.__projetRoot = path.dirname(fileURLToPath(import.meta.url))
|
||||||
global.__config = {
|
global.__config = getConfig()
|
||||||
...getConfig(),
|
|
||||||
version: readSync(path.join(__projetRoot, 'Version'))
|
|
||||||
}
|
|
||||||
|
|
||||||
const op = process.argv[2]
|
const op = process.argv[2]
|
||||||
let OPERATOR_NAMES = process.argv.slice(3);
|
let OPERATOR_NAMES = process.argv.slice(3);
|
||||||
@@ -39,6 +37,7 @@ async function main() {
|
|||||||
for (const [key, _] of Object.entries(__config.operators)) {
|
for (const [key, _] of Object.entries(__config.operators)) {
|
||||||
OPERATOR_NAMES.push(key)
|
OPERATOR_NAMES.push(key)
|
||||||
}
|
}
|
||||||
|
increase(__projetRoot)
|
||||||
break
|
break
|
||||||
case 'preview':
|
case 'preview':
|
||||||
assert(OPERATOR_NAMES.length !== 0, 'Please set the operator name.')
|
assert(OPERATOR_NAMES.length !== 0, 'Please set the operator name.')
|
||||||
@@ -176,7 +175,7 @@ async function main() {
|
|||||||
value: __config.operators[OPERATOR_NAME].link
|
value: __config.operators[OPERATOR_NAME].link
|
||||||
}, {
|
}, {
|
||||||
key: "version",
|
key: "version",
|
||||||
value: __config.version
|
value: __config.version.showcase
|
||||||
}, {
|
}, {
|
||||||
key: "title",
|
key: "title",
|
||||||
value: __config.operators[OPERATOR_NAME].title
|
value: __config.operators[OPERATOR_NAME].title
|
||||||
|
|||||||
@@ -21,6 +21,9 @@ share:
|
|||||||
title:
|
title:
|
||||||
zh-CN: "明日方舟:"
|
zh-CN: "明日方舟:"
|
||||||
en-US: "Arknights: "
|
en-US: "Arknights: "
|
||||||
|
directory:
|
||||||
|
title: AKLive2D
|
||||||
|
voice: jp/CN_037.ogg
|
||||||
operators:
|
operators:
|
||||||
chen: !include config/chen.yaml
|
chen: !include config/chen.yaml
|
||||||
dusk: !include config/dusk.yaml
|
dusk: !include config/dusk.yaml
|
||||||
|
|||||||
@@ -1 +1,3 @@
|
|||||||
VITE_APP_TITLE="AKLive2D"
|
VITE_APP_TITLE=AKLive2D
|
||||||
|
VITE_VERSION=0.5.5
|
||||||
|
VITE_APP_VOICE_URL=jp/CN_037.ogg
|
||||||
1
directory/Version
Normal file
1
directory/Version
Normal file
@@ -0,0 +1 @@
|
|||||||
|
0.5.6
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
:root {
|
:root {
|
||||||
--text-color: rgba(255, 255, 255, 0.87);
|
--text-color: rgba(255, 255, 255, 0.87);
|
||||||
|
--text-color-full: #fff;
|
||||||
--secondary-text-color: #686a72;
|
--secondary-text-color: #686a72;
|
||||||
--date-color: rgba(255, 255, 255, 0.2);
|
--date-color: rgba(255, 255, 255, 0.2);
|
||||||
--border-color: #707070;
|
--border-color: #707070;
|
||||||
@@ -17,7 +18,7 @@
|
|||||||
|
|
||||||
font-family: "Geometos", "Noto Sans SC", sans-serif;
|
font-family: "Geometos", "Noto Sans SC", sans-serif;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 1.1em;
|
line-height: 1.2em;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
|
|
||||||
color: var(--text-color);
|
color: var(--text-color);
|
||||||
|
|||||||
@@ -4,13 +4,13 @@
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown .text {
|
.dropdown .text {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown .content {
|
.dropdown .content {
|
||||||
@@ -18,6 +18,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dropdown .icon {
|
.dropdown .icon {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0.5rem;
|
||||||
|
right: -0.1rem;
|
||||||
width: 0.5em;
|
width: 0.5em;
|
||||||
height: 0.5em;
|
height: 0.5em;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -27,10 +30,10 @@
|
|||||||
border-right: 0.15em solid var(--text-color);
|
border-right: 0.15em solid var(--text-color);
|
||||||
border-top: 0.15em solid var(--text-color);
|
border-top: 0.15em solid var(--text-color);
|
||||||
transform: translate(0, -0.15em) rotate(-45deg);
|
transform: translate(0, -0.15em) rotate(-45deg);
|
||||||
transition: all cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown .icon.active {
|
.dropdown.active .icon,
|
||||||
|
.dropdown:hover .icon {
|
||||||
animation: icon-flash 2s cubic-bezier(0.65, 0.05, 0.36, 1) infinite;
|
animation: icon-flash 2s cubic-bezier(0.65, 0.05, 0.36, 1) infinite;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +58,7 @@
|
|||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown .menu.active {
|
.dropdown.active .menu {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
@@ -76,7 +79,9 @@
|
|||||||
transition: color cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
|
transition: color cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown .menu .item:hover, .dropdown .menu .item:focus, .dropdown .menu .item.active {
|
.dropdown .menu .item:hover,
|
||||||
|
.dropdown .menu .item:focus,
|
||||||
|
.dropdown .menu .item.active {
|
||||||
color: var(--link-highlight-color);
|
color: var(--link-highlight-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
useState,
|
useState
|
||||||
useEffect
|
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import './dropdown.css'
|
import './dropdown.css'
|
||||||
|
|
||||||
@@ -13,15 +12,15 @@ export default function Dropdown(props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<section className='dropdown'>
|
<section className={`dropdown ${hidden ? '' : 'active'}`} >
|
||||||
<section
|
<section
|
||||||
className='text'
|
className='text'
|
||||||
onClick={() => toggleDropdown()}
|
onClick={() => toggleDropdown()}
|
||||||
>
|
>
|
||||||
<span className='content'>{props.text}</span>
|
<span className='content'>{props.text}</span>
|
||||||
<span className={`icon ${hidden ? '' : 'active'}`}></span>
|
<span className='icon'></span>
|
||||||
</section>
|
</section>
|
||||||
<ul className={`menu ${hidden ? '' : 'active'}`}>
|
<ul className='menu'>
|
||||||
{
|
{
|
||||||
props.menu.map((item) => {
|
props.menu.map((item) => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
62
directory/src/component/switch.css
Normal file
62
directory/src/component/switch.css
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
.switch {
|
||||||
|
position: relative;
|
||||||
|
user-select: none;
|
||||||
|
z-index: 2;
|
||||||
|
padding: 8px 36px 8px 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
transition: color cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch.active {
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch .content {
|
||||||
|
padding-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch .icon-wrapper {
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
transition: all cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch.active .icon-wrapper {
|
||||||
|
color: var(--text-color-full);
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch .icon {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 8px;
|
||||||
|
right: 18px;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
border-left: 2px solid currentColor;
|
||||||
|
border-bottom: 2px solid currentColor;
|
||||||
|
border-right: 2px solid currentColor;
|
||||||
|
border-top: 2px solid currentColor;
|
||||||
|
transform: translate(0, -2px) rotate(-45deg);
|
||||||
|
transition: right cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s, background-color cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch.active .icon {
|
||||||
|
background-color: currentColor;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.switch .icon-line {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 15px;
|
||||||
|
right: 6px;
|
||||||
|
width: 18px;
|
||||||
|
height: 2px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-color: currentColor;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
23
directory/src/component/switch.jsx
Normal file
23
directory/src/component/switch.jsx
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import { useState, useEffect } from 'react';
|
||||||
|
import './switch.css';
|
||||||
|
|
||||||
|
export default function Switch(props) {
|
||||||
|
const [on, setOn] = useState(props.on)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setOn(props.on)
|
||||||
|
}, [props.on])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section
|
||||||
|
className={`switch ${on ? 'active' : ''}`}
|
||||||
|
onClick={() => props.handleOnClick()}
|
||||||
|
>
|
||||||
|
<span className='text'>{props.text}</span>
|
||||||
|
<section className='icon-wrapper'>
|
||||||
|
<span className='icon-line'></span>
|
||||||
|
<span className='icon'></span>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -31,7 +31,7 @@ export function HeaderProvider(props) {
|
|||||||
<HeaderContext.Provider value={{
|
<HeaderContext.Provider value={{
|
||||||
title, setTitle,
|
title, setTitle,
|
||||||
tabs, setTabs,
|
tabs, setTabs,
|
||||||
currentTab, setCurrentTab,
|
currentTab, setCurrentTab
|
||||||
}}>
|
}}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</HeaderContext.Provider>
|
</HeaderContext.Provider>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
],
|
],
|
||||||
"key": {
|
"key": {
|
||||||
"dynamic_compile": {
|
"dynamic_compile": {
|
||||||
"zh-CN": "干员动态集录",
|
"zh-CN": "动态集录",
|
||||||
"en-US": "Dynamic Compile"
|
"en-US": "Dynamic Compile"
|
||||||
},
|
},
|
||||||
"home": {
|
"home": {
|
||||||
@@ -47,6 +47,14 @@
|
|||||||
"zh-CN": "干员时装",
|
"zh-CN": "干员时装",
|
||||||
"en-US": "Skin"
|
"en-US": "Skin"
|
||||||
},
|
},
|
||||||
|
"voice": {
|
||||||
|
"zh-CN": "语音",
|
||||||
|
"en-US": "Voice"
|
||||||
|
},
|
||||||
|
"live2d": {
|
||||||
|
"zh-CN": "Live2D",
|
||||||
|
"en-US": "Live2D"
|
||||||
|
},
|
||||||
"zh-CN": {
|
"zh-CN": {
|
||||||
"zh-CN": "简体中文",
|
"zh-CN": "简体中文",
|
||||||
"en-US": "Chinese (Simplified)"
|
"en-US": "Chinese (Simplified)"
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
letter-spacing: 0.1rem;
|
letter-spacing: 0.1rem;
|
||||||
flex: auto;
|
flex: auto;
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home .item-group .item {
|
.home .item-group .item {
|
||||||
@@ -86,11 +87,17 @@
|
|||||||
background-color: var(--home-item-hover-background-color);
|
background-color: var(--home-item-hover-background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.home .item-group .item .item-img .live2d {
|
||||||
|
width: 100%;
|
||||||
|
height: 360px;
|
||||||
|
}
|
||||||
|
|
||||||
.home .item-group .item .item-info {
|
.home .item-group .item .item-info {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding: 0.8rem 0.4rem;
|
padding: 0.8rem 0.4rem;
|
||||||
line-height: 1;
|
line-height: 1.2em;
|
||||||
|
height: 36px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home .item-group .item .item-info .item-title-container {
|
.home .item-group .item .item-info .item-title-container {
|
||||||
@@ -109,11 +116,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.home .item-group .item .item-info .item-title-container .item-title {
|
.home .item-group .item .item-info .item-title-container .item-title {
|
||||||
line-height: 1.1em;
|
line-height: 1.3em;
|
||||||
height: 1.25rem;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.home .item-group .item .item-info .item-title-container .item-type {
|
.home .item-group .item .item-info .item-title-container .item-type {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: baseline;
|
||||||
|
text-align: center;
|
||||||
width: 1.5rem;
|
width: 1.5rem;
|
||||||
fill: var(--text-color)
|
fill: var(--text-color)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
useEffect,
|
useEffect,
|
||||||
useContext,
|
useContext,
|
||||||
useMemo
|
useRef
|
||||||
} from 'react'
|
} from 'react'
|
||||||
import {
|
import {
|
||||||
Link,
|
Link,
|
||||||
|
useOutletContext,
|
||||||
} from "react-router-dom";
|
} from "react-router-dom";
|
||||||
import './home.css'
|
import './home.css'
|
||||||
import { ConfigContext } from '@/context/useConfigContext';
|
import { ConfigContext } from '@/context/useConfigContext';
|
||||||
@@ -13,14 +14,19 @@ import { LanguageContext } from '@/context/useLanguageContext';
|
|||||||
import { HeaderContext } from '@/context/useHeaderContext';
|
import { HeaderContext } from '@/context/useHeaderContext';
|
||||||
import CharIcon from '@/component/char_icon';
|
import CharIcon from '@/component/char_icon';
|
||||||
import MainBorder from '@/component/main_border';
|
import MainBorder from '@/component/main_border';
|
||||||
import useUmami from '@parcellab/react-use-umami'
|
import useUmami from '@parcellab/react-use-umami';
|
||||||
|
import Switch from '@/component/switch';
|
||||||
|
import spine from '!/libs/spine-player';
|
||||||
|
import '!/libs/spine-player.css';
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const _trackEvt = useUmami('/')
|
const _trackEvt = useUmami('/')
|
||||||
|
const { setAppbarExtraArea } = useOutletContext()
|
||||||
const {
|
const {
|
||||||
setTitle,
|
setTitle,
|
||||||
tabs, setTabs,
|
setTabs,
|
||||||
currentTab, setCurrentTab } = useContext(HeaderContext)
|
currentTab, setCurrentTab
|
||||||
|
} = useContext(HeaderContext)
|
||||||
const { config } = useContext(ConfigContext)
|
const { config } = useContext(ConfigContext)
|
||||||
const {
|
const {
|
||||||
language,
|
language,
|
||||||
@@ -29,6 +35,12 @@ export default function Home() {
|
|||||||
i18n
|
i18n
|
||||||
} = useContext(LanguageContext)
|
} = useContext(LanguageContext)
|
||||||
const [content, setContent] = useState([])
|
const [content, setContent] = useState([])
|
||||||
|
const [voiceOn, setVoiceOn] = useState(false)
|
||||||
|
const [live2dOn, setLive2dOn] = useState(false)
|
||||||
|
const [audioUrl, setAudioUrl] = useState('')
|
||||||
|
const audioEl = new Audio(audioUrl)
|
||||||
|
const live2dRefObject = useRef({})
|
||||||
|
const live2dSpineObject = useRef({})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTitle('dynamic_compile')
|
setTitle('dynamic_compile')
|
||||||
@@ -48,20 +60,100 @@ export default function Home() {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const value = config.reduce((acc, cur) => {
|
setContent(config?.operators || [])
|
||||||
const date = cur.date
|
|
||||||
if (acc[date]) {
|
|
||||||
acc[date].push(cur)
|
|
||||||
} else {
|
|
||||||
acc[date] = [cur]
|
|
||||||
}
|
|
||||||
return acc
|
|
||||||
}, {})
|
|
||||||
setContent(Object.values(value).sort((a, b) => new Date(b[0].date) - new Date(a[0].date)))
|
|
||||||
}, [config])
|
}, [config])
|
||||||
|
|
||||||
|
const toggleVoice = () => {
|
||||||
|
setVoiceOn(!voiceOn)
|
||||||
|
setAudioUrl('')
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setAppbarExtraArea([
|
||||||
|
(
|
||||||
|
<Switch
|
||||||
|
key="voice"
|
||||||
|
text={i18n.key.voice[language]}
|
||||||
|
on={voiceOn}
|
||||||
|
handleOnClick={() => toggleVoice()}
|
||||||
|
/>
|
||||||
|
// ), (
|
||||||
|
// <Switch
|
||||||
|
// key="live2d"
|
||||||
|
// text={i18n.key.live2d[language]}
|
||||||
|
// on={live2dOn}
|
||||||
|
// handleOnClick={() => setLive2dOn(!live2dOn)}
|
||||||
|
// />
|
||||||
|
)
|
||||||
|
])
|
||||||
|
}, [voiceOn, live2dOn])
|
||||||
|
|
||||||
const isShown = (type) => currentTab === 'all' || currentTab === type
|
const isShown = (type) => currentTab === 'all' || currentTab === type
|
||||||
|
|
||||||
|
const playVoice = (link) => {
|
||||||
|
if (!voiceOn) return
|
||||||
|
audioEl.src = `/${link}/assets/voice/${import.meta.env.VITE_APP_VOICE_URL}`
|
||||||
|
let startPlayPromise = audioEl.play()
|
||||||
|
if (startPlayPromise !== undefined) {
|
||||||
|
startPlayPromise
|
||||||
|
.then(() => {
|
||||||
|
return
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
return
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getLive2d = (link) => {
|
||||||
|
const reactEl = <section className="live2d" ref={ref => {
|
||||||
|
live2dRefObject.current[link] = ref
|
||||||
|
}}></section>
|
||||||
|
return reactEl
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (live2dOn) {
|
||||||
|
Object.keys(live2dRefObject.current).forEach((link) => {
|
||||||
|
const ref = live2dRefObject.current[link]
|
||||||
|
if (ref) {
|
||||||
|
if (live2dSpineObject.current[link]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fetch(`/_assets/dyn_portrait_char_2014_nian_nian%234.json`)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
live2dSpineObject.current[link] = new spine.SpinePlayer(ref, {
|
||||||
|
skelUrl: `./assets/dyn_portrait_char_2014_nian_nian%234.skel`,
|
||||||
|
atlasUrl: `./assets/dyn_portrait_char_2014_nian_nian%234.atlas`,
|
||||||
|
rawDataURIs: data,
|
||||||
|
animation: "Idle",
|
||||||
|
premultipliedAlpha: true,
|
||||||
|
alpha: true,
|
||||||
|
backgroundColor: "#00000000",
|
||||||
|
viewport: {
|
||||||
|
debugRender: false,
|
||||||
|
padLeft: `0%`,
|
||||||
|
padRight: `0%`,
|
||||||
|
padTop: `0%`,
|
||||||
|
padBottom: `0%`,
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
},
|
||||||
|
showControls: false,
|
||||||
|
touch: false,
|
||||||
|
fps: 60,
|
||||||
|
defaultMix: 0,
|
||||||
|
success: function (widget) {
|
||||||
|
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [live2dOn])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="home">
|
<section className="home">
|
||||||
{
|
{
|
||||||
@@ -71,11 +163,23 @@ export default function Home() {
|
|||||||
<section className="item-group-wrapper" key={v[0].date} hidden={length === 0}>
|
<section className="item-group-wrapper" key={v[0].date} hidden={length === 0}>
|
||||||
<section className="item-group">
|
<section className="item-group">
|
||||||
{v.map(item => {
|
{v.map(item => {
|
||||||
return (<Link reloadDocument to={`/${item.link}`} className="item" key={item.link} hidden={!isShown(item.type)}>
|
return (
|
||||||
|
<Link
|
||||||
|
reloadDocument
|
||||||
|
to={`/${item.link}`}
|
||||||
|
className="item"
|
||||||
|
key={item.link}
|
||||||
|
hidden={!isShown(item.type)}
|
||||||
|
onMouseEnter={(e) => playVoice(item.link)}
|
||||||
|
>
|
||||||
<section className="item-background-filler" />
|
<section className="item-background-filler" />
|
||||||
<section className="item-outline" />
|
<section className="item-outline" />
|
||||||
<section className="item-img">
|
<section className="item-img">
|
||||||
|
{live2dOn && item.portrait !== null ? (
|
||||||
|
getLive2d(item.link)
|
||||||
|
) : (
|
||||||
<img src={`/${item.link}/assets/${item.fallback_name.replace("#", "%23")}_portrait.png`} alt={item.codename[language]} />
|
<img src={`/${item.link}/assets/${item.fallback_name.replace("#", "%23")}_portrait.png`} alt={item.codename[language]} />
|
||||||
|
)}
|
||||||
</section>
|
</section>
|
||||||
<section className="item-info">
|
<section className="item-info">
|
||||||
<section className="item-title-container">
|
<section className="item-title-container">
|
||||||
@@ -95,7 +199,8 @@ export default function Home() {
|
|||||||
color: item.color
|
color: item.color
|
||||||
}} />
|
}} />
|
||||||
</section>
|
</section>
|
||||||
</Link>)
|
</Link>
|
||||||
|
)
|
||||||
})}
|
})}
|
||||||
<section className='item-group-date'>{v[0].date}</section>
|
<section className='item-group-date'>{v[0].date}</section>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -25,6 +25,10 @@
|
|||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.header .spacer {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.header .dropdown {
|
.header .dropdown {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
@@ -140,7 +144,7 @@
|
|||||||
font-size: 3rem;
|
font-size: 3rem;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
line-height: 1.1em;
|
line-height: 1.2em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main .main-header .main-tab {
|
.main .main-header .main-tab {
|
||||||
@@ -174,7 +178,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
.main .main-header .return-button {
|
.main .return-button {
|
||||||
right: -3.4rem;
|
right: -3.4rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,10 +27,15 @@ export default function Root(props) {
|
|||||||
alternateLang,
|
alternateLang,
|
||||||
i18n
|
i18n
|
||||||
} = useContext(LanguageContext)
|
} = useContext(LanguageContext)
|
||||||
const { title, tabs, currentTab, setCurrentTab } = useContext(HeaderContext)
|
const {
|
||||||
|
title,
|
||||||
|
tabs,
|
||||||
|
currentTab, setCurrentTab
|
||||||
|
} = useContext(HeaderContext)
|
||||||
const [drawerDestinations, setDrawerDestinations] = useState(null)
|
const [drawerDestinations, setDrawerDestinations] = useState(null)
|
||||||
const currentYear = new Date().getFullYear()
|
const currentYear = new Date().getFullYear()
|
||||||
const [headerTabs, setHeaderTabs] = useState(null)
|
const [headerTabs, setHeaderTabs] = useState(null)
|
||||||
|
const [appbarExtraArea, setAppbarExtraArea] = useState(null)
|
||||||
|
|
||||||
const renderHeaderTabs = (tabs) => {
|
const renderHeaderTabs = (tabs) => {
|
||||||
setHeaderTabs(tabs?.map((item) => {
|
setHeaderTabs(tabs?.map((item) => {
|
||||||
@@ -111,6 +116,8 @@ export default function Root(props) {
|
|||||||
<section className='bar'></section>
|
<section className='bar'></section>
|
||||||
<section className='bar'></section>
|
<section className='bar'></section>
|
||||||
</section>
|
</section>
|
||||||
|
<section className='spacer' />
|
||||||
|
{appbarExtraArea}
|
||||||
<Dropdown
|
<Dropdown
|
||||||
text={i18n.key[language][language]}
|
text={i18n.key[language][language]}
|
||||||
menu={i18n.available.map((item) => {
|
menu={i18n.available.map((item) => {
|
||||||
@@ -150,7 +157,7 @@ export default function Root(props) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</MainBorder>
|
</MainBorder>
|
||||||
<Outlet />
|
<Outlet context={{setAppbarExtraArea}}/>
|
||||||
</main>
|
</main>
|
||||||
<footer className='footer'>
|
<footer className='footer'>
|
||||||
<section className='links section'>
|
<section className='links section'>
|
||||||
@@ -176,6 +183,7 @@ export default function Root(props) {
|
|||||||
<span>Spine Runtimes © 2013 - 2019 Esoteric Software LLC</span>
|
<span>Spine Runtimes © 2013 - 2019 Esoteric Software LLC</span>
|
||||||
<span>Assets © 2017 - {currentYear} Arknights/Hypergryph Co., Ltd</span>
|
<span>Assets © 2017 - {currentYear} Arknights/Hypergryph Co., Ltd</span>
|
||||||
<span>Source Code © 2021 - {currentYear} Halyul</span>
|
<span>Source Code © 2021 - {currentYear} Halyul</span>
|
||||||
|
<span>Version: {import.meta.env.VITE_APP_VERSION}</span>
|
||||||
</section>
|
</section>
|
||||||
</footer>
|
</footer>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@parcellab/react-use-umami": "^2.0.1",
|
"@parcellab/react-use-umami": "^2.0.1",
|
||||||
|
"@react-hook/cache": "^1.1.1",
|
||||||
"dotenv": "^16.0.3",
|
"dotenv": "^16.0.3",
|
||||||
"node-fetch": "^3.3.0",
|
"node-fetch": "^3.3.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
|||||||
19
pnpm-lock.yaml
generated
19
pnpm-lock.yaml
generated
@@ -2,6 +2,7 @@ lockfileVersion: 5.4
|
|||||||
|
|
||||||
specifiers:
|
specifiers:
|
||||||
'@parcellab/react-use-umami': ^2.0.1
|
'@parcellab/react-use-umami': ^2.0.1
|
||||||
|
'@react-hook/cache': ^1.1.1
|
||||||
'@types/react': ^18.0.28
|
'@types/react': ^18.0.28
|
||||||
'@types/react-dom': ^18.0.11
|
'@types/react-dom': ^18.0.11
|
||||||
'@vitejs/plugin-react-swc': ^3.2.0
|
'@vitejs/plugin-react-swc': ^3.2.0
|
||||||
@@ -18,6 +19,7 @@ specifiers:
|
|||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
'@parcellab/react-use-umami': 2.0.1_react@18.2.0
|
'@parcellab/react-use-umami': 2.0.1_react@18.2.0
|
||||||
|
'@react-hook/cache': 1.1.1_react@18.2.0
|
||||||
dotenv: 16.0.3
|
dotenv: 16.0.3
|
||||||
node-fetch: 3.3.0
|
node-fetch: 3.3.0
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
@@ -242,6 +244,23 @@ packages:
|
|||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/@react-hook/cache/1.1.1_react@18.2.0:
|
||||||
|
resolution: {integrity: sha512-FY0Bwvxsv9Gu6pUbVdNylh4jyWPtQRegQM9G6yVx3l2cYjbxzaJwEXticLfsRcciCbnk7iyZfJn6mZ4N4+q9qA==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16.8'
|
||||||
|
dependencies:
|
||||||
|
'@react-hook/latest': 1.0.3_react@18.2.0
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/@react-hook/latest/1.0.3_react@18.2.0:
|
||||||
|
resolution: {integrity: sha512-dy6duzl+JnAZcDbNTfmaP3xHiKtbXYOaz3G51MGVljh548Y8MWzTr+PHLOfvpypEVW9zwvl+VyKjbWKEVbV1Rg==}
|
||||||
|
peerDependencies:
|
||||||
|
react: '>=16.8'
|
||||||
|
dependencies:
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@remix-run/router/1.3.2:
|
/@remix-run/router/1.3.2:
|
||||||
resolution: {integrity: sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA==}
|
resolution: {integrity: sha512-t54ONhl/h75X94SWsHGQ4G/ZrCEguKSRQr7DrjTciJXW0YU1QhlwYeycvK5JgkzlxmvrK7wq1NB/PLtHxoiDcA==}
|
||||||
engines: {node: '>=14'}
|
engines: {node: '>=14'}
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import { defineConfig } from 'vite'
|
|||||||
import assert from 'assert'
|
import assert from 'assert'
|
||||||
import react from '@vitejs/plugin-react-swc'
|
import react from '@vitejs/plugin-react-swc'
|
||||||
import getConfig from './libs/config.js'
|
import getConfig from './libs/config.js'
|
||||||
import { rmdir } from './libs/file.js'
|
import { rmdir, writeSync } from './libs/file.js'
|
||||||
|
import { increase } from './libs/version.js'
|
||||||
|
import EnvGenerator from './libs/env_generator.js'
|
||||||
|
|
||||||
global.__projetRoot = path.dirname(fileURLToPath(import.meta.url))
|
global.__projetRoot = path.dirname(fileURLToPath(import.meta.url))
|
||||||
|
|
||||||
@@ -28,7 +30,10 @@ class ViteRunner {
|
|||||||
this.#mode = temp[0] === "vite" ? temp[1] : process.argv[2]
|
this.#mode = temp[0] === "vite" ? temp[1] : process.argv[2]
|
||||||
switch (this.#mode) {
|
switch (this.#mode) {
|
||||||
case 'directory':
|
case 'directory':
|
||||||
result = this.#directoryConfig
|
result = {
|
||||||
|
data: this.#directoryConfig,
|
||||||
|
versionDir: path.join(__projetRoot, "directory"),
|
||||||
|
}
|
||||||
const op = temp[2] || process.argv[3]
|
const op = temp[2] || process.argv[3]
|
||||||
if (op !== 'preview') {
|
if (op !== 'preview') {
|
||||||
rmdir(path.resolve(__projetRoot, this.#globalConfig.folder.release, "_directory"))
|
rmdir(path.resolve(__projetRoot, this.#globalConfig.folder.release, "_directory"))
|
||||||
@@ -39,7 +44,10 @@ class ViteRunner {
|
|||||||
case 'build':
|
case 'build':
|
||||||
case 'build-all':
|
case 'build-all':
|
||||||
case 'preview':
|
case 'preview':
|
||||||
result = this.#operatorConfig
|
result = {
|
||||||
|
data: this.#operatorConfig,
|
||||||
|
versionDir: path.join(__projetRoot),
|
||||||
|
}
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
@@ -48,12 +56,14 @@ class ViteRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
const viteConfig = this.config;
|
const configObj = this.config
|
||||||
|
const viteConfig = configObj.data;
|
||||||
switch (this.#mode) {
|
switch (this.#mode) {
|
||||||
case 'dev':
|
case 'dev':
|
||||||
this.#dev(viteConfig)
|
this.#dev(viteConfig)
|
||||||
break
|
break
|
||||||
case 'build':
|
case 'build':
|
||||||
|
increase(configObj.versionDir)
|
||||||
case 'build-all':
|
case 'build-all':
|
||||||
this.#build(viteConfig)
|
this.#build(viteConfig)
|
||||||
break
|
break
|
||||||
@@ -122,7 +132,22 @@ class ViteRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get #directoryConfig() {
|
get #directoryConfig() {
|
||||||
|
if (process.env.npm_lifecycle_event === 'vite:directory:build') {
|
||||||
|
increase(path.join(__projetRoot, "directory"))
|
||||||
|
}
|
||||||
const directoryDir = path.resolve(__projetRoot, 'directory')
|
const directoryDir = path.resolve(__projetRoot, 'directory')
|
||||||
|
writeSync((new EnvGenerator()).generate([
|
||||||
|
{
|
||||||
|
key: "app_title",
|
||||||
|
value: this.#globalConfig.directory.title
|
||||||
|
}, {
|
||||||
|
key: "version",
|
||||||
|
value: this.#globalConfig.version.directory
|
||||||
|
}, {
|
||||||
|
key: "app_voice_url",
|
||||||
|
value: this.#globalConfig.directory.voice
|
||||||
|
}
|
||||||
|
]), path.join(directoryDir, '.env'))
|
||||||
this.#mode = process.argv[3]
|
this.#mode = process.argv[3]
|
||||||
return {
|
return {
|
||||||
...this.#baseViteConfig,
|
...this.#baseViteConfig,
|
||||||
@@ -136,6 +161,7 @@ class ViteRunner {
|
|||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': path.resolve(directoryDir, './src'),
|
'@': path.resolve(directoryDir, './src'),
|
||||||
|
'!': path.resolve(__projetRoot, './src'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
@@ -151,7 +177,6 @@ class ViteRunner {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
@@ -162,4 +187,4 @@ async function main() {
|
|||||||
|
|
||||||
main()
|
main()
|
||||||
|
|
||||||
export default defineConfig((new ViteRunner()).config)
|
export default defineConfig((new ViteRunner()).config.data)
|
||||||
Reference in New Issue
Block a user