chore: remove usage of styled-jsx

This commit is contained in:
Divlo 2022-12-13 22:31:32 +01:00
parent e8a9ce4e69
commit 67a1699102
No known key found for this signature in database
GPG Key ID: 8F9478F220CE65E9
23 changed files with 345 additions and 454 deletions

View File

@ -10,8 +10,6 @@
"editorconfig.editorconfig",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"divlo.vscode-styled-jsx-syntax",
"divlo.vscode-styled-jsx-languageserver",
"bradlc.vscode-tailwindcss",
"mikestead.dotenv",
"davidanson.vscode-markdownlint",

View File

@ -3,8 +3,6 @@
"editorconfig.editorconfig",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"divlo.vscode-styled-jsx-syntax",
"divlo.vscode-styled-jsx-languageserver",
"bradlc.vscode-tailwindcss",
"mikestead.dotenv",
"davidanson.vscode-markdownlint",

View File

@ -16,7 +16,6 @@ export const UserProfile: React.FC<UserProfileProps> = (props) => {
const { t } = useTranslation()
return (
<>
<div className='relative flex h-full flex-col items-center justify-center'>
<div className='transition'>
<div className='max-w-[1000px] px-12'>
@ -100,12 +99,5 @@ export const UserProfile: React.FC<UserProfileProps> = (props) => {
</div>
</div>
</div>
<style jsx global>{`
#application-page-content {
overflow-x: hidden;
}
`}</style>
</>
)
}

View File

@ -1,17 +1,24 @@
import useTranslation from 'next-translate/useTranslation'
import Link from 'next/link'
export interface ErrorPageProps {
import type { FooterProps } from './Footer'
import { Footer } from './Footer'
import { Header } from './Header'
export interface ErrorPageProps extends FooterProps {
statusCode: number
message: string
}
export const ErrorPage: React.FC<ErrorPageProps> = (props) => {
const { message, statusCode } = props
const { message, statusCode, version } = props
const { t } = useTranslation()
return (
<>
<div className='flex h-screen flex-col pt-0'>
<Header />
<main className='flex min-w-full flex-1 flex-col items-center justify-center'>
<h1 className='my-6 text-4xl font-semibold'>
{t('errors:error')}{' '}
<span
@ -30,25 +37,9 @@ export const ErrorPage: React.FC<ErrorPageProps> = (props) => {
{t('errors:return-to-home-page')}
</Link>
</p>
<style jsx global>
{`
main {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-width: 100vw;
flex: 1;
}
#__next {
display: flex;
flex-direction: column;
padding-top: 0;
height: 100vh;
}
`}
</style>
</main>
<Footer version={version} />
</div>
</>
)
}

View File

@ -0,0 +1,78 @@
import { useEffect, useState } from 'react'
import classNames from 'clsx'
import { useTheme } from 'next-themes'
export const SwitchTheme: React.FC = () => {
const [mounted, setMounted] = useState(false)
const { theme, setTheme } = useTheme()
useEffect(() => {
setMounted(true)
}, [])
if (!mounted) {
return null
}
const handleClick = (): void => {
setTheme(theme === 'dark' ? 'light' : 'dark')
}
return (
<div
className='flex items-center'
data-cy='switch-theme-click'
onClick={handleClick}
>
<div className='relative inline-block cursor-pointer touch-pan-x select-none border-0 bg-transparent p-0'>
<div className='h-[24px] w-[50px] rounded-[30px] bg-[#4d4d4d] p-0 text-white transition-all duration-200 ease-in-out'>
<div
data-cy='switch-theme-dark'
className={classNames(
'absolute top-0 bottom-0 left-[8px] mt-auto mb-auto h-[10px] w-[14px] leading-[0] transition-opacity duration-[250ms] ease-in-out',
{
'opacity-100': theme === 'dark',
'opacity-0': theme === 'light'
}
)}
>
<span className='relative flex h-[10px] w-[10px] items-center justify-center'>
🌜
</span>
</div>
<div
data-cy='switch-theme-light'
className={classNames(
'absolute right-[10px] top-0 bottom-0 mt-auto mb-auto h-[10px] w-[10px] leading-[0]',
{
'opacity-100': theme === 'light',
'opacity-0': theme === 'dark'
}
)}
>
<span className='relative flex h-[10px] w-[10px] items-center justify-center'>
🌞
</span>
</div>
</div>
<div
className={classNames(
'absolute top-[1px] box-border h-[22px] w-[22px] rounded-[50%] bg-[#fafafa] text-white transition-all duration-[250ms] ease-in-out',
{
'left-[27px]': theme === 'dark',
'left-0': theme === 'light'
}
)}
style={{ border: '1px solid #4d4d4d' }}
/>
<input
data-cy='switch-theme-input'
type='checkbox'
aria-label='Dark mode toggle'
className='absolute m-[-1px] h-[1px] w-[1px] overflow-hidden border-0 p-0'
defaultChecked
/>
</div>
</div>
)
}

View File

@ -1,126 +0,0 @@
import { useEffect, useState } from 'react'
import { useTheme } from 'next-themes'
export const SwitchTheme: React.FC = () => {
const [mounted, setMounted] = useState(false)
const { theme, setTheme } = useTheme()
useEffect(() => {
setMounted(true)
}, [])
if (!mounted) {
return null
}
const handleClick = (): void => {
setTheme(theme === 'dark' ? 'light' : 'dark')
}
return (
<>
<div
className='flex items-center'
data-cy='switch-theme-click'
onClick={handleClick}
>
<div className='toggle-theme-button relative inline-block cursor-pointer bg-transparent'>
<div className='toggle-track'>
<div
data-cy='switch-theme-dark'
className='toggle-track-check absolute'
>
<span className='toggle_Dark relative flex items-center justify-center'>
🌜
</span>
</div>
<div
data-cy='switch-theme-light'
className='toggle-track-x absolute'
>
<span className='toggle_Light relative flex items-center justify-center'>
🌞
</span>
</div>
</div>
<div className='toggle-thumb absolute' />
<input
data-cy='switch-theme-input'
type='checkbox'
aria-label='Dark mode toggle'
className='toggle-screenreader-only absolute overflow-hidden'
defaultChecked
/>
</div>
</div>
<style jsx>
{`
.toggle-theme-button {
touch-action: pan-x;
border: 0;
padding: 0;
user-select: none;
}
.toggle-track {
width: 50px;
height: 24px;
padding: 0;
border-radius: 30px;
background-color: #4d4d4d;
transition: all 0.2s ease;
color: #fff;
}
.toggle-track-check {
width: 14px;
height: 10px;
top: 0;
bottom: 0;
margin-top: auto;
margin-bottom: auto;
line-height: 0;
left: 8px;
opacity: ${theme === 'dark' ? 1 : 0};
transition: opacity 0.25s ease;
}
.toggle-track-x {
width: 10px;
height: 10px;
top: 0;
bottom: 0;
margin-top: auto;
margin-bottom: auto;
line-height: 0;
right: 10px;
opacity: ${theme === 'dark' ? 0 : 1};
}
.toggle_Dark,
.toggle_Light {
height: 10px;
width: 10px;
}
.toggle-thumb {
left: ${theme === 'dark' ? '27px' : '0px'};
width: 22px;
height: 22px;
border: 1px solid #4d4d4d;
border-radius: 50%;
background-color: #fafafa;
box-sizing: border-box;
transition: all 0.25s ease;
top: 1px;
color: #fff;
}
.toggle-screenreader-only {
border: 0;
clip: rect(0 0 0 0);
height: 1px;
margin: -1px;
padding: 0;
width: 1px;
}
`}
</style>
</>
)
}

View File

@ -1 +0,0 @@
export * from './SwitchTheme'

View File

@ -1,20 +0,0 @@
export const ScrollableBody: React.FC<React.PropsWithChildren<{}>> = (
props
) => {
const { children } = props
return (
<>
{children}
<style jsx global>{`
body {
scrollbar-width: thin;
scrollbar-color: var(--scroll-bar-color) var(--scroll-bar-bg-color);
z-index: 1000;
height: calc(100vh - 64px);
overflow-y: auto;
}
`}</style>
</>
)
}

View File

@ -35,11 +35,8 @@ export const Input: React.FC<InputProps> = (props) => {
}
return (
<>
<div className='flex flex-col'>
<div
className={classNames('mt-6 mb-2 flex justify-between', className)}
>
<div className={classNames('mt-6 mb-2 flex justify-between', className)}>
<label className='pl-1' htmlFor={name}>
{label}
</label>
@ -66,7 +63,10 @@ export const Input: React.FC<InputProps> = (props) => {
<div
data-cy='password-eye'
onClick={handlePassword}
className='password-eye absolute cursor-pointer bg-[#f1f1f1] bg-cover'
style={{
backgroundImage: `url('/images/svg/icons/input/${inputType}.svg')`
}}
className='absolute top-3 right-4 z-10 h-5 w-5 cursor-pointer bg-[#f1f1f1] bg-cover'
/>
)}
<FormState
@ -76,19 +76,5 @@ export const Input: React.FC<InputProps> = (props) => {
/>
</div>
</div>
<style jsx>
{`
.password-eye {
top: 12px;
right: 16px;
z-index: 1;
width: 20px;
height: 20px;
background-image: url('/images/svg/icons/input/${inputType}.svg');
}
`}
</style>
</>
)
}

View File

@ -0,0 +1,39 @@
@keyframes progressSpinnerRotate {
100% {
transform: rotate(360deg);
}
}
@keyframes progressSpinnerDash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -35px;
}
100% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -124px;
}
}
.progressSpinnerSvg {
animation: progressSpinnerRotate 2s linear infinite;
height: 100%;
transform-origin: center center;
width: 100%;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.progressSpinnerCircle {
stroke-dasharray: 89, 200;
stroke-dashoffset: 0;
stroke: #27b05e;
animation: progressSpinnerDash 1.5s ease-in-out infinite;
stroke-linecap: round;
}

View File

@ -1,3 +1,5 @@
import styles from './Loader.module.css'
export interface LoaderProps {
width?: number
height?: number
@ -9,10 +11,14 @@ export const Loader: React.FC<LoaderProps> = (props) => {
return (
<div className={props.className}>
<div data-cy='progress-spinner' className='progress-spinner'>
<svg className='progress-spinner-svg' viewBox='25 25 50 50'>
<div
data-cy='progress-spinner'
className='relative my-0 mx-auto before:block before:pt-[100%] before:content-none'
style={{ width: `${width}px`, height: `${height}px` }}
>
<svg className={styles.progressSpinnerSvg} viewBox='25 25 50 50'>
<circle
className='progress-spinner-circle'
className={styles.progressSpinnerCircle}
cx='50'
cy='50'
r='20'
@ -22,60 +28,6 @@ export const Loader: React.FC<LoaderProps> = (props) => {
/>
</svg>
</div>
<style jsx>
{`
.progress-spinner {
position: relative;
margin: 0 auto;
width: ${width}px;
height: ${height}px;
}
.progress-spinner::before {
content: '';
display: block;
padding-top: 100%;
}
.progress-spinner-svg {
animation: progress-spinner-rotate 2s linear infinite;
height: 100%;
transform-origin: center center;
width: 100%;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
.progress-spinner-circle {
stroke-dasharray: 89, 200;
stroke-dashoffset: 0;
stroke: #27b05e;
animation: progress-spinner-dash 1.5s ease-in-out infinite;
stroke-linecap: round;
}
@keyframes progress-spinner-rotate {
100% {
transform: rotate(360deg);
}
}
@keyframes progress-spinner-dash {
0% {
stroke-dasharray: 1, 200;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -35px;
}
100% {
stroke-dasharray: 89, 200;
stroke-dashoffset: -124px;
}
}
`}
</style>
</div>
)
}

View File

@ -0,0 +1,11 @@
.buttonGoogle {
color: #000;
border: 1px solid #000;
}
.buttonMedia {
color: #fff;
border: none;
}
.button:focus {
box-shadow: 0 0 0 2px #27b05e;
}

View File

@ -3,6 +3,7 @@ import Image from 'next/image'
import classNames from 'clsx'
import type { ProviderOAuth } from '../../../models/OAuth'
import styles from './SocialMediaButton.module.css'
export type SocialMedia = ProviderOAuth
@ -52,27 +53,21 @@ export const SocialMediaButton: React.FC<SocialMediaButtonProps> = (props) => {
}, [socialMedia])
return (
<>
<button
{...rest}
className={classNames(className, 'button', givenClassName)}
style={{ background: socialMediaColor }}
className={classNames(
className,
styles.button,
{
[styles.buttonGoogle]: socialMedia === 'Google',
[styles.buttonMedia]: socialMedia !== 'Google'
},
givenClassName
)}
>
<SocialMediaChildren socialMedia={socialMedia} />
</button>
<style jsx>
{`
.button {
background: ${socialMediaColor};
color: ${socialMedia === 'Google' ? '#000' : '#fff'};
border: ${socialMedia === 'Google' ? '1px solid #000' : 'none'};
}
.button:focus {
box-shadow: 0 0 0 2px #27b05e;
}
`}
</style>
</>
)
}
@ -88,23 +83,20 @@ export const SocialMediaLink: React.FC<SocialMediaLinkProps> = (props) => {
}, [socialMedia])
return (
<>
<a {...rest} className={classNames(className, 'link', givenClassName)}>
<a
{...rest}
style={{ background: socialMediaColor }}
className={classNames(
className,
styles.button,
{
[styles.buttonGoogle]: socialMedia === 'Google',
[styles.buttonMedia]: socialMedia !== 'Google'
},
givenClassName
)}
>
<SocialMediaChildren socialMedia={socialMedia} />
</a>
<style jsx>
{`
.link {
background: ${socialMediaColor};
color: ${socialMedia === 'Google' ? '#000' : '#fff'};
border: ${socialMedia === 'Google' ? '1px solid #000' : 'none'};
}
.link:focus {
box-shadow: 0 0 0 2px #27b05e;
}
`}
</style>
</>
)
}

