feat(directory): removed portrait and add cache for image and audio
This commit is contained in:
@@ -120,10 +120,7 @@ async function main() {
|
|||||||
|
|
||||||
const assetsProcessor = new AssetsProcessor(OPERATOR_NAME, OPERATOR_SHARE_FOLDER)
|
const assetsProcessor = new AssetsProcessor(OPERATOR_NAME, OPERATOR_SHARE_FOLDER)
|
||||||
assetsProcessor.process(EXTRACTED_FOLDER).then((content) => {
|
assetsProcessor.process(EXTRACTED_FOLDER).then((content) => {
|
||||||
write(JSON.stringify(content.landscape.assetsJson, null), path.join(OPERATOR_SOURCE_FOLDER, OPERATOR_NAME, `assets.json`))
|
write(JSON.stringify(content.assetsJson, null), path.join(OPERATOR_SOURCE_FOLDER, OPERATOR_NAME, `assets.json`))
|
||||||
if (__config.operators[OPERATOR_NAME].portrait) {
|
|
||||||
write(JSON.stringify(content.portrait.assetsJson, null), path.join(OPERATOR_SOURCE_FOLDER, OPERATOR_NAME, `assets_portrait.json`))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const filesToCopy = [
|
const filesToCopy = [
|
||||||
|
|||||||
@@ -11,4 +11,3 @@ color: rgba(14, 126, 239, 0.85)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 假日威龙陈
|
zh-CN: 假日威龙陈
|
||||||
en-US: Ch'en/Chen the Holungday
|
en-US: Ch'en/Chen the Holungday
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgba(14, 126, 239, 0.85)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 假日威龙陈
|
zh-CN: 假日威龙陈
|
||||||
en-US: Ch'en/Chen the Holungday
|
en-US: Ch'en/Chen the Holungday
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(255, 133, 34)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 重岳
|
zh-CN: 重岳
|
||||||
en-US: Chongyue
|
en-US: Chongyue
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(9, 212, 208)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 夕
|
zh-CN: 夕
|
||||||
en-US: Dusk
|
en-US: Dusk
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(78, 201, 187)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 染尘烟 · 夕
|
zh-CN: 染尘烟 · 夕
|
||||||
en-US: Everything is a Miracle / Dusk
|
en-US: Everything is a Miracle / Dusk
|
||||||
portrait: dyn_portrait_char_2015_dusk_nian#7
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(29, 185, 53)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 百练嘉维尔
|
zh-CN: 百练嘉维尔
|
||||||
en-US: Gavial the Invincible
|
en-US: Gavial the Invincible
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(206, 0, 0)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 手到牌来 · 老鲤
|
zh-CN: 手到牌来 · 老鲤
|
||||||
en-US: Trust Your Eyes / Lee
|
en-US: Trust Your Eyes / Lee
|
||||||
portrait: dyn_portrait_char_322_lmlee_witch#3
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(15, 206, 216)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 令
|
zh-CN: 令
|
||||||
en-US: Ling
|
en-US: Ling
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(37, 148, 197)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 濯缨 · 令
|
zh-CN: 濯缨 · 令
|
||||||
en-US: It Does Wash the Strings / Ling
|
en-US: It Does Wash the Strings / Ling
|
||||||
portrait: dyn_portrait_char_2023_ling_nian#9
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(156, 210, 246)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 夏日餮宴 · 水月
|
zh-CN: 夏日餮宴 · 水月
|
||||||
en-US: Summer Feast / Mizuki
|
en-US: Summer Feast / Mizuki
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgba(253, 236, 189, 0.95)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 耀骑士临光
|
zh-CN: 耀骑士临光
|
||||||
en-US: Nearl the Radiant Knight
|
en-US: Nearl the Radiant Knight
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(141, 213, 228)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 复现荣光 · 耀骑士临光
|
zh-CN: 复现荣光 · 耀骑士临光
|
||||||
en-US: Relight / Nearl
|
en-US: Relight / Nearl
|
||||||
portrait: dyn_portrait_char_1014_nearl2_epoque#17
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(255, 48, 0)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 年
|
zh-CN: 年
|
||||||
en-US: Nian
|
en-US: Nian
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(187, 163, 106)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 乐逍遥 · 年
|
zh-CN: 乐逍遥 · 年
|
||||||
en-US: Unfettered Freedom / Nian
|
en-US: Unfettered Freedom / Nian
|
||||||
portrait: dyn_portrait_char_2014_nian_nian#4
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(231, 166, 144)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 今昔须臾之梦 · 异客
|
zh-CN: 今昔须臾之梦 · 异客
|
||||||
en-US: Dream in a Moment / Passager
|
en-US: Dream in a Moment / Passager
|
||||||
portrait: dyn_portrait_char_472_pasngr_epoque#17
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(158, 2, 2)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 焦点 · 傀影
|
zh-CN: 焦点 · 傀影
|
||||||
en-US: Focus / Phatom
|
en-US: Focus / Phatom
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(145, 220, 253)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 字句中的雪原 · 鸿雪
|
zh-CN: 字句中的雪原 · 鸿雪
|
||||||
en-US: Snowy Plains in Words / Позёмка
|
en-US: Snowy Plains in Words / Позёмка
|
||||||
portrait: dyn_portrait_char_4055_bgsnow_wild#7
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(23, 210, 236)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 迷迭香
|
zh-CN: 迷迭香
|
||||||
en-US: Rosmontis
|
en-US: Rosmontis
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(116, 177, 222)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 拥抱新生 · 迷迭香
|
zh-CN: 拥抱新生 · 迷迭香
|
||||||
en-US: Become Anew / Rosmontis
|
en-US: Become Anew / Rosmontis
|
||||||
portrait: dyn_portrait_char_391_rosmon_epoque#17
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(226, 96, 96)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 浊心斯卡蒂
|
zh-CN: 浊心斯卡蒂
|
||||||
en-US: Skadi the Corrupting Heart
|
en-US: Skadi the Corrupting Heart
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgba(95, 116, 187, 0.74)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 升华 · 浊心斯卡蒂
|
zh-CN: 升华 · 浊心斯卡蒂
|
||||||
en-US: Sublimation / Skadi the Corrupting Heart
|
en-US: Sublimation / Skadi the Corrupting Heart
|
||||||
portrait: dyn_portrait_char_1012_skadi2_boc#4
|
|
||||||
@@ -11,4 +11,3 @@ color: rgba(14, 124, 203, 0.86)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 归溟幽灵鲨
|
zh-CN: 归溟幽灵鲨
|
||||||
en-US: Specter the Unchained
|
en-US: Specter the Unchained
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(177, 226, 249)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 缤纷奇境 CW03 · 史尔特尔
|
zh-CN: 缤纷奇境 CW03 · 史尔特尔
|
||||||
en-US: Colorful Wonderland CW03 / Surtr
|
en-US: Colorful Wonderland CW03 / Surtr
|
||||||
portrait: dyn_portrait_char_350_surtr_summer#9
|
|
||||||
@@ -11,4 +11,3 @@ color: rgba(34, 37, 255, 0.9)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 缄默德克萨斯
|
zh-CN: 缄默德克萨斯
|
||||||
en-US: Texas the Omertosa
|
en-US: Texas the Omertosa
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgb(228, 54, 56)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: W
|
zh-CN: W
|
||||||
en-US: W
|
en-US: W
|
||||||
portrait: null
|
|
||||||
@@ -11,4 +11,3 @@ color: rgba(0, 0, 0, 0.83)
|
|||||||
codename:
|
codename:
|
||||||
zh-CN: 恍惚 · W
|
zh-CN: 恍惚 · W
|
||||||
en-US: Wonder / W
|
en-US: Wonder / W
|
||||||
portrait: dyn_portrait_char_113_cqbw_epoque#7
|
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
VITE_APP_TITLE=AKLive2D
|
VITE_APP_TITLE=AKLive2D
|
||||||
VITE_VERSION=0.5.5
|
VITE_VERSION=0.5.7
|
||||||
VITE_APP_VOICE_URL=jp/CN_037.ogg
|
VITE_APP_VOICE_URL=jp/CN_037.ogg
|
||||||
@@ -1 +1 @@
|
|||||||
0.5.6
|
0.5.8
|
||||||
@@ -16,7 +16,8 @@ export function HeaderProvider(props) {
|
|||||||
i18n
|
i18n
|
||||||
} = useContext(LanguageContext)
|
} = useContext(LanguageContext)
|
||||||
const [tabs, setTabs] = useState(null)
|
const [tabs, setTabs] = useState(null)
|
||||||
const [currentTab, setCurrentTab] = useState(null)
|
const [currentTab, setCurrentTab] = useState([])
|
||||||
|
const [appbarExtraArea, setAppbarExtraArea] = useState([])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let newTitle = key
|
let newTitle = key
|
||||||
@@ -31,7 +32,8 @@ export function HeaderProvider(props) {
|
|||||||
<HeaderContext.Provider value={{
|
<HeaderContext.Provider value={{
|
||||||
title, setTitle,
|
title, setTitle,
|
||||||
tabs, setTabs,
|
tabs, setTabs,
|
||||||
currentTab, setCurrentTab
|
currentTab, setCurrentTab,
|
||||||
|
appbarExtraArea, setAppbarExtraArea
|
||||||
}}>
|
}}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</HeaderContext.Provider>
|
</HeaderContext.Provider>
|
||||||
|
|||||||
9
directory/src/db/index.js
Normal file
9
directory/src/db/index.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import Dexie from 'dexie';
|
||||||
|
|
||||||
|
const db = new Dexie('aklive2dDatabase');
|
||||||
|
db.version(2).stores({
|
||||||
|
image: '++key, blob',
|
||||||
|
voice: '++key, blob',
|
||||||
|
});
|
||||||
|
|
||||||
|
export default db;
|
||||||
@@ -51,10 +51,6 @@
|
|||||||
"zh-CN": "语音",
|
"zh-CN": "语音",
|
||||||
"en-US": "Voice"
|
"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)"
|
||||||
|
|||||||
@@ -87,11 +87,6 @@
|
|||||||
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;
|
||||||
|
|||||||
@@ -2,11 +2,10 @@ import {
|
|||||||
useState,
|
useState,
|
||||||
useEffect,
|
useEffect,
|
||||||
useContext,
|
useContext,
|
||||||
useRef
|
useCallback
|
||||||
} 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';
|
||||||
@@ -16,16 +15,17 @@ 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 Switch from '@/component/switch';
|
||||||
import spine from '!/libs/spine-player';
|
import db from '@/db';
|
||||||
import '!/libs/spine-player.css';
|
|
||||||
|
const audioEl = new Audio()
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const _trackEvt = useUmami('/')
|
const _trackEvt = useUmami('/')
|
||||||
const { setAppbarExtraArea } = useOutletContext()
|
|
||||||
const {
|
const {
|
||||||
setTitle,
|
setTitle,
|
||||||
setTabs,
|
setTabs,
|
||||||
currentTab, setCurrentTab
|
currentTab, setCurrentTab,
|
||||||
|
setAppbarExtraArea
|
||||||
} = useContext(HeaderContext)
|
} = useContext(HeaderContext)
|
||||||
const { config } = useContext(ConfigContext)
|
const { config } = useContext(ConfigContext)
|
||||||
const {
|
const {
|
||||||
@@ -36,11 +36,6 @@ export default function Home() {
|
|||||||
} = useContext(LanguageContext)
|
} = useContext(LanguageContext)
|
||||||
const [content, setContent] = useState([])
|
const [content, setContent] = useState([])
|
||||||
const [voiceOn, setVoiceOn] = useState(false)
|
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')
|
||||||
@@ -65,7 +60,6 @@ export default function Home() {
|
|||||||
|
|
||||||
const toggleVoice = () => {
|
const toggleVoice = () => {
|
||||||
setVoiceOn(!voiceOn)
|
setVoiceOn(!voiceOn)
|
||||||
setAudioUrl('')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -77,82 +71,46 @@ export default function Home() {
|
|||||||
on={voiceOn}
|
on={voiceOn}
|
||||||
handleOnClick={() => toggleVoice()}
|
handleOnClick={() => toggleVoice()}
|
||||||
/>
|
/>
|
||||||
// ), (
|
|
||||||
// <Switch
|
|
||||||
// key="live2d"
|
|
||||||
// text={i18n.key.live2d[language]}
|
|
||||||
// on={live2dOn}
|
|
||||||
// handleOnClick={() => setLive2dOn(!live2dOn)}
|
|
||||||
// />
|
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
}, [voiceOn, live2dOn])
|
}, [voiceOn, language])
|
||||||
|
|
||||||
const isShown = (type) => currentTab === 'all' || currentTab === type
|
const isShown = (type) => currentTab === 'all' || currentTab === type
|
||||||
|
|
||||||
const playVoice = (link) => {
|
const playVoice = useCallback((blob) => {
|
||||||
if (!voiceOn) return
|
const audioUrl = URL.createObjectURL(blob)
|
||||||
audioEl.src = `/${link}/assets/voice/${import.meta.env.VITE_APP_VOICE_URL}`
|
audioEl.src = audioUrl
|
||||||
let startPlayPromise = audioEl.play()
|
let startPlayPromise = audioEl.play()
|
||||||
if (startPlayPromise !== undefined) {
|
if (startPlayPromise !== undefined) {
|
||||||
startPlayPromise
|
startPlayPromise
|
||||||
.then(() => {
|
.then(() => {
|
||||||
return
|
const audioEndedFunc = () => {
|
||||||
|
audioEl.removeEventListener('ended', audioEndedFunc)
|
||||||
|
URL.revokeObjectURL(audioUrl)
|
||||||
|
}
|
||||||
|
audioEl.addEventListener('ended', audioEndedFunc)
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}, [])
|
||||||
|
|
||||||
const getLive2d = (link) => {
|
const loadVoice = (link) => {
|
||||||
const reactEl = <section className="live2d" ref={ref => {
|
if (!voiceOn) return
|
||||||
live2dRefObject.current[link] = ref
|
db.voice.get({ key: link }).then((v) => {
|
||||||
}}></section>
|
if (v === undefined) {
|
||||||
return reactEl
|
fetch(`/${link}/assets/voice/${import.meta.env.VITE_APP_VOICE_URL}`)
|
||||||
}
|
.then(res => res.blob())
|
||||||
|
.then(blob => {
|
||||||
useEffect(() => {
|
db.voice.put({ key: link, blob: blob })
|
||||||
if (live2dOn) {
|
playVoice(blob)
|
||||||
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) {
|
|
||||||
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
})
|
} else {
|
||||||
}
|
playVoice(v.blob)
|
||||||
})
|
}
|
||||||
}
|
})
|
||||||
}, [live2dOn])
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="home">
|
<section className="home">
|
||||||
@@ -170,16 +128,15 @@ export default function Home() {
|
|||||||
className="item"
|
className="item"
|
||||||
key={item.link}
|
key={item.link}
|
||||||
hidden={!isShown(item.type)}
|
hidden={!isShown(item.type)}
|
||||||
onMouseEnter={(e) => playVoice(item.link)}
|
onMouseEnter={() => loadVoice(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 ? (
|
<ImageElement
|
||||||
getLive2d(item.link)
|
item={item}
|
||||||
) : (
|
language={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">
|
||||||
@@ -212,3 +169,24 @@ export default function Home() {
|
|||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ImageElement({ item, language }) {
|
||||||
|
const [blobUrl, setBlobUrl] = useState(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
db.image.get({ key: item.link }).then((v) => {
|
||||||
|
if (v === undefined) {
|
||||||
|
fetch(`/${item.link}/assets/${item.fallback_name.replace("#", "%23")}_portrait.png`)
|
||||||
|
.then(res => res.blob())
|
||||||
|
.then(blob => {
|
||||||
|
db.image.put({ key: item.link, blob: blob })
|
||||||
|
setBlobUrl(URL.createObjectURL(blob))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setBlobUrl(URL.createObjectURL(v.blob))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [item.link])
|
||||||
|
|
||||||
|
return blobUrl ? <img src={blobUrl} alt={item.codename[language]} /> : null
|
||||||
|
}
|
||||||
@@ -30,12 +30,12 @@ export default function Root(props) {
|
|||||||
const {
|
const {
|
||||||
title,
|
title,
|
||||||
tabs,
|
tabs,
|
||||||
currentTab, setCurrentTab
|
currentTab, setCurrentTab,
|
||||||
|
appbarExtraArea
|
||||||
} = useContext(HeaderContext)
|
} = 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) => {
|
||||||
@@ -157,7 +157,7 @@ export default function Root(props) {
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</MainBorder>
|
</MainBorder>
|
||||||
<Outlet context={{setAppbarExtraArea}}/>
|
<Outlet />
|
||||||
</main>
|
</main>
|
||||||
<footer className='footer'>
|
<footer className='footer'>
|
||||||
<section className='links section'>
|
<section className='links section'>
|
||||||
@@ -183,7 +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>
|
<span>Version: {import.meta.env.VITE_VERSION}</span>
|
||||||
</section>
|
</section>
|
||||||
</footer>
|
</footer>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -36,10 +36,7 @@ export default class AssetsProcessor {
|
|||||||
const croppedBuffer = await this.#alphaCompositer.crop(portraitBuffer, rect)
|
const croppedBuffer = await this.#alphaCompositer.crop(portraitBuffer, rect)
|
||||||
await write(croppedBuffer, path.join(this.#operatorSourceFolder, this.#operatorName, `${fallback_name}_portrait.png`))
|
await write(croppedBuffer, path.join(this.#operatorSourceFolder, this.#operatorName, `${fallback_name}_portrait.png`))
|
||||||
|
|
||||||
return {
|
return await this.#generateAssets(__config.operators[this.#operatorName].filename, extractedDir)
|
||||||
landscape: await this.#generateAssets(__config.operators[this.#operatorName].filename, extractedDir),
|
|
||||||
portrait: __config.operators[this.#operatorName].portrait ? await this.#generateAssets(__config.operators[this.#operatorName].portrait, extractedDir) : null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async #generateAssets(filename, extractedDir) {
|
async #generateAssets(filename, extractedDir) {
|
||||||
|
|||||||
@@ -28,8 +28,5 @@ export default function () {
|
|||||||
writeSync(JSON.stringify(directoryJson, null), path.join(targetFolder, "directory.json"))
|
writeSync(JSON.stringify(directoryJson, null), path.join(targetFolder, "directory.json"))
|
||||||
filesToCopy.forEach((key) => {
|
filesToCopy.forEach((key) => {
|
||||||
copy(path.join(sourceFolder, key, 'assets.json'), path.join(targetFolder, `${__config.operators[key].filename}.json`))
|
copy(path.join(sourceFolder, key, 'assets.json'), path.join(targetFolder, `${__config.operators[key].filename}.json`))
|
||||||
if (__config.operators[key].portrait) {
|
|
||||||
copy(path.join(sourceFolder, key, 'assets_portrait.json'), path.join(targetFolder, `${__config.operators[key].portrait}.json`))
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@parcellab/react-use-umami": "^2.0.1",
|
"@parcellab/react-use-umami": "^2.0.1",
|
||||||
"@react-hook/cache": "^1.1.1",
|
"dexie": "^3.2.3",
|
||||||
|
"dexie-react-hooks": "^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",
|
||||||
|
|||||||
44
pnpm-lock.yaml
generated
44
pnpm-lock.yaml
generated
@@ -2,10 +2,11 @@ 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
|
||||||
|
dexie: ^3.2.3
|
||||||
|
dexie-react-hooks: ^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,7 +20,8 @@ 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
|
dexie: 3.2.3
|
||||||
|
dexie-react-hooks: 1.1.1_oyoivydq6d62bcmmdhna6akh5q
|
||||||
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
|
||||||
@@ -244,23 +246,6 @@ 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'}
|
||||||
@@ -375,7 +360,6 @@ packages:
|
|||||||
|
|
||||||
/@types/prop-types/15.7.5:
|
/@types/prop-types/15.7.5:
|
||||||
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
|
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@types/react-dom/18.0.11:
|
/@types/react-dom/18.0.11:
|
||||||
resolution: {integrity: sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==}
|
resolution: {integrity: sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw==}
|
||||||
@@ -389,11 +373,9 @@ packages:
|
|||||||
'@types/prop-types': 15.7.5
|
'@types/prop-types': 15.7.5
|
||||||
'@types/scheduler': 0.16.2
|
'@types/scheduler': 0.16.2
|
||||||
csstype: 3.1.1
|
csstype: 3.1.1
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@types/scheduler/0.16.2:
|
/@types/scheduler/0.16.2:
|
||||||
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
|
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@vitejs/plugin-react-swc/3.2.0_vite@4.1.4:
|
/@vitejs/plugin-react-swc/3.2.0_vite@4.1.4:
|
||||||
resolution: {integrity: sha512-IcBoXL/mcH7JdQr/nfDlDwTdIaH8Rg7LpfQDF4nAht+juHWIuv6WhpKPCSfY4+zztAaB07qdBoFz1XCZsgo3pQ==}
|
resolution: {integrity: sha512-IcBoXL/mcH7JdQr/nfDlDwTdIaH8Rg7LpfQDF4nAht+juHWIuv6WhpKPCSfY4+zztAaB07qdBoFz1XCZsgo3pQ==}
|
||||||
@@ -455,7 +437,6 @@ packages:
|
|||||||
|
|
||||||
/csstype/3.1.1:
|
/csstype/3.1.1:
|
||||||
resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==}
|
resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==}
|
||||||
dev: true
|
|
||||||
|
|
||||||
/data-uri-to-buffer/4.0.1:
|
/data-uri-to-buffer/4.0.1:
|
||||||
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
|
resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==}
|
||||||
@@ -479,6 +460,23 @@ packages:
|
|||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/dexie-react-hooks/1.1.1_oyoivydq6d62bcmmdhna6akh5q:
|
||||||
|
resolution: {integrity: sha512-Cam5JP6PxHN564RvWEoe8cqLhosW0O4CAZ9XEVYeGHJBa6KEJlOpd9CUpV3kmU9dm2MrW97/lk7qkf1xpij7gA==}
|
||||||
|
peerDependencies:
|
||||||
|
'@types/react': '>=16'
|
||||||
|
dexie: '>=3.1.0-alpha.1 <5.0.0'
|
||||||
|
react: '>=16'
|
||||||
|
dependencies:
|
||||||
|
'@types/react': 18.0.28
|
||||||
|
dexie: 3.2.3
|
||||||
|
react: 18.2.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/dexie/3.2.3:
|
||||||
|
resolution: {integrity: sha512-iHayBd4UYryDCVUNa3PMsJMEnd8yjyh5p7a+RFeC8i8n476BC9wMhVvqiImq5zJZJf5Tuer+s4SSj+AA3x+ZbQ==}
|
||||||
|
engines: {node: '>=6.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/dotenv/16.0.3:
|
/dotenv/16.0.3:
|
||||||
resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
|
resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|||||||
@@ -161,7 +161,6 @@ class ViteRunner {
|
|||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': path.resolve(directoryDir, './src'),
|
'@': path.resolve(directoryDir, './src'),
|
||||||
'!': path.resolve(__projetRoot, './src'),
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
build: {
|
build: {
|
||||||
|
|||||||
Reference in New Issue
Block a user