Funcionnal custom checkboxes, fixed small card component and added the ability to launch both backend and frontend at once

This commit is contained in:
Gu://em_ 2025-05-25 13:16:10 +02:00
parent f8bf646565
commit ca96f57fb8
17 changed files with 1438 additions and 77 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
node_modules/

View file

@ -1,6 +1,6 @@
{ {
"name": "wf-radio-backend", "name": "wf-radio-backend",
"version": "1.0.0", "version": "Alpha 1",
"description": "", "description": "",
"main": "server.js", "main": "server.js",
"scripts": { "scripts": {

View file

@ -1,7 +1,7 @@
{ {
"name": "wf-radio-frontend", "name": "wf-radio-frontend",
"private": true, "private": true,
"version": "0.0.0", "version": "Alpha 1",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e8eaed"><path d="M382-221.91 135.91-468l75.66-75.65L382-373.22l366.43-366.43L824.09-664 382-221.91Z"/></svg>

After

Width:  |  Height:  |  Size: 207 B

View file

@ -1,8 +1,10 @@
//TODO made by AI
import { h } from 'preact'; import { h } from 'preact';
import { useState } from 'preact/hooks'; import { useState } from 'preact/hooks';
import styles from './checkbox.module.css'; import styles from './checkbox.module.css';
// Assets
import Checkmark from '../../assets/checkmark.svg'
function Checkbox({ id, name, value, checked: initialChecked, onChange, label }) { function Checkbox({ id, name, value, checked: initialChecked, onChange, label }) {
const [isChecked, setIsChecked] = useState(initialChecked || false); const [isChecked, setIsChecked] = useState(initialChecked || false);
@ -24,11 +26,8 @@ function Checkbox({ id, name, value, checked: initialChecked, onChange, label })
onChange={handleChange} onChange={handleChange}
className={styles.nativeCheckbox} // Hide this element className={styles.nativeCheckbox} // Hide this element
/> />
<label htmlFor={id} className={styles.checkbox}> <label htmlFor={id} className={styles.customCheckbox}>
{/* This div will be our custom visual checkbox */} {isChecked && <img src={Checkmark} className={styles.checkmark} ></img>}
<div className={styles.checkmark}>
{isChecked && <span>&#10003;</span>} {/* Checkmark icon */}
</div>
{label && <span className={styles.label}>{label}</span>} {label && <span className={styles.label}>{label}</span>}
</label> </label>
</div> </div>

View file

@ -1,51 +1,66 @@
/*TODO made by AI */
.checkboxContainer { .checkboxContainer {
margin: 1.5em .5em;
/* width: 100%; */
display: flex; display: flex;
align-items: center; align-items: center;
cursor: pointer;
user-select: none; /* Prevent text selection on click */ user-select: none;
} }
.nativeCheckbox { .nativeCheckbox {
position: absolute; position: absolute;
opacity: 0;
cursor: pointer;
height: 0; height: 0;
width: 0; width: 0;
user-select: none;
} }
.customCheckbox { .customCheckbox {
position: relative; position: relative;
height: 1.5em;
width: 1.5em;
min-height: 1em;
min-width: 1em;
width: 1.7em; /* Adjust size as needed */
height: 1.7em;
background-color: transparent;
border: #eaeaea .1rem solid;
border-radius: .2em;
display: inline-block; display: inline-block;
width: 20px; /* Adjust size as needed */ box-sizing: border-box;
height: 20px; user-select: none;
background-color: #eee;
border: 1px solid #ccc; transition: 200ms;
border-radius: 3px; /* Optional rounded corners */
} }
.customCheckbox:hover input ~ .checkmark { .customCheckbox:hover {
background-color: #ddd; background-color: #eaeaea20;
} }
.nativeCheckbox:checked ~ .customCheckbox { .nativeCheckbox:checked ~ .customCheckbox {
background-color: #2196F3; /* Active color */
border: 1px solid #2196F3; background-color: #353be5;
border: #353be5 .1rem solid;
/* border-radius: .3em; */
}
.nativeCheckbox:checked ~ .customCheckbox:hover {
border: #6b70f7 .1rem solid;
filter: drop-shadow(#353be580 0 0 .7em);
}
.label {
position: absolute;
top: 0;
margin-left: 2.5em;
} }
.checkmark { .checkmark {
position: absolute; position: absolute;
top: 0; transform: scale(1.2);
left: 0;
width: 100%;
height: 100%; height: 100%;
display: flex;
justify-content: center;
align-items: center;
color: white; /* Checkmark color */
font-size: 16px; /* Adjust checkmark size */
}
.label {
margin-left: 8px;
} }

View file

@ -1,6 +1,6 @@
.rowCard { .rowCard {
height: 7rem; min-height: 7rem;
margin-bottom: 1rem; margin-bottom: 1rem;
background-color: #1a1a1a; background-color: #1a1a1a;

View file

@ -22,6 +22,8 @@ function SmallCard({item, variant, href}) {
const item_page = "/mods/" + item.name; const item_page = "/mods/" + item.name;
return ( return (
<a className={styles.Card} href={href}> <a className={styles.Card} href={href}>
<img src={Banner} className={styles.banner}></img>
<img src={Thumbnail} className={styles.thumbnail}></img>
<div className={styles.CardText}> <div className={styles.CardText}>
{item.display_name} {item.display_name}
</div> </div>

View file

@ -1,6 +1,9 @@
.emptyCard { .emptyCard {
height: 100%; height: 100%;
width: 22em; width: 22em;
min-width: 22em;
min-height: 13rem;
align-items: center; align-items: center;
display: flex; display: flex;
@ -25,27 +28,66 @@
} }
.Card { .Card {
height: 100%;
width: 22em;
align-items: center;
display: flex;
background-color: #141414; position: relative;
height: 100%;
min-width: 22em;
min-height: 13rem;
background-color: #101010;
border: #3a3a3a .1rem solid; border: #3a3a3a .1rem solid;
border-radius: 1rem; border-radius: 1rem;
box-sizing: border-box; box-sizing: border-box;
overflow: hidden;
} }
.CardText { .CardText {
padding: 1em; margin-left: 7rem;
width: 100%; margin-top: .2rem;
color: #9a9a9a; color: #eaeaea;
/* font-weight: 600; */
text-align: center; font-size: 1.3rem;
vertical-align: middle;
user-select: none; user-select: none;
}
.banner {
width: 100%;
height: 40%;
border-radius: 1rem 1rem 0 0;
filter: brightness(50%);
object-fit: cover;
}
.thumbnail {
position: absolute;
left: 1rem;
top: 25%;
width: 5rem;
height: 5rem;
padding: .5rem;
background-color: #101010;
border: #3a3a3a .1rem solid;
border-radius: 1rem;
box-sizing: border-box;
}
.Card:hover {
filter: drop-shadow(#353be515 0 0 1em);
transform: scale(1.01);
border-color: #6b70f7;
} }

View file

@ -92,7 +92,7 @@ function DashboardPage() {
return ( return (
<> <>
{base_page} {base_page}
<div class='container'> <div class={styles.container}>
<p>Loading</p> <p>Loading</p>
</div> </div>
</> </>
@ -103,7 +103,7 @@ function DashboardPage() {
return ( return (
<> <>
{base_page} {base_page}
<div class='container'> <div class={styles.container}>
<p>Error: {creations_error}</p> <p>Error: {creations_error}</p>
</div> </div>
</> </>
@ -113,7 +113,7 @@ function DashboardPage() {
return ( return (
<> <>
{base_page} {base_page}
<div class='container'> <div className={styles.container}>
<div className={styles.category}> <div className={styles.category}>
<p className={styles.title}> <p className={styles.title}>
Favorites Favorites
@ -148,6 +148,8 @@ function DashboardPage() {
href='/create/mod' href='/create/mod'
/> />
</div> </div>
</div>
<div style="height: 2rem"/>
</div> </div>
<div className={styles.toolbar}> <div className={styles.toolbar}>
<div className={styles.toolbarRightItems}> <div className={styles.toolbarRightItems}>
@ -159,7 +161,6 @@ function DashboardPage() {
</Button> </Button>
</div> </div>
</div> </div>
</div>
</> </>
); );
} }

View file

@ -9,12 +9,16 @@ import { listMods } from '../services/mods';
import FiltersPanel from '../components/Filters/panel' import FiltersPanel from '../components/Filters/panel'
import SearchBar from '../components/Fields/search'; import SearchBar from '../components/Fields/search';
// Assets
import '../styles/filters_bar.css'
// Images // Images
import logo from '../assets/logo.png' import logo from '../assets/logo.png'
// Styles // Components
import GridCard from '../components/Cards/grid'; import GridCard from '../components/Cards/grid';
import RowCard from '../components/Cards/row'; import RowCard from '../components/Cards/row';
import Checkbox from '../components/Buttons/checkbox';
function ModsPage() { function ModsPage() {
@ -67,7 +71,19 @@ function ModsPage() {
</a> </a>
<FiltersPanel> <FiltersPanel>
<SearchBar onSearch={handleSearch} /> <SearchBar onSearch={handleSearch} />
<div class='filterTitle'>
Platform
</div>
<div class='filterOptions'>
<Checkbox
id='client'
label='Client'
/>
<Checkbox
id='server'
label='Server'
/>
</div>
</FiltersPanel> </FiltersPanel>
</> </>
); );

View file

@ -9,6 +9,7 @@ import { deleteUser } from '../services/users';
// Components // Components
import Button from '../components/Buttons/button'; import Button from '../components/Buttons/button';
import Checkbox from '../components/Buttons/checkbox';
// Styles // Styles
import styles from '../styles/settings.module.css' import styles from '../styles/settings.module.css'
@ -97,16 +98,12 @@ function SettingsPage() {
<option value="dark">Dark</option> <option value="dark">Dark</option>
</select> </select>
</p> </p>
<p> <Checkbox
<label> id='notifications'
Enable Notifications: label='Enable Notifications'
<input
type="checkbox"
checked={notificationsEnabled} checked={notificationsEnabled}
onChange={handleNotificationsChange} onChange={handleNotificationsChange}
/> />
</label>
</p>
</> </>
) : ) :
tab === 'user' ? ( tab === 'user' ? (

View file

@ -129,6 +129,12 @@ h1 {
/* border: #3a3a3a solid; */ /* border: #3a3a3a solid; */
border-width: .1em; border-width: .1em;
border-radius: .5rem; border-radius: .5rem;
display: flex;
flex-direction: column;
gap: .5rem;
overflow: scroll;
} }
.container { .container {

View file

@ -1,3 +1,24 @@
.container {
position: absolute;
top: 11rem;
right: 4rem;
left: 22rem;
bottom: 4rem;
padding: 3rem;
padding-top: 2rem;
background-color: #1a1a1a;
color: #eaeaea;
border: #3a3a3a solid;
border-width: .1em;
border-radius: .5rem;
overflow: scroll;
}
.category { .category {
margin-top: 0; margin-top: 0;
} }
@ -14,8 +35,10 @@
.tiles { .tiles {
height: 13rem; height: 14rem;
margin-bottom: 3rem; margin-bottom: 2rem;
padding: 1rem;
margin-right: -3rem;
overflow-x: scroll; overflow-x: scroll;
overflow-y: visible; overflow-y: visible;
@ -26,20 +49,29 @@
.toolbar { .toolbar {
position: absolute; position: absolute;
bottom: 0; right: 5rem;
left: 0; left: 23rem;
right: 0; bottom: 5rem;
height: 5rem; height: 3rem;
padding: .5rem; min-width: 30rem;
padding: 1rem;
background-color: #141414;
border: #3a3a3a .1rem solid;
border-radius: .5rem;
display: flex;
justify-content: space-between;
align-items: center;
/* background-color: #9a9a9a; */
} }
.toolbarRightItems { .toolbarRightItems {
position: absolute; /* position: absolute; */
right: 1rem; /* right: 1rem; */
bottom: 1rem; /* bottom: 1rem; */
margin-left: auto;
} }
.createButton { .createButton {

View file

@ -0,0 +1,9 @@
.filterTitle {
font-weight: 600;
font-size:1.3em;
margin-top: 1.4em
}
.filterOptions {
font-size:0.9em;
}

20
package.json Normal file
View file

@ -0,0 +1,20 @@
{
"name": "wf-radio",
"version": "1.0.0",
"description": "",
"scripts": {
"start:frontend": "cd frontend && pnpm dev",
"start:backend": "cd backend && pnpm start",
"build:frontend": "cd frontend && pnpm build",
"start:dev": "npm-run-all --parallel start:frontend start:backend",
"start:prod": "npm-run-all --parallel build:frontend start:backend",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"packageManager": "pnpm@10.11.0",
"devDependencies": {
"npm-run-all": "^4.1.5"
}
}

1220
pnpm-lock.yaml Normal file

File diff suppressed because it is too large Load diff