frontend of sidebar

This commit is contained in:
Brieuc Dubois 2023-12-28 03:08:10 +01:00
parent 84aa9b3e22
commit 18c94bd7a0
8 changed files with 222 additions and 103 deletions

View File

@ -4,6 +4,7 @@
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="/img/favicon.png" /> <link rel="icon" href="/img/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" type="text/css" href="/css/index.css" />
%sveltekit.head% %sveltekit.head%
</head> </head>
<body data-sveltekit-preload-data="hover"> <body data-sveltekit-preload-data="hover">

View File

@ -0,0 +1,9 @@
<script lang="ts">
export const projectId: number = 0;
</script>
{#if Number.isNaN(projectId)}
<p>Invalid number</p>
{:else}
<p>Hello on dashboard {projectId}!</p>
{/if}

View File

@ -0,0 +1,82 @@
<script lang="ts">
import { projects } from "../stores/projects";
let newProject = false;
let editProject: number | undefined = undefined;
function handleKeydown(event: KeyboardEvent, id: number | undefined = undefined) {
if (event.key === 'Enter' && event.target) {
if(id !== undefined){
projects.edit({
id: id,
title: (event.target as HTMLInputElement).value
})
editProject = undefined;
} else {
createNewProject((event.target as HTMLInputElement).value);
newProject = false;
}
}
}
function createNewProject(value: string) {
projects.add({
title: value,
id: undefined
});
}
</script>
<svelte:head>
<link rel="stylesheet" type="text/css" href="/css/sidebar.css" />
</svelte:head>
<div id="sidebar" class="sidebar">
<div class="logo">
<a href="/">
<img src="img/icon.svg" alt="">
<span class="title">Focus</span>
<span class="version">v0.0.1</span>
</a>
</div>
<div class="boards">
{#await projects.init()}
<p>Loading ...</p>
{:then}
<h2>Projects</h2>
<ul>
{#each $projects as project}
<li>
{#if editProject === project.id}
<input
type="text"
on:keydown={(e) => handleKeydown(e, project.id)}
value={project.title}
class="edit-input"
/>
{:else}
<a href="/{project.id}">{project.title}</a><span class="edit-icon" on:click={() => editProject = project.id}>
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="18" viewBox="0 0 576 512"><path d="M402.6 83.2l90.2 90.2c3.8 3.8 3.8 10 0 13.8L274.4 405.6l-92.8 10.3c-12.4 1.4-22.9-9.1-21.5-21.5l10.3-92.8L388.8 83.2c3.8-3.8 10-3.8 13.8 0zm162-22.9l-48.8-48.8c-15.2-15.2-39.9-15.2-55.2 0l-35.4 35.4c-3.8 3.8-3.8 10 0 13.8l90.2 90.2c3.8 3.8 10 3.8 13.8 0l35.4-35.4c15.2-15.3 15.2-40 0-55.2zM384 346.2V448H64V128h229.8c3.2 0 6.2-1.3 8.5-3.5l40-40c7.6-7.6 2.2-20.5-8.5-20.5H48C21.5 64 0 85.5 0 112v352c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48V306.2c0-10.7-12.9-16-20.5-8.5l-40 40c-2.2 2.3-3.5 5.3-3.5 8.5z" fill="#aaa"/></svg>
</span>
{/if}
</li>
{/each}
{#if newProject}
<li>
<input
type="text"
placeholder="Enter project title"
on:keydown={handleKeydown}
style="padding: 8px; border: 1px solid #ccc; border-radius: 4px; width: 100%;" />
</li>
{/if}
</ul>
{:catch error}
<p>Something went wrong: {error.message}</p>
{/await}
</div>
<div class="bottom-links">
<span on:click={() => newProject = true}>New project</span>
<span>Settings</span>
</div>
</div>

View File

@ -1,33 +1,6 @@
<script> <script>
import { projects } from "../stores/projects"; import Sidebar from "../components/sidebar.svelte";
</script> </script>
<svelte:head> <Sidebar />
<link rel="stylesheet" type="text/css" href="/css/index.css" />
</svelte:head>
{#await projects.init()}
<p>Loading ...</p>
{:then}
<div id="sidebar" class="sidebar">
<div class="logo">
<img src="img/icon.svg" alt="">
<span class="title">Focus</span>
<span class="version">v0.0.1</span>
</div>
<div class="boards">
<h2>Projects</h2>
<ul>
{#each $projects as project}
<!-- <li><a href="/{{project.id}}">{{project.title}}</a></li> -->
{/each}
</ul>
</div>
<div class="bottom-links">
<a href="#">Add board</a>
<a href="#">Settings</a>
</div>
</div>
{:catch error}
<p>Something went wrong: {error.message}</p>
{/await}

View File

@ -0,0 +1,10 @@
<script lang="ts">
import Project from "../../components/project.svelte";
import Sidebar from "../../components/sidebar.svelte";
import { page } from '$app/stores';
let projectId: number = +$page.params.project;
</script>
<Sidebar />
<Project {projectId} />

View File

@ -6,23 +6,51 @@ export const projects = getProjects();
const backend = 'http://127.0.0.1:3000' const backend = 'http://127.0.0.1:3000'
interface Project { interface Project {
id: number, id: number | undefined,
title: string, title: string,
} }
function getProjects() { function getProjects() {
const { subscribe, set, update } = writable([]); const { subscribe, set, update } = writable([] as Project[]);
return { return {
subscribe, subscribe,
init: async () => { init: async () => {
const response = await axios.get(`${backend}/api/projects`) const response = await axios.get(`${backend}/api/projects`);
console.log(response.data)
if(response.status < 303) { if(response.status < 303) {
const projects: Project[] = response.data; const data: Project[] = response.data;
return projects; set(data);
return data;
}
},
add: async (project: Project) => {
const response = await axios.post(`${backend}/api/project`, project);
if(response.status < 303) {
project.id = response.data["id"];
update((oldProjects) => {
oldProjects.push(project)
return oldProjects;
});
}
},
edit: async (project: Project) => {
const response = await axios.put(`${backend}/api/project/${project.id}`, project)
if(response.status < 303) {
update((oldProjects: Project[]) => {
for(let p of oldProjects){
if(p.id === project.id){
p.title = project.title;
}
}
return oldProjects;
});
} }
} }
} }

View File

@ -3,71 +3,6 @@ body {
font-family: "Open sans", sans-serif; font-family: "Open sans", sans-serif;
color: white; color: white;
background-color: #2b2e30; background-color: #2b2e30;
}
#sidebar {
width: 240px;
background-color: #262a2b;
color: white;
height: 100vh;
display: flex;
flex-direction: column;
}
#sidebar .logo {
display: flex;
align-items: center;
padding: 10px;
margin-top: 20px;
}
#sidebar .logo img {
max-height: 30px;
margin-right: 10px;
}
#sidebar .logo .title {
padding-right: 10px;
}
#sidebar .logo .version {
font-size: 0.8em;
opacity: 0.7;
}
#sidebar .boards h2 {
padding-left: 10px;
font-size: 0.9em;
margin-top: 20px;
margin-bottom: 10px;
}
#sidebar .boards ul {
list-style: none;
padding: 0;
margin: 0; margin: 0;
} padding: 0;
}
#sidebar .boards ul li a {
text-decoration: none;
color: white;
display: block;
padding: 5px 10px;
font-size: 0.9em;
}
#sidebar .boards ul li a:hover {
background-color: #444;
}
#sidebar .bottom-links {
margin-top: auto;
}
#sidebar .bottom-links a {
text-decoration: none;
color: white;
display: block;
padding: 10px;
font-size: 0.9em;
border-top: 1px solid #444;
}

