feat(directory): add voice

This commit is contained in:
Haoyu Xu
2023-02-27 16:34:36 -05:00
parent 00e6916ad1
commit 0a320e1eb0
19 changed files with 399 additions and 123 deletions

View File

@@ -1 +1 @@
3.3.7 3.3.10

View File

@@ -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

View File

@@ -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

View File

@@ -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
View File

@@ -0,0 +1 @@
0.5.6

View File

@@ -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);

View File

@@ -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);
} }

View File

@@ -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 (

View 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;
}

View 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>
)
}

View File

@@ -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>

View File

@@ -3,57 +3,65 @@
"zh-CN", "en-US" "zh-CN", "en-US"
], ],
"key": { "key": {
"dynamic_compile": { "dynamic_compile": {
"zh-CN": "干员动态集录", "zh-CN": "动态集录",
"en-US": "Dynamic Compile" "en-US": "Dynamic Compile"
}, },
"home": { "home": {
"zh-CN": "首页", "zh-CN": "首页",
"en-US": "Home" "en-US": "Home"
}, },
"changelogs": { "changelogs": {
"zh-CN": "更新日志", "zh-CN": "更新日志",
"en-US": "Changelogs" "en-US": "Changelogs"
}, },
"offical_page": { "offical_page": {
"zh-CN": "官方页面", "zh-CN": "官方页面",
"en-US": "Offical Page" "en-US": "Offical Page"
}, },
"disclaimer": { "disclaimer": {
"zh-CN": "免责声明", "zh-CN": "免责声明",
"en-US": "Disclaimer" "en-US": "Disclaimer"
}, },
"disclaimer_content": { "disclaimer_content": {
"zh-CN": "本网站由 Halyul 设立并为明日方舟社区服务Halyul 声明本网站完全独立运营,与 上海鹰角网络科技有限公司, Esoteric Software LLC 或其任何关联实体并无任何联系。", "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." "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": { "privacy_policy": {
"zh-CN": "隐私政策", "zh-CN": "隐私政策",
"en-US": "Privacy Policy" "en-US": "Privacy Policy"
}, },
"contact_us": { "contact_us": {
"zh-CN": "联系我们", "zh-CN": "联系我们",
"en-US": "Contact Us" "en-US": "Contact Us"
}, },
"all": { "all": {
"zh-CN": "综合", "zh-CN": "综合",
"en-US": "All" "en-US": "All"
}, },
"elite2": { "elite2": {
"zh-CN": "干员晋升", "zh-CN": "干员晋升",
"en-US": "Elite 2" "en-US": "Elite 2"
}, },
"skin": { "skin": {
"zh-CN": "干员时装", "zh-CN": "干员时装",
"en-US": "Skin" "en-US": "Skin"
}, },
"zh-CN": { "voice": {
"zh-CN": "简体中文", "zh-CN": "语音",
"en-US": "Chinese (Simplified)" "en-US": "Voice"
}, },
"en-US": { "live2d": {
"zh-CN": "英语", "zh-CN": "Live2D",
"en-US": "English" "en-US": "Live2D"
} },
"zh-CN": {
"zh-CN": "简体中文",
"en-US": "Chinese (Simplified)"
},
"en-US": {
"zh-CN": "英语",
"en-US": "English"
}
} }
} }

View File

@@ -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 {
@@ -41,7 +42,7 @@
transition: all cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s; transition: all cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
} }
.home .item-group .item .item-outline{ .home .item-group .item .item-outline {
width: 100%; width: 100%;
height: 100%; height: 100%;
left: -6px; left: -6px;
@@ -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)
} }

View File

@@ -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,31 +163,44 @@ 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 (
<section className="item-background-filler" /> <Link
<section className="item-outline" /> reloadDocument
<section className="item-img"> to={`/${item.link}`}
<img src={`/${item.link}/assets/${item.fallback_name.replace("#", "%23")}_portrait.png`} alt={item.codename[language]} /> className="item"
</section> key={item.link}
<section className="item-info"> hidden={!isShown(item.type)}
<section className="item-title-container"> onMouseEnter={(e) => playVoice(item.link)}
<section className="item-title">{item.codename[language]}</section> >
<section className="item-type"> <section className="item-background-filler" />
<CharIcon <section className="item-outline" />
type={item.type} <section className="item-img">
viewBox={ {live2dOn && item.portrait !== null ? (
item.type === 'operator' ? '0 0 88.969 71.469' : '0 0 94.563 67.437' getLive2d(item.link)
} /> ) : (
<img src={`/${item.link}/assets/${item.fallback_name.replace("#", "%23")}_portrait.png`} alt={item.codename[language]} />
)}
</section>
<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>
<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> </section>
<section className="item-text-wrapper"> </Link>
<span className='item-text'>{item.codename[language.startsWith("en") ? alternateLang : textDefaultLang]}</span> )
</section>
<section className="item-info-background" style={{
color: item.color
}} />
</section>
</Link>)
})} })}
<section className='item-group-date'>{v[0].date}</section> <section className='item-group-date'>{v[0].date}</section>
</section> </section>

View File

@@ -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;
} }
} }

View File

@@ -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>
</> </>

View File

@@ -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
View File

@@ -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'}

View File

@@ -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)