diff --git a/frontend/src/app.jsx b/frontend/src/app.jsx
index 816f90e..0552b25 100644
--- a/frontend/src/app.jsx
+++ b/frontend/src/app.jsx
@@ -16,6 +16,7 @@ import ModCreationPage from './pages/mod_creation'
import ModpacksPage from './pages/modpacks';
+import DashboardPage from './pages/dashboard';
import LoginPage from './pages/login';
import RegisterPage from './pages/register';
import SettingsPage from './pages/settings';
@@ -45,6 +46,8 @@ export function App() {
+
+
diff --git a/frontend/src/assets/account.svg b/frontend/src/assets/account.svg
index 33cfc7b..6584d93 100644
--- a/frontend/src/assets/account.svg
+++ b/frontend/src/assets/account.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/frontend/src/assets/add.svg b/frontend/src/assets/add.svg
new file mode 100644
index 0000000..4132977
--- /dev/null
+++ b/frontend/src/assets/add.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/dashboard.svg b/frontend/src/assets/dashboard.svg
new file mode 100644
index 0000000..ef6ea42
--- /dev/null
+++ b/frontend/src/assets/dashboard.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/dashboard_add.svg b/frontend/src/assets/dashboard_add.svg
new file mode 100644
index 0000000..d08d973
--- /dev/null
+++ b/frontend/src/assets/dashboard_add.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/login.svg b/frontend/src/assets/login.svg
index 1bc327d..01a79fb 100644
--- a/frontend/src/assets/login.svg
+++ b/frontend/src/assets/login.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/frontend/src/assets/logout.svg b/frontend/src/assets/logout.svg
new file mode 100644
index 0000000..aa6e5b2
--- /dev/null
+++ b/frontend/src/assets/logout.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/search.svg b/frontend/src/assets/search.svg
new file mode 100644
index 0000000..9902d0a
--- /dev/null
+++ b/frontend/src/assets/search.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/assets/settings.svg b/frontend/src/assets/settings.svg
index 5eaeb73..4049836 100644
--- a/frontend/src/assets/settings.svg
+++ b/frontend/src/assets/settings.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/frontend/src/assets/settings_small.svg b/frontend/src/assets/settings_small.svg
new file mode 100644
index 0000000..5eaeb73
--- /dev/null
+++ b/frontend/src/assets/settings_small.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/components/Buttons/button.module.css b/frontend/src/components/Buttons/button.module.css
index b8688b5..52e86e7 100644
--- a/frontend/src/components/Buttons/button.module.css
+++ b/frontend/src/components/Buttons/button.module.css
@@ -47,4 +47,15 @@
.tertiary:hover {
background-color: #eaeaea16;
border-color: #eaeaea;
+}
+
+.delete {
+ background-color: #de3535;
+ border-color: #e85f5f;
+}
+
+.delete:hover {
+ border-color: #fb7777;
+ filter: drop-shadow(#de3535 0 0 .6em);
+
}
\ No newline at end of file
diff --git a/frontend/src/components/Fields/search.jsx b/frontend/src/components/Fields/search.jsx
index fb6eff1..f50ee8f 100644
--- a/frontend/src/components/Fields/search.jsx
+++ b/frontend/src/components/Fields/search.jsx
@@ -1,52 +1,53 @@
+// Preact
import { h } from 'preact';
-import { useState } from 'preact/hooks';
-import { searchMods } from '../services/api'; // Your API fetching function
-import styles from './SearchBar.module.css'; // Optional: CSS Modules
+import { useState, useRef, useEffect } from 'preact/hooks';
-function SearchBar({ onResults }) {
- const [searchTerm, setSearchTerm] = useState('');
- const [loading, setLoading] = useState(false);
- const [error, setError] = useState(null);
+// Images
+import SearchIcon from '../../assets/search.svg'
- const handleInputChange = (event) => {
- setSearchTerm(event.target.value);
- };
+// Styles
+import styles from './search.module.css'; // Optional: CSS Modules
- const handleSearch = async () => {
- if (!searchTerm.trim()) {
- onResults([]); // Clear results if search term is empty
- return;
- }
- setLoading(true);
- setError(null);
+function SearchBar({ onSearch }) {
- try {
- const results = await searchItems(searchTerm);
- onResults(results); // Pass the fetched results to the parent component
- } catch (err) {
- setError('Failed to fetch search results.');
- onResults([]); // Clear results on error
- } finally {
- setLoading(false);
- }
- };
+ const [search_input, setSearchInput] = useState('');
+ const timeout_id = useRef(null);
- return (
-
-
-
- {loading ? 'Searching...' : 'Search'}
-
- {error &&
{error}
}
-
- );
+ const handleInputChange = (event) => {
+
+ const new_search_input = event.target.value;
+ setSearchTerm(new_search_input);
+
+ if (timeout_id.current) {
+ clearTimeout(timeout_id.current);
+ }
+
+ timeout_id.current = setTimeout(() => {
+ onSearch(newSearchTerm);
+ }, 500);
+ };
+
+ useEffect(() => {
+ return () => {
+ if (timeout_id.current) {
+ clearTimeout(timeout_id.current);
+ }
+ };
+ }, []);
+
+ return (
+
+
+
+
+ );
}
export default SearchBar;
\ No newline at end of file
diff --git a/frontend/src/components/Fields/search.module.css b/frontend/src/components/Fields/search.module.css
index e69de29..85bb27b 100644
--- a/frontend/src/components/Fields/search.module.css
+++ b/frontend/src/components/Fields/search.module.css
@@ -0,0 +1,42 @@
+.searchBarContainer {
+
+ margin-bottom: 1rem;
+ /* padding: 0.5rem 1.2rem; */
+ box-sizing: border-box;
+
+ background-color: #242424;
+ border: transparent;
+ border: .1rem solid #3a3a3a;
+ border-radius: 20rem;
+
+ display: flex;
+}
+
+.searchBarInput {
+
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ box-sizing: border-box;
+ margin: 0.5em;
+
+ font-size: 1rem;
+ font-family: 'IBM Plex Mono';
+ color: #ffffffc0;
+
+ background-color: transparent;
+ border: transparent;
+}
+
+.searchBarInput:focus {
+ outline: none;
+
+ color: #ffffff;
+}
+
+.searchIcon {
+ margin-left: 1em;
+ width: 1.6em;
+
+ user-select: none;
+}
\ No newline at end of file
diff --git a/frontend/src/components/Filters/panel.module.css b/frontend/src/components/Filters/panel.module.css
index 7c100a6..9f72042 100644
--- a/frontend/src/components/Filters/panel.module.css
+++ b/frontend/src/components/Filters/panel.module.css
@@ -9,6 +9,7 @@
margin: 1rem;
width: 18rem;
min-height: 40rem;
+ padding: 1.3rem;
background-color: #1a1a1a;
color: #eaeaea;
@@ -16,4 +17,5 @@
border: #3a3a3a solid;
border-width: .1em;
border-radius: .5rem;
+ box-sizing: border-box;
}
\ No newline at end of file
diff --git a/frontend/src/components/NavBar/navbar.jsx b/frontend/src/components/NavBar/navbar.jsx
index 884e6f4..bbce79d 100644
--- a/frontend/src/components/NavBar/navbar.jsx
+++ b/frontend/src/components/NavBar/navbar.jsx
@@ -10,8 +10,8 @@ import styles from './navbar.module.css'
// Images
import Settings from '../../assets/settings.svg'
-import Login from '../../assets/login_small.svg'
-import Account from '../../assets/account.svg'
+import Login from '../../assets/login.svg'
+import Dashboard from '../../assets/dashboard.svg'
function NavBar({ children, className, ...rest}) {
@@ -43,19 +43,19 @@ function NavBar({ children, className, ...rest}) {
diff --git a/frontend/src/components/NavBar/navbar.module.css b/frontend/src/components/NavBar/navbar.module.css
index 2d362d9..d28bfae 100644
--- a/frontend/src/components/NavBar/navbar.module.css
+++ b/frontend/src/components/NavBar/navbar.module.css
@@ -18,7 +18,8 @@
display: flex;
flex-direction: row;
align-items: center;
- padding-left: 2em;
+ padding: 1.3em;
+ box-sizing: border-box;
}
.leftItem {
@@ -45,7 +46,7 @@
/* WIP */
.rightItem {
- margin: 0 1em;
+ margin: 0 .5em;
user-select: none;
@@ -54,28 +55,31 @@
.rightItems {
margin-left: auto;
- margin-right: 1em;
- margin-top: .3em;
+ height: 100%;
+ /* margin-right: 1em; */
+ /* margin-top: .3em; */
display: flex;
}
.settings {
+ height: 100%;
border-radius: 100rem;
transition: 600ms;
}
-.profile {
- border-radius: 100rem;
+.dashboard {
+ height: 100%;
+ border-radius: .5rem;
transition: 300ms;
}
.login {
+ height: 100%;
border-radius: .5rem;
transition: 600ms;
margin-top: .06em;
- height: 80%;
}
.login:hover {
@@ -87,6 +91,6 @@
transform: rotate(180deg);
}
-.profile:hover {
+.dashboard:hover {
background-color: #eaeaea10;
}
\ No newline at end of file
diff --git a/frontend/src/pages/about.jsx b/frontend/src/pages/about.jsx
index 419a0eb..bbbebe4 100644
--- a/frontend/src/pages/about.jsx
+++ b/frontend/src/pages/about.jsx
@@ -26,7 +26,7 @@ function AboutPage() {
WF radio is a platform for all your personnal mods and modpacks.
The difference with already existing big platforms is that radio is self-hosted and open-source.
- It's meant for your personnal works that you don't want to publish on the said platforms, but feel free to use it the way you want.
+ It's meant for your personnal works that you don't want to publish on the these platforms, but feel free to use it the way you want.
Don't hesitate to learn more about the project with the link below (not here yet).
>
diff --git a/frontend/src/pages/dashboard.jsx b/frontend/src/pages/dashboard.jsx
index 0ffdd02..dad1675 100644
--- a/frontend/src/pages/dashboard.jsx
+++ b/frontend/src/pages/dashboard.jsx
@@ -1 +1,67 @@
-// TODO
\ No newline at end of file
+import { h } from 'preact';
+import { useState } from 'preact/hooks';
+
+// Components
+import Button from '../components/Buttons/button'
+
+// Images
+import Logo from '../assets/logo.png'
+import Add from '../assets/add.svg'
+
+// Styles
+import styles from '../styles/dashboard.module.css'
+
+function DashboardPage() {
+
+ const handleCreate = () => {
+ window.location.href('/create/mod');
+ }
+
+ return (
+ <>
+
+
+ dashboard
+
+
+
+
+
+ Favorites
+
+
+
+
+ You have no favorites for the moment
+
+
+
+
+
+
+
+ >
+ );
+}
+
+export default DashboardPage;
\ No newline at end of file
diff --git a/frontend/src/pages/home.jsx b/frontend/src/pages/home.jsx
index 446d0ae..fcac821 100644
--- a/frontend/src/pages/home.jsx
+++ b/frontend/src/pages/home.jsx
@@ -21,7 +21,7 @@ function HomePage() {
radio
An open place for mods
- Get started
+ Start exploring
>
diff --git a/frontend/src/pages/login.jsx b/frontend/src/pages/login.jsx
index 42be74f..c636ae7 100644
--- a/frontend/src/pages/login.jsx
+++ b/frontend/src/pages/login.jsx
@@ -15,7 +15,7 @@ import Button from '../components/Buttons/button';
import InputField from '../components/Fields/input_field';
// Functions
-import { login } from '../services/auth';
+import { login } from '../services/users';
function LoginPage() {
@@ -129,7 +129,8 @@ function LoginPage() {
type='submit'
disabled={loginStatus === 'logging in'}
>
- {loginStatus === 'logging in' ? 'Logging in' : 'Login'}
+ {loginStatus === 'logging in' ? 'Logging in' :
+ loginStatus === 'success' ? 'Success' : 'Login'}
{
+ setSearchInput(new_search_input);
+ };
// UseEffect
useEffect(() => {
+
async function loadItems() {
+
setLoading(true);
setError(false);
+
try {
- const fetched_mods = await listMods();
+ const filters = {
+ search: search_input,
+ categories: selected_categories
+ };
+ const fetched_mods = await listMods(filters);
setMods(fetched_mods);
} catch (err) {
setError(err.message);
@@ -48,7 +63,10 @@ function ModsPage() {
mods
-
+
+
+
+
>
);
@@ -91,7 +109,7 @@ function ModsPage() {
{mods.map((mod) => {
console.debug(mod.name);
// return Test
- return
+ return
})}
>
diff --git a/frontend/src/pages/register.jsx b/frontend/src/pages/register.jsx
index f065661..d6e49bb 100644
--- a/frontend/src/pages/register.jsx
+++ b/frontend/src/pages/register.jsx
@@ -16,7 +16,7 @@ import Button from '../components/Buttons/button';
import InputField from '../components/Fields/input_field';
// Functions
-import { register } from '../services/auth';
+import { register } from '../services/users';
function RegisterPage() {
diff --git a/frontend/src/pages/settings.jsx b/frontend/src/pages/settings.jsx
index 302bd6c..5c6fac6 100644
--- a/frontend/src/pages/settings.jsx
+++ b/frontend/src/pages/settings.jsx
@@ -4,6 +4,12 @@ import { useState, useEffect } from 'preact/hooks'; // If you need state for set
import Cookies from 'js-cookie'
import { jwtDecode } from 'jwt-decode'
+// Functions
+import { deleteUser } from '../services/users';
+
+// Components
+import Button from '../components/Buttons/button';
+
// Styles
import styles from '../styles/settings.module.css'
@@ -16,12 +22,17 @@ function SettingsPage() {
const [theme, setTheme] = useState('dark');
const [notificationsEnabled, setNotificationsEnabled] = useState(true);
const [user, setUser] = useState(null)
+ const [tab, setTab] = useState('global');
useEffect( () => {
const token = Cookies.get('authToken');
if (token) {
- setUser(token);
+ const decoded_token = jwtDecode(token);
+ if (decoded_token && decoded_token.username) {
+ setUser(decoded_token.username);
+ }
+
}
},
[])
@@ -36,7 +47,18 @@ function SettingsPage() {
// Save notification preference
};
- const logout = () => {
+ const handleUserDeletion = async () => {
+ try {
+ await deleteUser(user);
+ handleLogout();
+ } catch (error) {
+ console.error("Couldn't delete account: ", error);
+ }
+
+
+ }
+
+ const handleLogout = () => {
Cookies.remove('authToken');
location.replace('/');
}
@@ -48,15 +70,15 @@ function SettingsPage() {
settings
-
- Theme:
-
- Light
- Dark
-
-
-
-
- Enable Notifications:
-
-
-
+ { tab === 'global' ? (
+ <>
+
+ Theme:
+
+ Light
+ Dark
+
+
+
+
+ Enable Notifications:
+
+
+
+ >
+ ) :
+ tab === 'user' ? (
+ <>
+
+
Danger zone
+
+ Delete account
+
+
+ >
+ ) : (
+ <>
+ >
+ )
+ }
+
>
);
diff --git a/frontend/src/services/mods.js b/frontend/src/services/mods.js
index 9fbef21..678f163 100644
--- a/frontend/src/services/mods.js
+++ b/frontend/src/services/mods.js
@@ -30,7 +30,7 @@ export async function createMod(mod_data) {
}
-export async function listMods() {
+export async function listMods(filters) {
try {
const response = await fetch(`${API_BASE_URL}/list/mods`);
if (!response.ok) {
diff --git a/frontend/src/services/auth.js b/frontend/src/services/users.js
similarity index 69%
rename from frontend/src/services/auth.js
rename to frontend/src/services/users.js
index 9ab7f1e..62773cc 100644
--- a/frontend/src/services/auth.js
+++ b/frontend/src/services/users.js
@@ -25,8 +25,6 @@ export async function login(username, password) {
export async function register(user_data) {
try {
- console.debug(user_data);
- console.debug(JSON.stringify(user_data));
const response = await fetch(`${API_BASE_URL}/users`, {
method: 'POST',
headers: {
@@ -43,4 +41,23 @@ export async function register(user_data) {
// console.error('Failed to fetch items:', error);
throw error;
}
+}
+
+export async function deleteUser(username) {
+ try {
+ const authToken = Cookies.get('authToken');
+ const response = await fetch(`${API_BASE_URL}/users/${username}`, {
+ method: 'DELETE',
+ headers: {
+ 'Authorization': authToken,
+ }});
+ if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+ }
+ const data = await response.json();
+ return data;
+ } catch (error) {
+ // console.error('Failed to fetch items:', error);
+ throw error;
+ }
}
\ No newline at end of file
diff --git a/frontend/src/styles/app.css b/frontend/src/styles/app.css
index b542145..00faa2b 100644
--- a/frontend/src/styles/app.css
+++ b/frontend/src/styles/app.css
@@ -24,6 +24,7 @@ body {
* {
transition: 200ms;
+ -webkit-user-drag: none;
}
@@ -31,6 +32,12 @@ a {
text-decoration: none;
}
+
+::selection {
+ color: #ffffff;
+ background: #353be5;
+}
+
/* Logo */
.logo.img {
@@ -87,6 +94,8 @@ a {
user-select: none;
}
+/* Titles */
+
h1 {
position: absolute;
left: 0rem;
@@ -101,6 +110,7 @@ h1 {
font-size: 3em;
}
+/* Containers */
.content-container {
@@ -137,6 +147,8 @@ h1 {
border-width: .1em;
border-radius: .5rem;
+ overflow: scroll;
+
}
.loadingContent {
diff --git a/frontend/src/styles/dashboard.module.css b/frontend/src/styles/dashboard.module.css
new file mode 100644
index 0000000..f19540c
--- /dev/null
+++ b/frontend/src/styles/dashboard.module.css
@@ -0,0 +1,71 @@
+.category {
+ margin-top: 0;
+}
+
+.title {
+ margin-top: 0;
+
+ color: #eaeaea;
+ font-size: 1.6em;
+ font-weight: 600;
+
+ user-select: none;
+}
+
+.tiles {
+
+ height: 13rem;
+ margin-bottom: 3rem;
+
+ overflow-x: scroll;
+ overflow-y: visible;
+ display: flex;
+
+ gap: 2em;
+}
+
+.toolbar {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+
+ height: 5rem;
+ padding: .5rem;
+
+ /* background-color: #9a9a9a; */
+}
+
+.toolbarRightItems {
+ position: absolute;
+ right: 1rem;
+ bottom: 1rem;
+
+}
+.createButton {
+ font-size: 1.4rem;
+}
+
+.emptyTile {
+ height: 99%;
+ width: 22em;
+ align-items: center;
+ display: flex;
+
+ background-color: #141414;
+ border: #3a3a3a .1rem solid;
+ border-radius: 1rem;
+}
+
+.emptyTileText {
+
+ padding: 1em;
+ width: 100%;
+
+ color: #9a9a9a;
+
+ text-align: center;
+ vertical-align: middle;
+
+ user-select: none;
+}
\ No newline at end of file
diff --git a/frontend/src/styles/home.css b/frontend/src/styles/home.css
index 8f922e6..ec67126 100644
--- a/frontend/src/styles/home.css
+++ b/frontend/src/styles/home.css
@@ -84,6 +84,6 @@
color: #eaeaead0;
font-size: 1.5em;
- text-align: justify;
+ text-align: center;
}
\ No newline at end of file
diff --git a/frontend/src/styles/settings.module.css b/frontend/src/styles/settings.module.css
index df023ba..8ee11fb 100644
--- a/frontend/src/styles/settings.module.css
+++ b/frontend/src/styles/settings.module.css
@@ -59,6 +59,7 @@
.tab:hover {
background-color: #eaeaea20;
+ cursor: pointer;
}
.tab:active {
@@ -73,4 +74,15 @@
.logout:hover {
color: #eaeaea;
background-color: #bc3939;
+}
+
+.title {
+ font-size: 1.4em;
+ font-weight: 600;
+ margin-top: 0;
+ margin-bottom: 2em;
+}
+
+.category {
+ background: none; /*Only to remove the empty warning for the moment */
}
\ No newline at end of file