View File

@ -0,0 +1,81 @@
#sidebar {
width: 240px;
background-color: #262a2b;
color: white;
height: 100vh;
display: flex;
flex-direction: column;
}
#sidebar .logo {
display: flex;
align-items: center;
padding: 10px;
margin-top: 20px;
}
#sidebar .logo img {
max-height: 30px;
margin-right: 10px;
}
#sidebar .logo .title {
padding-right: 10px;
}
#sidebar .logo .version {
font-size: 0.8em;
opacity: 0.7;
}
#sidebar .boards h2 {
padding-left: 10px;
font-size: 0.9em;
margin-top: 20px;
margin-bottom: 10px;
}
#sidebar .boards ul {
list-style: none;
padding: 0;
margin: 0;
}
#sidebar a {
text-decoration: none;
color: white;
}
#sidebar .boards ul li:hover {
background-color: #444;
}
#sidebar .bottom-links {
margin-top: auto;
}
#sidebar .bottom-links span {
text-decoration: none;
color: white;
display: block;
padding: 10px;
font-size: 0.9em;
border-top: 1px solid #444;
cursor: pointer;
}
#sidebar li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 5px 10px;
}
#sidebar .edit-icon {
visibility: hidden;
margin-right: 10px;
cursor: pointer;
}
#sidebar li:hover .edit-icon {
visibility: visible;
}