View File

@ -19,9 +19,7 @@ let server: Mockttp | null = null
export default defineConfig({
fixturesFolder: false,
video: false,
downloadsFolder: undefined,
screenshotOnRunFailure: false,
e2e: {
baseUrl: 'http://127.0.0.1:3000',
supportFile: false,
@ -62,7 +60,6 @@ export default defineConfig({
return config
}
},
component: {
devServer: {
framework: 'next',

View File

@ -3,9 +3,7 @@ import useTranslation from 'next-translate/useTranslation'
import { ErrorPage } from '../components/ErrorPage'
import { Head } from '../components/Head'
import { Header } from '../components/Header'
import type { FooterProps } from '../components/Footer'
import { Footer } from '../components/Footer'
const Error404: NextPage<FooterProps> = (props) => {
const { t } = useTranslation()
@ -14,12 +12,11 @@ const Error404: NextPage<FooterProps> = (props) => {
return (
<>
<Head title='Thream | 404' />
<Header />
<main className='flex flex-col md:mx-auto md:max-w-4xl lg:max-w-7xl'>
<ErrorPage statusCode={404} message={t('errors:page-not-found')} />
</main>
<Footer version={version} />
<ErrorPage
statusCode={404}
message={t('errors:page-not-found')}
version={version}
/>
</>
)
}

View File

@ -5,7 +5,6 @@ import { ErrorPage } from '../components/ErrorPage'
import { Head } from '../components/Head'
import { Header } from '../components/Header'
import type { FooterProps } from '../components/Footer'
import { Footer } from '../components/Footer'
const Error500: NextPage<FooterProps> = (props) => {
const { t } = useTranslation()
@ -16,10 +15,11 @@ const Error500: NextPage<FooterProps> = (props) => {
<Head title='Thream | 500' />
<Header />
<main className='flex flex-col md:mx-auto md:max-w-4xl lg:max-w-7xl'>
<ErrorPage statusCode={500} message={t('errors:server-error')} />
</main>
<Footer version={version} />
<ErrorPage
statusCode={500}
message={t('errors:server-error')}
version={version}
/>
</>
)
}

View File

@ -15,7 +15,6 @@ import { Input } from '../../components/design/Input'
import { Button } from '../../components/design/Button'
import { FormState } from '../../components/design/FormState'
import { authenticationFromServerSide } from '../../tools/authentication'
import { ScrollableBody } from '../../components/ScrollableBody'
import { userSchema } from '../../models/User'
import { api } from '../../tools/api'
import { useFormTranslation } from '../../hooks/useFormTranslation'
@ -60,7 +59,7 @@ const ForgotPassword: NextPage<FooterProps> = (props) => {
}
return (
<ScrollableBody>
<>
<Head title={`Thream | ${t('authentication:forgot-password')}`} />
<Header />
<Main>
@ -86,7 +85,7 @@ const ForgotPassword: NextPage<FooterProps> = (props) => {
/>
</Main>
<Footer version={version} />
</ScrollableBody>
</>
)
}

View File

@ -15,7 +15,6 @@ import { Input } from '../../components/design/Input'
import { Button } from '../../components/design/Button'
import { authenticationFromServerSide } from '../../tools/authentication'
import { AuthenticationForm } from '../../components/Authentication'
import { ScrollableBody } from '../../components/ScrollableBody'
import { api } from '../../tools/api'
import { userSchema } from '../../models/User'
import { useFormTranslation } from '../../hooks/useFormTranslation'
@ -55,7 +54,7 @@ const ResetPassword: NextPage<FooterProps> = (props) => {
}
return (
<ScrollableBody>
<>
<Head title={`Thream | ${t('authentication:reset-password')}`} />
<Header />
<Main>
@ -81,7 +80,7 @@ const ResetPassword: NextPage<FooterProps> = (props) => {
/>
</Main>
<Footer version={version} />
</ScrollableBody>
</>
)
}

View File

@ -7,19 +7,18 @@ import { Header } from '../../components/Header'
import type { FooterProps } from '../../components/Footer'
import { Footer } from '../../components/Footer'
import { authenticationFromServerSide } from '../../tools/authentication'
import { ScrollableBody } from '../../components/ScrollableBody'
const Signin: NextPage<FooterProps> = (props) => {
const { version } = props
const { t } = useTranslation()
return (
<ScrollableBody>
<>
<Head title={`Thream | ${t('authentication:signin')}`} />
<Header />
<Authentication mode='signin' />
<Footer version={version} />
</ScrollableBody>
</>
)
}

View File

@ -7,19 +7,18 @@ import { Header } from '../../components/Header'
import type { FooterProps } from '../../components/Footer'
import { Footer } from '../../components/Footer'
import { authenticationFromServerSide } from '../../tools/authentication'
import { ScrollableBody } from '../../components/ScrollableBody'
const Signup: NextPage<FooterProps> = (props) => {
const { version } = props
const { t } = useTranslation()
return (
<ScrollableBody>
<>
<Head title={`Thream | ${t('authentication:signup')}`} />
<Header />
<Authentication mode='signup' />
<Footer version={version} />
</ScrollableBody>
</>
)
}

View File

@ -11,14 +11,13 @@ import type { FooterProps } from '../components/Footer'
import { Footer } from '../components/Footer'
import { SocialMediaLink } from '../components/design/SocialMediaButton'
import { ButtonLink } from '../components/design/Button'
import { ScrollableBody } from '../components/ScrollableBody'
const Home: NextPage<FooterProps> = (props) => {
const { t } = useTranslation()
const { version } = props
return (
<ScrollableBody>
<>
<Head />
<Header />
<Main>
@ -71,7 +70,7 @@ const Home: NextPage<FooterProps> = (props) => {
</div>
</Main>
<Footer version={version} />
</ScrollableBody>
</>
)
}

View File

@ -12,9 +12,18 @@
@apply flex h-screen flex-col;
}
#application-page-content {
overflow-x: hidden;
}
body {
@apply bg-white font-headline text-black dark:bg-black dark:text-white;
overflow: hidden;
scrollbar-width: thin;
scrollbar-color: var(--scroll-bar-color) var(--scroll-bar-bg-color);
z-index: 1000;
height: calc(100vh - 64px);
overflow-y: auto;
}
.h-full-without-header {

View File

@ -1,4 +1,5 @@
module.exports = {
/** @type {import('tailwindcss').Config} */
const tailwindConfig = {
content: [
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}'
@ -31,3 +32,5 @@ module.exports = {
},
plugins: []
}
module.exports = tailwindConfig