refactor(aklive2d): use scss, stylelint, and postcss
This commit is contained in:
6
.postcssrc.json
Normal file
6
.postcssrc.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"map": true,
|
||||
"plugins": {
|
||||
"autoprefixer": {}
|
||||
}
|
||||
}
|
||||
3
.stylelintrc.json
Normal file
3
.stylelintrc.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "stylelint-config-standard-scss"
|
||||
}
|
||||
@@ -1 +1 @@
|
||||
1.0.12
|
||||
1.0.17
|
||||
@@ -1,26 +1,25 @@
|
||||
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap');
|
||||
@import url('https://fonts.cdnfonts.com/css/bender');
|
||||
@import url('https://fonts.cdnfonts.com/css/geometos');
|
||||
@import 'https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@400;500;700&display=swap';
|
||||
@import 'https://fonts.cdnfonts.com/css/bender';
|
||||
@import 'https://fonts.cdnfonts.com/css/geometos';
|
||||
|
||||
:root {
|
||||
--text-color: rgba(255, 255, 255, 0.87);
|
||||
--text-color: rgba(255 255 255 87%);
|
||||
--text-color-full: #fff;
|
||||
--secondary-text-color: #686a72;
|
||||
--date-color: rgba(255, 255, 255, 0.2);
|
||||
--date-color: rgba(255 255 255 20%);
|
||||
--border-color: #707070;
|
||||
--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;
|
||||
--home-item-hover-background-color: rgba(67, 67, 67, 0.3);
|
||||
--home-item-background-linear-gradient-color: rgba(255, 255, 255, 0.1);
|
||||
--home-item-outline-color: rgba(214, 214, 214, 0.3);
|
||||
--home-item-hover-background-color: rgba(67 67 67 30%);
|
||||
--home-item-background-linear-gradient-color: rgba(255 255 255 10%);
|
||||
--home-item-outline-color: rgba(214 214 214 30%);
|
||||
--button-color: #666;
|
||||
|
||||
font-family: "Geometos", "Noto Sans SC", sans-serif;
|
||||
font-family: Geometos, "Noto Sans SC", sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 1.2em;
|
||||
font-weight: 400;
|
||||
|
||||
color: var(--text-color);
|
||||
background-color: var(--root-background-color);
|
||||
min-height: 100vh;
|
||||
@@ -28,9 +27,7 @@
|
||||
|
||||
#root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
align-content: flex-start;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: flex-start;
|
||||
align-items: stretch;
|
||||
min-height: 100vh;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import React, {
|
||||
useState
|
||||
} from 'react'
|
||||
import PropTypes from 'prop-types';
|
||||
import './dropdown.css'
|
||||
import classes from './dropdown.module.scss'
|
||||
|
||||
export default function Dropdown(props) {
|
||||
const [hidden, setHidden] = useState(true)
|
||||
@@ -13,34 +13,34 @@ export default function Dropdown(props) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className={`dropdown ${props.className ? props.className : ''} ${hidden ? '' : 'active'}`} >
|
||||
<section className={`${classes.dropdown} ${hidden ? '' : classes.active} ${props.className ? props.className : ''}`} >
|
||||
<section
|
||||
className='text'
|
||||
className={classes.text}
|
||||
onClick={() => toggleDropdown()}
|
||||
>
|
||||
<span className='content'>{props.text}</span>
|
||||
<span className='icon'></span>
|
||||
<span className={classes.content}>{props.text}</span>
|
||||
<span className={classes.icon}></span>
|
||||
</section>
|
||||
<ul className='menu' style={props.activeColor}>
|
||||
<ul className={classes.menu} style={props.activeColor}>
|
||||
{
|
||||
props.menu.map((item) => {
|
||||
return (
|
||||
<li
|
||||
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={() => {
|
||||
props.onClick(item)
|
||||
toggleDropdown()
|
||||
}}
|
||||
>
|
||||
<section className="text">{item.name}</section>
|
||||
<section className={classes.text}>{item.name}</section>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
<section
|
||||
className='overlay'
|
||||
className={classes.overlay}
|
||||
hidden={hidden}
|
||||
onClick={() => toggleDropdown()}
|
||||
/>
|
||||
|
||||
111
directory/src/component/dropdown.module.scss
Normal file
111
directory/src/component/dropdown.module.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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%;
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import './main_border.css';
|
||||
import classes from './main_border.module.scss';
|
||||
|
||||
export default function MainBorder(props) {
|
||||
return (
|
||||
<section className="main-border">
|
||||
<section className={classes.border}>
|
||||
{props.children}
|
||||
</section>
|
||||
)
|
||||
|
||||
22
directory/src/component/main_border.module.scss
Normal file
22
directory/src/component/main_border.module.scss
Normal 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%;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, {
|
||||
useState,
|
||||
} from 'react'
|
||||
import './popup.css'
|
||||
import classes from './popup.module.scss';
|
||||
import ReturnButton from '@/component/return_button';
|
||||
import MainBorder from '@/component/main_border';
|
||||
import PropTypes from 'prop-types';
|
||||
@@ -14,22 +14,22 @@ export default function Popup(props) {
|
||||
}
|
||||
|
||||
return (<>
|
||||
<section className={`popup ${hidden ? '' : 'active'}`}>
|
||||
<section className='wrapper'>
|
||||
<section className='title'>
|
||||
<section className="text">{props.title}</section>
|
||||
<ReturnButton onClick={toggle} className="return-button" />
|
||||
<section className={`${classes.popup} ${hidden ? '' : classes.active}`}>
|
||||
<section className={classes.wrapper}>
|
||||
<section className={classes.title}>
|
||||
<section className={classes.text}>{props.title}</section>
|
||||
<ReturnButton onClick={toggle} className={classes["return-button"]} />
|
||||
</section>
|
||||
<MainBorder />
|
||||
<section className='content'>
|
||||
<section className={classes.content}>
|
||||
{props.children}
|
||||
</section>
|
||||
</section>
|
||||
<section className={`overlay ${hidden ? '' : 'active'}`}
|
||||
<section className={`${classes.overlay} ${hidden ? '' : classes.active}`}
|
||||
onClick={() => toggle()} />
|
||||
</section>
|
||||
<span
|
||||
className="popup-text"
|
||||
className={classes['entry-text']}
|
||||
onClick={toggle}
|
||||
>
|
||||
{props.title}
|
||||
|
||||
94
directory/src/component/popup.module.scss
Normal file
94
directory/src/component/popup.module.scss
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,33 +1,33 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import './return_button.css'
|
||||
import classes from './return_button.module.scss'
|
||||
|
||||
export default function ReturnButton(props) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className='return-button'
|
||||
<section className={`${classes['return-button']} ${props.className ? props.className : ''}`}
|
||||
onClick={() => props.onClick()}
|
||||
>
|
||||
<section className='bar-wrapper'>
|
||||
<section className='bar-arrow-left'></section>
|
||||
<section className='bar'></section>
|
||||
<section className='bar-arrow-right'></section>
|
||||
<section className={classes.wrapper}>
|
||||
<section className={classes["arrow-left"]}></section>
|
||||
<section className={classes.bar}></section>
|
||||
<section className={classes["arrow-right"]}></section>
|
||||
</section>
|
||||
<section className='bar-wrapper'>
|
||||
<section className='bar-arrow-left'></section>
|
||||
<section className='bar'></section>
|
||||
<section className='bar-arrow-right'></section>
|
||||
<section className={classes.wrapper}>
|
||||
<section className={classes["arrow-left"]}></section>
|
||||
<section className={classes.bar}></section>
|
||||
<section className={classes["arrow-right"]}></section>
|
||||
</section>
|
||||
<section className='bar-wrapper'>
|
||||
<section className='bar-arrow-left'></section>
|
||||
<section className='bar'></section>
|
||||
<section className='bar-arrow-right'></section>
|
||||
<section className={classes.wrapper}>
|
||||
<section className={classes["arrow-left"]}></section>
|
||||
<section className={classes.bar}></section>
|
||||
<section className={classes["arrow-right"]}></section>
|
||||
</section>
|
||||
<section className='bar-wrapper'>
|
||||
<section className='bar-arrow-left'></section>
|
||||
<section className='bar'></section>
|
||||
<section className='bar-arrow-right'></section>
|
||||
<section className={classes.wrapper}>
|
||||
<section className={classes["arrow-left"]}></section>
|
||||
<section className={classes.bar}></section>
|
||||
<section className={classes["arrow-right"]}></section>
|
||||
</section>
|
||||
</section>
|
||||
</>
|
||||
@@ -35,4 +35,5 @@ export default function ReturnButton(props) {
|
||||
}
|
||||
ReturnButton.propTypes = {
|
||||
onClick: PropTypes.func,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
46
directory/src/component/return_button.module.scss
Normal file
46
directory/src/component/return_button.module.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import './switch.css';
|
||||
import classes from './switch.module.scss';
|
||||
import {
|
||||
useI18n
|
||||
} from '@/state/language'
|
||||
@@ -15,13 +15,13 @@ export default function Switch(props) {
|
||||
|
||||
return (
|
||||
<section
|
||||
className={`switch ${on ? 'active' : ''}`}
|
||||
className={`${classes.switch} ${on ? classes.active : ''}`}
|
||||
onClick={() => props.handleOnClick()}
|
||||
>
|
||||
<span className='text'>{i18n(props.text)}</span>
|
||||
<section className='icon-wrapper'>
|
||||
<span className='icon-line'></span>
|
||||
<span className='icon'></span>
|
||||
<span className={classes.text}>{i18n(props.text)}</span>
|
||||
<section className={classes.wrapper}>
|
||||
<span className={classes.line}></span>
|
||||
<span className={classes.icon}></span>
|
||||
</section>
|
||||
</section>
|
||||
)
|
||||
|
||||
60
directory/src/component/switch.module.scss
Normal file
60
directory/src/component/switch.module.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
useNavigate,
|
||||
Link
|
||||
} from "react-router-dom";
|
||||
import { atom, useAtom } from 'jotai';
|
||||
import './operator.css'
|
||||
import { useConfig } from '@/state/config';
|
||||
import {
|
||||
@@ -31,8 +30,7 @@ const getVoiceFoler = (lang) => {
|
||||
const voiceFolder = folderObject.sub.find(e => e.lang === lang) || folderObject.sub.find(e => e.name === 'custom')
|
||||
return `${folderObject.main}/${voiceFolder.name}`
|
||||
}
|
||||
const spinePlayerAtom = atom(null);
|
||||
const spineAnimationAtom = atom("Idle");
|
||||
const defaultSpineAnimation = 'Idle'
|
||||
|
||||
const getTabName = (item, language) => {
|
||||
if (item.type === 'operator') {
|
||||
@@ -58,9 +56,9 @@ export default function Operator() {
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
const _trackEvt = useUmami(`/${key}`)
|
||||
const spineRef = useRef(null)
|
||||
const [spineAnimation, setSpineAnimation] = useAtom(spineAnimationAtom)
|
||||
const [spineAnimation, setSpineAnimation] = useState(defaultSpineAnimation)
|
||||
const { i18n } = useI18n()
|
||||
const [spinePlayer, setSpinePlayer] = useAtom(spinePlayerAtom)
|
||||
const [spinePlayer, setSpinePlayer] = useState(null)
|
||||
const [voiceLang, _setVoiceLang] = useState(null)
|
||||
const { backgrounds } = useBackgrounds()
|
||||
const [currentBackground, setCurrentBackground] = useState(null)
|
||||
@@ -104,6 +102,7 @@ export default function Operator() {
|
||||
setConfig(config)
|
||||
configRef.current = config
|
||||
fetch(`/${import.meta.env.VITE_DIRECTORY_FOLDER}/${config.filename.replace("#", "%23")}.json`).then(res => res.json()).then(data => {
|
||||
setSpineAnimation(defaultSpineAnimation)
|
||||
setSpineData(data)
|
||||
})
|
||||
setHeaderIcon(config.type)
|
||||
@@ -261,7 +260,7 @@ export default function Operator() {
|
||||
{
|
||||
name: 'idle',
|
||||
onClick: () => {
|
||||
spinePlayer.setAnimation("Idle", true)
|
||||
spinePlayer.animationState.setAnimation(0, "Idle", true, 0)
|
||||
setSpineAnimation('Idle')
|
||||
},
|
||||
activeRule: () => {
|
||||
@@ -270,7 +269,7 @@ export default function Operator() {
|
||||
}, {
|
||||
name: 'interact',
|
||||
onClick: () => {
|
||||
spinePlayer.setAnimation("Interact", true)
|
||||
spinePlayer.animationState.setAnimation(0, "Interact", true, 0)
|
||||
setSpineAnimation('Interact')
|
||||
},
|
||||
activeRule: () => {
|
||||
@@ -279,7 +278,7 @@ export default function Operator() {
|
||||
}, {
|
||||
name: 'special',
|
||||
onClick: () => {
|
||||
spinePlayer.setAnimation("Special", true)
|
||||
spinePlayer.animationState.setAnimation(0, "Special", true, 0)
|
||||
setSpineAnimation('Special')
|
||||
},
|
||||
activeRule: () => {
|
||||
|
||||
@@ -8,15 +8,17 @@
|
||||
margin: 0 auto;
|
||||
width: 70%;
|
||||
max-width: 100rem;
|
||||
padding-top: 5rem;
|
||||
}
|
||||
|
||||
.header {
|
||||
width: auto;
|
||||
position: sticky;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 1rem;
|
||||
z-index: 2;
|
||||
z-index: 3;
|
||||
height: 3rem;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
Link,
|
||||
NavLink,
|
||||
useNavigate,
|
||||
ScrollRestoration,
|
||||
} from "react-router-dom";
|
||||
import './root.css'
|
||||
import routes from '@/routes'
|
||||
@@ -125,6 +126,7 @@ export default function Root() {
|
||||
</section>
|
||||
<HeaderReturnButton />
|
||||
<Outlet />
|
||||
<ScrollRestoration />
|
||||
</main>
|
||||
<FooterElement />
|
||||
</>
|
||||
|
||||
@@ -25,11 +25,17 @@
|
||||
"@types/react": "^18.0.28",
|
||||
"@types/react-dom": "^18.0.11",
|
||||
"@vitejs/plugin-react-swc": "^3.2.0",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"eslint": "^8.35.0",
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"postcss": "^8.4.21",
|
||||
"prop-types": "^15.8.1",
|
||||
"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"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
914
pnpm-lock.yaml
generated
914
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user