Styling pages WIP

This commit is contained in:
2025-02-20 20:31:26 +01:00
parent 1cbcb8ce4c
commit 80dd1b48aa
15 changed files with 371 additions and 33 deletions
+13 -6
View File
@@ -5,14 +5,21 @@ import Languages from 'pages/Languages';
import Typing from 'pages/Typing'; import Typing from 'pages/Typing';
import NotFound from 'pages/NotFound'; import NotFound from 'pages/NotFound';
import Footer from 'components/Footer';
function App() { function App() {
return ( return (
<Routes> <>
<Route index element={<Home />} /> <div className='app'>
<Route path='languages' element={<Languages />} /> <Routes>
<Route path='typing/:lang' element={<Typing />} /> <Route index element={<Home />} />
<Route path='*' element={<NotFound />} /> <Route path='languages' element={<Languages />} />
</Routes> <Route path='typing/:lang' element={<Typing />} />
<Route path='*' element={<NotFound />} />
</Routes>
</div>
<Footer />
</>
); );
} }
+7 -2
View File
@@ -1,5 +1,10 @@
.code { .code-container {
padding: 1rem; min-width: 500px;
padding: 1.5rem;
border-radius: 0.75rem;
background: var(--black);
} }
.pending, .space { .pending, .space {
+1 -1
View File
@@ -73,7 +73,7 @@ function Code({ code, loaded }: CodeProps) {
}, [timer, characters]); }, [timer, characters]);
return ( return (
<div className='code'> <div className='code-container'>
{code.split('').map((char, index) => renderCharacter(code, characters, loaded, char, index))} {code.split('').map((char, index) => renderCharacter(code, characters, loaded, char, index))}
</div> </div>
); );
+10
View File
@@ -0,0 +1,10 @@
footer {
text-align: center;
width: 100%;
min-height: 5vh;
}
footer a {
color: var(--crimson);
}
+11
View File
@@ -0,0 +1,11 @@
import './index.css';
function Footer() {
return (
<footer>
<p><a href='https://github.com/hazemKrimi/touch-programming' target='_blank' rel="noreferrer">Source code</a> Made by <a href='https://hazemkrimi.tech' target='_blank' rel="noreferrer">Hazem Krimi</a></p>
</footer>
);
}
export default Footer;
+11 -5
View File
@@ -1,6 +1,12 @@
.score { .stats-container {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
padding: 1rem;
gap: 2rem;
padding: 1.5rem;
border-radius: 0.75rem;
background: var(--black);
} }
+1 -1
View File
@@ -17,7 +17,7 @@ function Stats({ loaded }: StatsProps) {
if (!loaded) return; if (!loaded) return;
return ( return (
<div className='score'> <div className='stats-container'>
{renderTimer(timer)} {renderTimer(timer)}
<p>WPM: {Math.round(score)}</p> <p>WPM: {Math.round(score)}</p>
<p>Accuracy: {Math.round(accuracy)}%</p> <p>Accuracy: {Math.round(accuracy)}%</p>
+28
View File
@@ -34,3 +34,31 @@ export const KEYS_TO_DISABLE = [
'ArrowLeft', 'ArrowLeft',
'ArrowRight', 'ArrowRight',
]; ];
export const SUPPORTED_LANGUAGES = [
'javascript',
'typescript',
'python',
'rust',
'golang',
'java',
'ruby',
'php',
'swift',
'kotlin',
'dart',
'scala',
'elixir',
'haskell',
'clojure',
'lua',
'r',
'perl',
'bash',
'powershell',
'pascal',
'ocaml',
'c',
'c++',
'fortran'
];
+52 -5
View File
@@ -1,4 +1,9 @@
:root { :root {
--black: #131314;
--white: #dddddd;
--crimson: #bd1839;
--background: #1d1b1b;
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5; line-height: 1.5;
font-weight: 400; font-weight: 400;
@@ -12,10 +17,52 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
body { * {
margin: 0; margin: 0;
display: flex; padding: 0;
place-items: center; }
min-width: 320px;
min-height: 100vh; ::-webkit-scrollbar {
width: 0;
height: 0;
background: transparent;
}
::-webkit-scrollbar-thumb {
background: transparent;
}
::selection {
background: var(--crimson);
color: var(--white);
}
a {
text-decoration: none;
color: var(--white);
}
body {
background: var(--background);
color: var(--white);
}
body::-webkit-scrollbar {
width: 0.5rem;
}
body::-webkit-scrollbar-thumb {
background-color: var(--crimson);
}
.app {
min-height: 95vh;
}
@media (min-width: 1441px) {
.app {
width: 1368px;
margin: 0 auto;
}
} }
+98 -2
View File
@@ -1,3 +1,99 @@
.container { .home-container {
text-align: left; padding: 0rem 3rem;
margin-bottom: 1rem;
}
@media (max-width: 768px) {
.home-container {
padding: 0rem 1rem;
}
}
header {
margin: 0 auto;
padding: 2.5rem 1.25rem;
text-align: center;
}
header h1 {
font-size: 3.5rem;
font-weight: bold;
margin-bottom: 1.5rem;
color: var(--crimson);
}
header p {
font-size: 1.5rem;
font-weight: 400;
margin-bottom: 2.5rem;
color: var(--white);
}
header .cta {
all: unset;
cursor: pointer;
background: var(--crimson);
color: var(--white);
border-radius: 0.75rem;
box-shadow: none;
padding: 1rem 2rem;
font-size: 1.25rem;
font-weight: bold;
text-decoration: none;
}
.features {
margin-top: 2rem;
padding: 2.5rem 1.25rem;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
align-items: stretch;
gap: 3rem;
}
.feature, .benefit {
padding: 1.5rem;
border-radius: 0.75rem;
background: var(--black);
}
.feature h3, .benefit h3 {
font-size: 1.5rem;
font-weight: bold;
margin-bottom: 1rem;
}
.benefits {
margin-top: 2rem;
padding: 2.5rem 1.25rem;
}
.benefits h2 {
font-size: 3.5rem;
font-weight: bold;
text-align: center;
margin-bottom: 1.5rem;
color: var(--crimson);
}
.benefits-wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
align-items: stretch;
gap: 3rem;
} }
+49 -2
View File
@@ -1,9 +1,56 @@
import { NavLink } from 'react-router';
import './index.css'; import './index.css';
function Home() { function Home() {
return ( return (
<div className='container'> <div className='home-container'>
<h1>Home</h1> <header>
<h1>Touch Programming</h1>
<p>Master touch typing with real code snippets from your favorite programming languages, powered by AI.</p>
<NavLink to='/languages'>
<button className='cta'>
Start Typing
</button>
</NavLink>
</header>
<section className='features'>
<div className='feature'>
<h3>Real Code Snippets</h3>
<p>
Practice with actual code examples from popular repositories, making your learning relevant to real-world
programming.
</p>
</div>
<div className='feature'>
<h3>Multiple Languages</h3>
<p>
Choose from Python, JavaScript, TypeScript, Rust, and more. Practice with the languages you use daily.
</p>
</div>
<div className='feature'>
<h3>AI Powered</h3>
<p>
Code is generated with the help of the Open Source LLM Models.
</p>
</div>
</section>
<section className='benefits'>
<h2>Why Practice Touch Programming?</h2>
<div className='benefits-wrapper'>
<div className='benefit'>
<h3>Boost Productivity</h3>
<p>Increase your coding speed and reduce errors with proper typing technique</p>
</div>
<div className='benefit'>
<h3>Learn Syntax</h3>
<p>
Familiarize yourself with language syntax while improving your typing speed
</p>
</div>
</div>
</section>
</div> </div>
); );
} }
+42 -2
View File
@@ -1,3 +1,43 @@
.container { .languages-container {
text-align: left; padding: 0rem 3rem;
margin-bottom: 1rem;
}
@media (max-width: 768px) {
.languages-container {
padding: 0rem 1rem;
}
}
header {
margin: 0 auto;
padding: 2.5rem 1.25rem;
text-align: center;
}
header h1 {
font-size: 3.5rem;
font-weight: bold;
margin-bottom: 1.5rem;
color: var(--crimson);
}
.languages-wrapper {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
align-items: stretch;
gap: 3rem;
}
.language {
padding: 1.5rem;
border-radius: 0.75rem;
background: var(--black);
text-transform: capitalize;
} }
+17 -2
View File
@@ -1,9 +1,24 @@
import { NavLink } from 'react-router';
import { SUPPORTED_LANGUAGES } from 'constants/default';
import './index.css'; import './index.css';
function Languages() { function Languages() {
return ( return (
<div className='container'> <div className='languages-container'>
<h1>Languages</h1> <header>
<h1>Choose Your Preferred Language</h1>
</header>
<div className='languages-wrapper'>
{SUPPORTED_LANGUAGES.map((lang) => (
<NavLink to={`/typing/${lang}`} key={lang}>
<div className='language'>
<h2>{lang}</h2>
</div>
</NavLink>
))}
</div>
</div> </div>
); );
} }
+23 -2
View File
@@ -1,5 +1,26 @@
.container { .typing-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
column-gap: 1rem; align-items: center;
gap: 2rem;
margin-bottom: 1rem;
}
header {
margin: 0 auto;
padding: 2.5rem 1.25rem;
text-align: center;
}
header h1 {
font-size: 3.5rem;
font-weight: bold;
margin-bottom: 1.5rem;
color: var(--crimson);
text-transform: capitalize;
} }
+8 -3
View File
@@ -1,4 +1,5 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { useParams } from 'react-router';
import TypingContextProvider from 'contexts/typing'; import TypingContextProvider from 'contexts/typing';
@@ -6,7 +7,6 @@ import Code from 'components/Code';
import Stats from 'components/Stats'; import Stats from 'components/Stats';
import './index.css'; import './index.css';
import { useParams } from 'react-router';
function Typing() { function Typing() {
const {lang} = useParams(); const {lang} = useParams();
@@ -39,11 +39,16 @@ function Typing() {
setCode((prev) => prev.trim()); setCode((prev) => prev.trim());
setLoaded(true); setLoaded(true);
})(); })();
}, []); }, [lang]);
return ( return (
<TypingContextProvider> <TypingContextProvider>
<div className='container'> <div className='typing-container'>
<header>
<h1>
Practice Typing in {lang}
</h1>
</header>
<Code code={code} loaded={loaded} /> <Code code={code} loaded={loaded} />
<Stats loaded={loaded} /> <Stats loaded={loaded} />
</div> </div>