Player: replace player.css with scss modules

This commit is contained in:
He4eT 2023-06-12 22:30:27 +03:00 committed by Alexey
commit ade6f5d2c3
14 changed files with 189 additions and 181 deletions

View file

@ -14,7 +14,7 @@ import ThemesView from '~/src/views/ThemesView/ThemesView'
import PlayerView from '~/src/views/PlayerView/PlayerView'
import NotFoundView from '~/src/views/NotFoundView/NotFoundView'
import * as style from './style/App.module.scss'
import * as s from './style/App.module.scss'
export default function App () {
const themeEngine = useThemeEngine()
@ -32,9 +32,10 @@ export default function App () {
return (
<Router hook={useHashLocation}>
<div className={[
style.app,
style[extractView(currentLocation)],
themeEngine.currentTheme].join(' ')}>
s.app,
s[extractView(currentLocation)],
themeEngine.currentTheme,
].join(' ')}>
<Switch>
<Route path='/'>

View file

@ -2,6 +2,8 @@ import { useEffect, useRef, useState } from 'preact/hooks'
import MenuButton from './MenuButton/MenuButton'
import * as s from './InputBox.module.scss'
/* eslint-disable */
const keyCodes = {
KEY_BACKSPACE: 8,
@ -147,9 +149,9 @@ export default function InputBox ({
}
return (
<section className='inputControls'>
<section className={s.inputControls}>
<input {...inputHandlers[inputType]}
className='inputBox'
className={s.inputBox}
ref={inputEl}
value={inputText}
autofocus

View file

@ -0,0 +1,31 @@
.inputControls {
position: relative;
margin-top: var(--input-box-margin);
.inputBox {
font: inherit;
color: inherit;
outline: 0;
background-color: var(--bg-color);
border: var(--border-width) solid var(--main-color);
border-top: var(--separator-width) solid var(--main-color);
padding: var(--inner-padding);
padding-right: calc(4 * var(--inner-padding));
margin: 0;
width: 100%;
&::placeholder {
color: var(--main-color);
opacity: 1;
}
&:focus::placeholder {
opacity: 0.5;
}
&::-webkit-search-cancel-button {
display: none;
}
}
}

View file

@ -1,41 +0,0 @@
.menu {
width: 100%;
border-left: none;
border-right: none;
text-align: center;
padding-top: 0;
padding-bottom: 0;
background-color: var(--bg-color);
border-color: var(--main-color);
color: var(--main-color);
}
.menu::backdrop {
background: none;
backdrop-filter: blur(2px);
}
.menu > section {
margin: 32px auto 40px;
gap: 32px;
max-width: 270px;
display: flex;
flex-direction: column;
}
.menu .navigation {
color: var(--accent-color);
}
.menu .appearance {
display: flex;
flex-direction: column;
gap: 8px;
}
.menu select,
.menu button {
width: 100%;
}

View file

@ -4,7 +4,7 @@ import { Link } from 'wouter-preact'
import ThemeSelector from
'~/src/components/ThemeSelector/ThemeSelector'
import './MenuOverlay.css'
import * as s from './MenuOverlay.module.scss'
export default function MenuOverlay ({
themeEngine, onFullscreenRequest, menuOpen, setMenuOpen,
@ -35,7 +35,7 @@ export default function MenuOverlay ({
return (
<dialog ref={dialog} className='menu'>
<dialog ref={dialog} className={s.menu}>
<section>
<div>
<button
@ -46,7 +46,7 @@ export default function MenuOverlay ({
</button>
</div>
<div className='appearance'>
<div className={s.appearance}>
<button
onClick={() => {
dialog.current.close()
@ -68,7 +68,7 @@ export default function MenuOverlay ({
</label>
</div>
<div className='navigation'>
<div className={s.navigation}>
<Link href="/" tabIndex={0}>
ElseIfPlayer
</Link>

View file

@ -0,0 +1,41 @@
.menu {
width: 100%;
border-left: none;
border-right: none;
text-align: center;
padding-top: 0;
padding-bottom: 0;
background-color: var(--bg-color);
border-color: var(--main-color);
color: var(--main-color);
&::backdrop {
background: none;
backdrop-filter: blur(2px);
}
& > section {
margin: 32px auto 40px;
gap: 32px;
max-width: 270px;
display: flex;
flex-direction: column;
}
.navigation {
color: var(--accent-color);
}
.appearance {
display: flex;
flex-direction: column;
gap: 8px;
}
select,
button {
width: 100%;
}
}

View file

@ -1,6 +1,8 @@
import { useEffect, useState } from 'preact/hooks'
import TextMessage from './TextMessage'
import TextMessage from '../TextMessage/TextMessage'
import * as s from '../../Player.module.scss'
export default function GridBuffer ({ inbox, currentWindow }) {
const [prevMessages, setPrevMessages] = useState([])
@ -70,8 +72,7 @@ export default function GridBuffer ({ inbox, currentWindow }) {
}, [inbox, currentWindow, prevMessages])
return (
<section
className='buffer gridBuffer'>
<section className={[s.buffer, s.gridBuffer].join(' ')}>
{messages.map(TextMessage)}
</section>
)

View file

@ -1,6 +1,8 @@
import { useEffect, useRef, useState } from 'preact/hooks'
import TextMessage from './TextMessage'
import TextMessage from '../TextMessage/TextMessage'
import * as s from '../../Player.module.scss'
const isFakeStatus = (w) =>
w.height < 5
@ -75,17 +77,19 @@ export default function TextBuffer ({ inbox, currentWindow }) {
}, 0)
}, [currentWindow, inbox])
const classes = [
const classes = () => [
s.buffer,
isFakeStatus(currentWindow)
? 'gridBuffer'
: 'textBuffer',
'buffer'].join(' ')
? s.gridBuffer
: s.textBuffer,
].join(' ')
return (
<section
tabindex='0'
ref={textBufferEl}
className={classes}>
className={classes()}
>
{messages.map(TextMessage)}
</section>
)

View file

@ -1,14 +0,0 @@
export default function TextMessage ({ style, text }) {
const defaultContent = (
<span className={['message', style].join(' ')}>
{text}
</span>)
return ({
grid: (text?.length > 0 ? <div>{text}</div> : <br />),
input: (<span className='message input'>&gt; {text}</span>),
subheader: (<strong className='message subheader'>{text}</strong>),
emphasized: (<em className='message emphasized'>{text}</em>),
endOfLine: (<br />),
})[style] || defaultContent
}

View file

@ -0,0 +1,21 @@
import * as s from './TextMessage.module.scss'
export default function TextMessage ({ style, text }) {
const defaultContent = (
<span className={[s.message, s[style]].join(' ')}>
{text}
</span>)
return ({
grid:
(text?.length > 0 ? <div>{text}</div> : <br />),
input:
(<span className={[s.message, s.input].join(' ')}>&gt; {text}</span>),
subheader:
(<strong className={[s.message, s.subheader].join(' ')}>{text}</strong>),
emphasized:
(<em className={[s.message, s.emphasized].join(' ')}>{text}</em>),
endOfLine:
(<br />),
})[style] || defaultContent
}

View file

@ -0,0 +1,11 @@
.message {
&.input {
scroll-margin-top: var(--inner-padding);
color: var(--input-color);
}
&.emphasized,
&.subheader {
color: var(--accent-color);
}
}

View file

@ -2,8 +2,8 @@ import { useState, useEffect } from 'preact/hooks'
import CheapGlkOte from 'cheap-glkote'
import TextBuffer from './OutputBox/TextBuffer'
import GridBuffer from './OutputBox/GridBuffer'
import TextBuffer from './OutputBox/TextBuffer/TextBuffer'
import GridBuffer from './OutputBox/GridBuffer/GridBuffer'
import InputBox from './InputBox/InputBox'
import Status from './Status/Status'
@ -13,7 +13,7 @@ import {
unhandledRejectionHandler,
} from './common/playerHandlers'
import './player.css'
import * as s from './Player.module.scss'
const INITIAL_STATUS = {
stage: 'loading',
@ -104,14 +104,16 @@ export default function Player ({
return status.stage !== 'ready'
? (<Status {...status} />)
: (<section className='ifplayer'>
<section className='output'>{
windows
: (<section className={s.elseifplayer}>
<section className={s.output}>
{
windows
.sort(byTop)
.filter(singleWindow
? ({ id }) => id === currentWindowId
: () => true)
.map(textWindow(inbox))}
.map(textWindow(inbox))
}
</section>
<InputBox {...{
inputType,

View file

@ -0,0 +1,49 @@
.elseifplayer {
height: 100%;
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: var(--bg-color);
color: var(--main-color);
padding: var(--outer-padding);
.output {
display: flex;
flex-grow: 2;
flex-direction: column;
overflow-y: hidden;
overflow-wrap: break-word;
border: var(--border-width) solid var(--main-color);
.buffer {
overflow-y: scroll;
box-sizing: border-box;
padding: var(--inner-padding);
&:empty {
display: none;
}
& > br:first-child,
& > br:last-child,
& > br + br + br {
display: none;
}
&.gridBuffer {
flex-shrink: 0;
max-height: 100%;
border-bottom: var(--separator-width) solid var(--main-color);
}
&.textBuffer {
flex: 2 1;
outline: none;
scroll-behavior: smooth;
}
}
}
}

View file

@ -1,100 +0,0 @@
.ifplayer {
height: 100%;
display: flex;
flex-direction: column;
box-sizing: border-box;
background-color: var(--bg-color);
color: var(--main-color);
padding: var(--outer-padding);
}
.ifplayer .inputControls {
position: relative;
margin-top: var(--input-box-margin);
}
.ifplayer .inputControls .menuButton {
position: absolute;
right: 0;
height: 100%;
}
.ifplayer .inputBox {
font: inherit;
color: inherit;
outline: 0;
background-color: var(--bg-color);
border: var(--border-width) solid var(--main-color);
border-top: var(--separator-width) solid var(--main-color);
padding: var(--inner-padding);
padding-right: calc(4 * var(--inner-padding));
margin: 0;
width: 100%;
}
.ifplayer .inputBox::placeholder {
color: var(--main-color);
opacity: 1;
}
.ifplayer .inputBox:focus::placeholder {
opacity: 0.5;
}
.ifplayer .inputBox::-webkit-search-cancel-button {
display: none;
}
.ifplayer .output {
display: flex;
flex-grow: 2;
flex-direction: column;
overflow-y: hidden;
overflow-wrap: break-word;
border: var(--border-width) solid var(--main-color);
}
.ifplayer .output .buffer {
overflow-y: scroll;
box-sizing: border-box;
padding: var(--inner-padding);
}
.ifplayer .output .buffer:empty {
display: none;
}
.ifplayer .output .gridBuffer {
flex-shrink: 0;
max-height: 100%;
border-bottom: var(--separator-width) solid var(--main-color);
}
.ifplayer .output .textBuffer {
flex: 2 1;
outline: none;
scroll-behavior: smooth;
}
.ifplayer .output .textBuffer > br:first-child,
.ifplayer .output .gridBuffer > br:first-child,
.ifplayer .output .textBuffer > br:last-child,
.ifplayer .output .gridBuffer > br:last-child,
.ifplayer .output .textBuffer > br + br + br,
.ifplayer .output .gridBuffer > br + br + br {
display: none;
}
.ifplayer .output .textBuffer .message.input {
scroll-margin-top: var(--inner-padding);
color: var(--input-color);
}
.ifplayer .output .textBuffer .message.emphasized,
.ifplayer .output .textBuffer .message.subheader {
color: var(--accent-color);
}