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

View file

@ -2,6 +2,8 @@ import { useEffect, useRef, useState } from 'preact/hooks'
import MenuButton from './MenuButton/MenuButton' import MenuButton from './MenuButton/MenuButton'
import * as s from './InputBox.module.scss'
/* eslint-disable */ /* eslint-disable */
const keyCodes = { const keyCodes = {
KEY_BACKSPACE: 8, KEY_BACKSPACE: 8,
@ -147,9 +149,9 @@ export default function InputBox ({
} }
return ( return (
<section className='inputControls'> <section className={s.inputControls}>
<input {...inputHandlers[inputType]} <input {...inputHandlers[inputType]}
className='inputBox' className={s.inputBox}
ref={inputEl} ref={inputEl}
value={inputText} value={inputText}
autofocus 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 import ThemeSelector from
'~/src/components/ThemeSelector/ThemeSelector' '~/src/components/ThemeSelector/ThemeSelector'
import './MenuOverlay.css' import * as s from './MenuOverlay.module.scss'
export default function MenuOverlay ({ export default function MenuOverlay ({
themeEngine, onFullscreenRequest, menuOpen, setMenuOpen, themeEngine, onFullscreenRequest, menuOpen, setMenuOpen,
@ -35,7 +35,7 @@ export default function MenuOverlay ({
return ( return (
<dialog ref={dialog} className='menu'> <dialog ref={dialog} className={s.menu}>
<section> <section>
<div> <div>
<button <button
@ -46,7 +46,7 @@ export default function MenuOverlay ({
</button> </button>
</div> </div>
<div className='appearance'> <div className={s.appearance}>
<button <button
onClick={() => { onClick={() => {
dialog.current.close() dialog.current.close()
@ -68,7 +68,7 @@ export default function MenuOverlay ({
</label> </label>
</div> </div>
<div className='navigation'> <div className={s.navigation}>
<Link href="/" tabIndex={0}> <Link href="/" tabIndex={0}>
ElseIfPlayer ElseIfPlayer
</Link> </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 { 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 }) { export default function GridBuffer ({ inbox, currentWindow }) {
const [prevMessages, setPrevMessages] = useState([]) const [prevMessages, setPrevMessages] = useState([])
@ -70,8 +72,7 @@ export default function GridBuffer ({ inbox, currentWindow }) {
}, [inbox, currentWindow, prevMessages]) }, [inbox, currentWindow, prevMessages])
return ( return (
<section <section className={[s.buffer, s.gridBuffer].join(' ')}>
className='buffer gridBuffer'>
{messages.map(TextMessage)} {messages.map(TextMessage)}
</section> </section>
) )

View file

@ -1,6 +1,8 @@
import { useEffect, useRef, useState } from 'preact/hooks' 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) => const isFakeStatus = (w) =>
w.height < 5 w.height < 5
@ -75,17 +77,19 @@ export default function TextBuffer ({ inbox, currentWindow }) {
}, 0) }, 0)
}, [currentWindow, inbox]) }, [currentWindow, inbox])
const classes = [ const classes = () => [
s.buffer,
isFakeStatus(currentWindow) isFakeStatus(currentWindow)
? 'gridBuffer' ? s.gridBuffer
: 'textBuffer', : s.textBuffer,
'buffer'].join(' ') ].join(' ')
return ( return (
<section <section
tabindex='0' tabindex='0'
ref={textBufferEl} ref={textBufferEl}
className={classes}> className={classes()}
>
{messages.map(TextMessage)} {messages.map(TextMessage)}
</section> </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 CheapGlkOte from 'cheap-glkote'
import TextBuffer from './OutputBox/TextBuffer' import TextBuffer from './OutputBox/TextBuffer/TextBuffer'
import GridBuffer from './OutputBox/GridBuffer' import GridBuffer from './OutputBox/GridBuffer/GridBuffer'
import InputBox from './InputBox/InputBox' import InputBox from './InputBox/InputBox'
import Status from './Status/Status' import Status from './Status/Status'
@ -13,7 +13,7 @@ import {
unhandledRejectionHandler, unhandledRejectionHandler,
} from './common/playerHandlers' } from './common/playerHandlers'
import './player.css' import * as s from './Player.module.scss'
const INITIAL_STATUS = { const INITIAL_STATUS = {
stage: 'loading', stage: 'loading',
@ -104,14 +104,16 @@ export default function Player ({
return status.stage !== 'ready' return status.stage !== 'ready'
? (<Status {...status} />) ? (<Status {...status} />)
: (<section className='ifplayer'> : (<section className={s.elseifplayer}>
<section className='output'>{ <section className={s.output}>
windows {
windows
.sort(byTop) .sort(byTop)
.filter(singleWindow .filter(singleWindow
? ({ id }) => id === currentWindowId ? ({ id }) => id === currentWindowId
: () => true) : () => true)
.map(textWindow(inbox))} .map(textWindow(inbox))
}
</section> </section>
<InputBox {...{ <InputBox {...{
inputType, 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);
}