refactor(aklive2d): use scss, stylelint, and postcss

This commit is contained in:
Haoyu Xu
2023-03-14 13:20:58 -04:00
parent 56e0d8178a
commit f14b8fc079
24 changed files with 1326 additions and 419 deletions

6
.postcssrc.json Normal file
View File

@@ -0,0 +1,6 @@
{
"map": true,
"plugins": {
"autoprefixer": {}
}
}

3
.stylelintrc.json Normal file
View File

@@ -0,0 +1,3 @@
{
"extends": "stylelint-config-standard-scss"
}

View File

@@ -1 +1 @@
1.0.12 1.0.17

View File

@@ -1,26 +1,25 @@
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap'); @import 'https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap';
@import url('https://fonts.cdnfonts.com/css/bender'); @import 'https://fonts.cdnfonts.com/css/bender';
@import url('https://fonts.cdnfonts.com/css/geometos'); @import 'https://fonts.cdnfonts.com/css/geometos';
:root { :root {
--text-color: rgba(255, 255, 255, 0.87); --text-color: rgba(255 255 255 87%);
--text-color-full: #fff; --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 20%);
--border-color: #707070; --border-color: #707070;
--link-highlight-color: #33b5e5; --link-highlight-color: #33b5e5;
--drawer-background-color: rgba(0, 0, 0, 0.88); --drawer-background-color: rgba(0 0 0 88%);
--root-background-color: #131313; --root-background-color: #131313;
--home-item-hover-background-color: rgba(67, 67, 67, 0.3); --home-item-hover-background-color: rgba(67 67 67 30%);
--home-item-background-linear-gradient-color: rgba(255, 255, 255, 0.1); --home-item-background-linear-gradient-color: rgba(255 255 255 10%);
--home-item-outline-color: rgba(214, 214, 214, 0.3); --home-item-outline-color: rgba(214 214 214 30%);
--button-color: #666; --button-color: #666;
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.2em; line-height: 1.2em;
font-weight: 400; font-weight: 400;
color: var(--text-color); color: var(--text-color);
background-color: var(--root-background-color); background-color: var(--root-background-color);
min-height: 100vh; min-height: 100vh;
@@ -28,9 +27,7 @@
#root { #root {
display: flex; display: flex;
flex-direction: column; flex-flow: column nowrap;
flex-wrap: nowrap;
align-content: flex-start;
justify-content: flex-start; justify-content: flex-start;
align-items: stretch; align-items: stretch;
min-height: 100vh; min-height: 100vh;

View File

@@ -1,107 +0,0 @@
.dropdown {
position: relative;
display: inline-block;
user-select: none;
z-index: 2;
padding: 0.5rem;
cursor: pointer;
}
.dropdown .text {
display: flex;
flex-direction: row;
align-items: center;
}
.dropdown .content {
padding-right: 0.5rem;
}
.dropdown .icon {
position: absolute;
bottom: 0.5rem;
right: -0.1rem;
width: 0.5em;
height: 0.5em;
display: inline-block;
vertical-align: middle;
border-left: 0.15em solid var(--text-color);
border-bottom: 0.15em solid var(--text-color);
border-right: 0.15em solid var(--text-color);
border-top: 0.15em solid var(--text-color);
transform: translate(0, -0.15em) rotate(-45deg);
}
.dropdown.active .icon,
.dropdown:hover .icon {
animation: icon-flash 2s cubic-bezier(0.65, 0.05, 0.36, 1) infinite;
}
.dropdown .menu {
opacity: 0;
position: absolute;
background-color: var(--root-background-color);
width: max-content;
z-index: -1;
top: 2rem;
right: 0;
gap: 0.5rem;
display: flex;
align-items: center;
flex-direction: column;
flex-wrap: nowrap;
transition: all cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
overflow: hidden;
padding: 0.5rem;
border: 1px solid var(--border-color);
visibility: hidden;
color: var(--link-highlight-color);
}
.dropdown.active .menu {
visibility: visible;
opacity: 1;
z-index: 2;
}
.dropdown .menu .item {
cursor: pointer;
padding: 0.5rem;
font-size: 1rem;
width: max-content;
height: max-content;
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
flex-wrap: nowrap;
transition: color cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
}
.dropdown .menu .item:hover .text,
.dropdown .menu .item:focus .text,
.dropdown .menu .item.active .text {
color: currentColor;
}
.dropdown .text {
color: var(--text-color);
}
.dropdown .overlay {
z-index: 1;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100vw;
height: 100vh;
}
@keyframes icon-flash {
50% {
opacity: 0.2;
}
}

View File

@@ -2,7 +2,7 @@ import React, {
useState useState
} from 'react' } from 'react'
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import './dropdown.css' import classes from './dropdown.module.scss'
export default function Dropdown(props) { export default function Dropdown(props) {
const [hidden, setHidden] = useState(true) const [hidden, setHidden] = useState(true)
@@ -13,34 +13,34 @@ export default function Dropdown(props) {
return ( return (
<> <>
<section className={`dropdown ${props.className ? props.className : ''} ${hidden ? '' : 'active'}`} > <section className={`${classes.dropdown} ${hidden ? '' : classes.active} ${props.className ? props.className : ''}`} >
<section <section
className='text' className={classes.text}
onClick={() => toggleDropdown()} onClick={() => toggleDropdown()}
> >
<span className='content'>{props.text}</span> <span className={classes.content}>{props.text}</span>
<span className='icon'></span> <span className={classes.icon}></span>
</section> </section>
<ul className='menu' style={props.activeColor}> <ul className={classes.menu} style={props.activeColor}>
{ {
props.menu.map((item) => { props.menu.map((item) => {
return ( return (
<li <li
key={item.name} key={item.name}
className={`item${item.name === props.text || (props.activeRule && props.activeRule(item)) ? ' active' : ''}`} className={`${classes.item} ${item.name === props.text || (props.activeRule && props.activeRule(item)) ? classes.active : ''}`}
onClick={() => { onClick={() => {
props.onClick(item) props.onClick(item)
toggleDropdown() toggleDropdown()
}} }}
> >
<section className="text">{item.name}</section> <section className={classes.text}>{item.name}</section>
</li> </li>
) )
}) })
} }
</ul> </ul>
<section <section
className='overlay' className={classes.overlay}
hidden={hidden} hidden={hidden}
onClick={() => toggleDropdown()} onClick={() => toggleDropdown()}
/> />

View File

@@ -0,0 +1,111 @@
.dropdown {
position: relative;
display: inline-block;
user-select: none;
z-index: 2;
padding: 0.5rem;
cursor: pointer;
.text {
display: flex;
flex-direction: row;
align-items: center;
color: var(--text-color);
}
.content {
padding-right: 0.5rem;
}
.icon {
position: absolute;
bottom: 0.5rem;
right: -0.1rem;
width: 0.5em;
height: 0.5em;
display: inline-block;
vertical-align: middle;
border-left: 0.15em solid var(--text-color);
border-bottom: 0.15em solid var(--text-color);
border-right: 0.15em solid var(--text-color);
border-top: 0.15em solid var(--text-color);
transform: translate(0, -0.15em) rotate(-45deg);
}
.menu {
opacity: 0;
position: absolute;
background-color: var(--root-background-color);
width: max-content;
z-index: -1;
top: 2rem;
right: 0;
gap: 0.5rem;
display: flex;
align-items: center;
flex-direction: column;
flex-wrap: nowrap;
transition: all cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
overflow: hidden;
padding: 0.5rem;
border: 1px solid var(--border-color);
visibility: hidden;
color: var(--link-highlight-color);
cursor: auto;
.item {
cursor: pointer;
padding: 0.5rem;
font-size: 1rem;
width: max-content;
height: max-content;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
flex-wrap: nowrap;
transition: color cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
&:hover,
&:focus,
&:active {
.text {
color: currentColor;
}
}
}
}
.overlay {
z-index: -1;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100vw;
height: 100vh;
cursor: auto;
}
&.active,
&:hover {
.icon {
animation: icon-flash 2s cubic-bezier(0.65, 0.05, 0.36, 1) infinite;
}
}
&.active {
.menu {
visibility: visible;
opacity: 1;
z-index: 2;
}
}
}
@keyframes icon-flash {
50% {
opacity: 0.2;
}
}

View File

@@ -1,23 +0,0 @@
.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

@@ -1,10 +1,10 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import './main_border.css'; import classes from './main_border.module.scss';
export default function MainBorder(props) { export default function MainBorder(props) {
return ( return (
<section className="main-border"> <section className={classes.border}>
{props.children} {props.children}
</section> </section>
) )

View File

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

View File

@@ -1,102 +0,0 @@
.popup-text {
cursor: pointer;
}
.popup {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
opacity: 0;
z-index: -1;
border: unset;
transition: all cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 1.2rem;
}
.popup .wrapper {
display: flex;
flex-direction: column;
align-items: stretch;
flex-wrap: nowrap;
max-width: 480px;
height: fit-content;
margin: 0 auto;
background-color: var(--root-background-color);
border: 1px solid var(--border-color);
padding: 2rem;
}
.popup.active {
opacity: 1;
z-index: 10;
}
.popup .title {
font-size: 3rem;
font-weight: 700;
display: flex;
flex-direction: row;
justify-content: space-between;
align-content: center;
align-items: center;
text-transform: uppercase;
font-family: "Geometos", "Noto Sans SC", sans-serif;
}
.popup .text {
flex-grow: 1;
margin-right: 3rem;
}
.popup .content {
line-height: 1.3em;
padding: 1rem 1rem 0 1rem;
user-select: text;
}
@media (max-width: 768px) {
.popup .title {
font-size: 2rem;
}
.popup .content {
font-size: 1rem;
}
.popup .return-button {
transform: scale(0.8);
}
}
.popup .overlay {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: -1;
opacity: 0;
background-color: var(--root-background-color);
transition: all cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
}
.popup .overlay.active {
opacity: 0.5;
visibility: visible;
}
.popup .return-button {
color: var(--button-color);
transition: color cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
}
.popup .return-button:hover {
color: var(--text-color);
}

View File

@@ -1,7 +1,7 @@
import React, { import React, {
useState, useState,
} from 'react' } from 'react'
import './popup.css' import classes from './popup.module.scss';
import ReturnButton from '@/component/return_button'; import ReturnButton from '@/component/return_button';
import MainBorder from '@/component/main_border'; import MainBorder from '@/component/main_border';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
@@ -14,22 +14,22 @@ export default function Popup(props) {
} }
return (<> return (<>
<section className={`popup ${hidden ? '' : 'active'}`}> <section className={`${classes.popup} ${hidden ? '' : classes.active}`}>
<section className='wrapper'> <section className={classes.wrapper}>
<section className='title'> <section className={classes.title}>
<section className="text">{props.title}</section> <section className={classes.text}>{props.title}</section>
<ReturnButton onClick={toggle} className="return-button" /> <ReturnButton onClick={toggle} className={classes["return-button"]} />
</section> </section>
<MainBorder /> <MainBorder />
<section className='content'> <section className={classes.content}>
{props.children} {props.children}
</section> </section>
</section> </section>
<section className={`overlay ${hidden ? '' : 'active'}`} <section className={`${classes.overlay} ${hidden ? '' : classes.active}`}
onClick={() => toggle()} /> onClick={() => toggle()} />
</section> </section>
<span <span
className="popup-text" className={classes['entry-text']}
onClick={toggle} onClick={toggle}
> >
{props.title} {props.title}

View File

@@ -0,0 +1,94 @@
.entry-text {
cursor: pointer;
}
.popup {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
overflow: hidden;
opacity: 0;
z-index: -1;
border: unset;
transition: all cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 1.2rem;
.wrapper {
display: flex;
flex-direction: column;
align-items: stretch;
flex-wrap: nowrap;
max-width: 480px;
height: fit-content;
margin: 0 auto;
background-color: var(--root-background-color);
border: 1px solid var(--border-color);
padding: 2rem;
}
.title {
font-size: 3rem;
font-weight: 700;
display: flex;
flex-direction: row;
justify-content: space-between;
align-content: center;
align-items: center;
text-transform: uppercase;
font-family: "Geometos", "Noto Sans SC", sans-serif;
}
.text {
flex-grow: 1;
margin-right: 3rem;
}
.content {
line-height: 1.3em;
padding: 1rem 1rem 0 1rem;
user-select: text;
}
.overlay {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: -1;
opacity: 0;
background-color: var(--root-background-color);
transition: all cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
&.active {
opacity: 0.5;
visibility: visible;
}
.return-button {
color: var(--button-color);
transition: color cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
&:hover {
color: var(--text-color);
}
}
}
&.active {
opacity: 1;
z-index: 10;
}
@media (max-width: 768px) {
.title {
font-size: 2rem;
}
.content {
font-size: 1rem;
}
.return-button {
transform: scale(0.8);
}
}
}

View File

@@ -1,50 +0,0 @@
.return-button {
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 0.6rem 0;
width: 3rem;
cursor: pointer;
}
.return-button .bar-wrapper {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
}
.return-button .bar {
width: 1rem;
height: 0.4rem;
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 currentColor;
}
.return-button .bar-arrow-right {
border-top: 0.24rem solid transparent;
border-bottom: 0.24rem solid transparent;
border-left: 0.3rem solid currentColor;
}
.return-button .bar-wrapper:nth-child(1) {
transform: translateY(-0.1rem) rotate(45deg);
}
.return-button .bar-wrapper:nth-child(2) {
transform: translateY(-0.1rem) translate(90%, -100%) rotate(-45deg);
}
.return-button .bar-wrapper:nth-child(3) {
transform: translateY(-0.1rem) translateY(150%) rotate(315deg);
}
.return-button .bar-wrapper:nth-child(4) {
transform: translateY(-0.1rem) translate(90%, 50%) rotate(225deg);
}

View File

@@ -1,33 +1,33 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import './return_button.css' import classes from './return_button.module.scss'
export default function ReturnButton(props) { export default function ReturnButton(props) {
return ( return (
<> <>
<section className='return-button' <section className={`${classes['return-button']} ${props.className ? props.className : ''}`}
onClick={() => props.onClick()} onClick={() => props.onClick()}
> >
<section className='bar-wrapper'> <section className={classes.wrapper}>
<section className='bar-arrow-left'></section> <section className={classes["arrow-left"]}></section>
<section className='bar'></section> <section className={classes.bar}></section>
<section className='bar-arrow-right'></section> <section className={classes["arrow-right"]}></section>
</section> </section>
<section className='bar-wrapper'> <section className={classes.wrapper}>
<section className='bar-arrow-left'></section> <section className={classes["arrow-left"]}></section>
<section className='bar'></section> <section className={classes.bar}></section>
<section className='bar-arrow-right'></section> <section className={classes["arrow-right"]}></section>
</section> </section>
<section className='bar-wrapper'> <section className={classes.wrapper}>
<section className='bar-arrow-left'></section> <section className={classes["arrow-left"]}></section>
<section className='bar'></section> <section className={classes.bar}></section>
<section className='bar-arrow-right'></section> <section className={classes["arrow-right"]}></section>
</section> </section>
<section className='bar-wrapper'> <section className={classes.wrapper}>
<section className='bar-arrow-left'></section> <section className={classes["arrow-left"]}></section>
<section className='bar'></section> <section className={classes.bar}></section>
<section className='bar-arrow-right'></section> <section className={classes["arrow-right"]}></section>
</section> </section>
</section> </section>
</> </>
@@ -35,4 +35,5 @@ export default function ReturnButton(props) {
} }
ReturnButton.propTypes = { ReturnButton.propTypes = {
onClick: PropTypes.func, onClick: PropTypes.func,
className: PropTypes.string,
}; };

View File

@@ -0,0 +1,46 @@
.return-button {
%arrow-shared {
border-top: 0.24rem solid transparent;
border-bottom: 0.24rem solid transparent;
}
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 0.6rem 0;
width: 3rem;
cursor: pointer;
.wrapper {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
&:nth-child(1) {
transform: translateY(-0.1rem) rotate(45deg);
}
&:nth-child(2) {
transform: translateY(-0.1rem) translate(90%, -100%) rotate(-45deg);
}
&:nth-child(3) {
transform: translateY(-0.1rem) translateY(150%) rotate(315deg);
}
&:nth-child(4) {
transform: translateY(-0.1rem) translate(90%, 50%) rotate(225deg);
}
}
.bar {
width: 1rem;
height: 0.4rem;
background-color: currentColor;
transition: transform cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
}
.arrow-left {
@extend %arrow-shared;
border-right: 0.3rem solid currentColor;
}
.arrow-right {
@extend %arrow-shared;
border-left: 0.3rem solid currentColor;
}
}

View File

@@ -1,62 +0,0 @@
.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

@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import './switch.css'; import classes from './switch.module.scss';
import { import {
useI18n useI18n
} from '@/state/language' } from '@/state/language'
@@ -15,13 +15,13 @@ export default function Switch(props) {
return ( return (
<section <section
className={`switch ${on ? 'active' : ''}`} className={`${classes.switch} ${on ? classes.active : ''}`}
onClick={() => props.handleOnClick()} onClick={() => props.handleOnClick()}
> >
<span className='text'>{i18n(props.text)}</span> <span className={classes.text}>{i18n(props.text)}</span>
<section className='icon-wrapper'> <section className={classes.wrapper}>
<span className='icon-line'></span> <span className={classes.line}></span>
<span className='icon'></span> <span className={classes.icon}></span>
</section> </section>
</section> </section>
) )

View File

@@ -0,0 +1,60 @@
.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;
.content {
padding-right: 8px;
}
.wrapper {
color: var(--secondary-text-color);
transition: all cubic-bezier(0.65, 0.05, 0.36, 1) 0.3s;
.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;
}
.line {
position: absolute;
bottom: 15px;
right: 6px;
width: 18px;
height: 2px;
display: inline-block;
vertical-align: middle;
background-color: currentColor;
z-index: -1;
}
}
&.active {
color: var(--text-color);
.wrapper {
color: var(--text-color-full);
.icon {
background-color: currentColor;
right: 0;
}
}
}
}

View File

@@ -10,7 +10,6 @@ import {
useNavigate, useNavigate,
Link Link
} from "react-router-dom"; } from "react-router-dom";
import { atom, useAtom } from 'jotai';
import './operator.css' import './operator.css'
import { useConfig } from '@/state/config'; import { useConfig } from '@/state/config';
import { import {
@@ -31,8 +30,7 @@ const getVoiceFoler = (lang) => {
const voiceFolder = folderObject.sub.find(e => e.lang === lang) || folderObject.sub.find(e => e.name === 'custom') const voiceFolder = folderObject.sub.find(e => e.lang === lang) || folderObject.sub.find(e => e.name === 'custom')
return `${folderObject.main}/${voiceFolder.name}` return `${folderObject.main}/${voiceFolder.name}`
} }
const spinePlayerAtom = atom(null); const defaultSpineAnimation = 'Idle'
const spineAnimationAtom = atom("Idle");
const getTabName = (item, language) => { const getTabName = (item, language) => {
if (item.type === 'operator') { if (item.type === 'operator') {
@@ -58,9 +56,9 @@ export default function Operator() {
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
const _trackEvt = useUmami(`/${key}`) const _trackEvt = useUmami(`/${key}`)
const spineRef = useRef(null) const spineRef = useRef(null)
const [spineAnimation, setSpineAnimation] = useAtom(spineAnimationAtom) const [spineAnimation, setSpineAnimation] = useState(defaultSpineAnimation)
const { i18n } = useI18n() const { i18n } = useI18n()
const [spinePlayer, setSpinePlayer] = useAtom(spinePlayerAtom) const [spinePlayer, setSpinePlayer] = useState(null)
const [voiceLang, _setVoiceLang] = useState(null) const [voiceLang, _setVoiceLang] = useState(null)
const { backgrounds } = useBackgrounds() const { backgrounds } = useBackgrounds()
const [currentBackground, setCurrentBackground] = useState(null) const [currentBackground, setCurrentBackground] = useState(null)
@@ -104,6 +102,7 @@ export default function Operator() {
setConfig(config) setConfig(config)
configRef.current = config configRef.current = config
fetch(`/${import.meta.env.VITE_DIRECTORY_FOLDER}/${config.filename.replace("#", "%23")}.json`).then(res => res.json()).then(data => { fetch(`/${import.meta.env.VITE_DIRECTORY_FOLDER}/${config.filename.replace("#", "%23")}.json`).then(res => res.json()).then(data => {
setSpineAnimation(defaultSpineAnimation)
setSpineData(data) setSpineData(data)
}) })
setHeaderIcon(config.type) setHeaderIcon(config.type)
@@ -261,7 +260,7 @@ export default function Operator() {
{ {
name: 'idle', name: 'idle',
onClick: () => { onClick: () => {
spinePlayer.setAnimation("Idle", true) spinePlayer.animationState.setAnimation(0, "Idle", true, 0)
setSpineAnimation('Idle') setSpineAnimation('Idle')
}, },
activeRule: () => { activeRule: () => {
@@ -270,7 +269,7 @@ export default function Operator() {
}, { }, {
name: 'interact', name: 'interact',
onClick: () => { onClick: () => {
spinePlayer.setAnimation("Interact", true) spinePlayer.animationState.setAnimation(0, "Interact", true, 0)
setSpineAnimation('Interact') setSpineAnimation('Interact')
}, },
activeRule: () => { activeRule: () => {
@@ -279,7 +278,7 @@ export default function Operator() {
}, { }, {
name: 'special', name: 'special',
onClick: () => { onClick: () => {
spinePlayer.setAnimation("Special", true) spinePlayer.animationState.setAnimation(0, "Special", true, 0)
setSpineAnimation('Special') setSpineAnimation('Special')
}, },
activeRule: () => { activeRule: () => {

View File

@@ -8,15 +8,17 @@
margin: 0 auto; margin: 0 auto;
width: 70%; width: 70%;
max-width: 100rem; max-width: 100rem;
padding-top: 5rem;
} }
.header { .header {
width: auto; width: auto;
position: sticky; position: fixed;
left: 0;
top: 0; top: 0;
right: 0; right: 0;
padding: 1rem; padding: 1rem;
z-index: 2; z-index: 3;
height: 3rem; height: 3rem;
display: flex; display: flex;
flex-direction: row; flex-direction: row;

View File

@@ -10,6 +10,7 @@ import {
Link, Link,
NavLink, NavLink,
useNavigate, useNavigate,
ScrollRestoration,
} from "react-router-dom"; } from "react-router-dom";
import './root.css' import './root.css'
import routes from '@/routes' import routes from '@/routes'
@@ -125,6 +126,7 @@ export default function Root() {
</section> </section>
<HeaderReturnButton /> <HeaderReturnButton />
<Outlet /> <Outlet />
<ScrollRestoration />
</main> </main>
<FooterElement /> <FooterElement />
</> </>

View File

@@ -25,11 +25,17 @@
"@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",
"autoprefixer": "^10.4.14",
"eslint": "^8.35.0", "eslint": "^8.35.0",
"eslint-plugin-react": "^7.32.2", "eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"postcss": "^8.4.21",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"rollup": "^3.17.3", "rollup": "^3.17.3",
"sass": "^1.59.2",
"stylelint": "^15.2.0",
"stylelint-config-standard": "^30.0.1",
"stylelint-config-standard-scss": "^7.0.1",
"vite": "^4.1.4" "vite": "^4.1.4"
}, },
"dependencies": { "dependencies": {

914
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff