Compare commits

...

7 commits

10 changed files with 79 additions and 18 deletions

View file

@ -37,7 +37,7 @@ header div {
}
}
header nav {
header menu {
margin: 0;
padding: 0;
width: 100%;
@ -151,7 +151,7 @@ header details {
}
}
.components__header__nav_button {
.components__header__menu_button {
color: var(--_font-color);
display: inline-block;
text-decoration: none;

View file

@ -15,21 +15,21 @@ export function Header() {
<span class='components__header__brand__text'>bit</span>
</a>
</span>
<nav>
<menu>
<li>
<a href='/machines' class='components__header__nav_button'>
<a href='/machines' class='components__header__menu_button'>
<i class='ri-hammer-line'></i>
<span>Machines</span>
</a>
</li>
<li>
<a href='/projets' class='components__header__nav_button'>
<a href='/projets' class='components__header__menu_button'>
<i class='ri-organization-chart'></i>
<span>Projets</span>
</a>
</li>
<li>
<a href='/blog' class='components__header__nav_button'>
<a href='/blog' class='components__header__menu_button'>
<i class='ri-question-answer-line'></i>
<span>Blog</span>
</a>
@ -53,11 +53,11 @@ export function Header() {
</ul>
</details>
</li>
</nav>
</menu>
<SearchBox />
<MoreBox>
<ThemePicker />
<a href='/profil'>
<a href='/profil' title={'Accéder à mon compte'}>
<i class='ri-user-line'></i>
</a>
<AiChatBox />

View file

@ -14,7 +14,11 @@ export function ProjectCard(
) {
return (
<div class='components__project_card'>
<img src={icon} class='components__project_card__icon' />
<img
alt='Icon du projet'
src={icon}
class='components__project_card__icon'
/>
<div class='components__project_card__content'>
<h3>{title}</h3>
<div class='components__project_card__state'>

View file

@ -88,6 +88,7 @@ export default function AiChatBox() {
<button
class='islands__ai_chat_box__button'
onClick={() => dialog.current?.showModal()}
title={'Ouvrir la chat box IA'}
>
<i class='ri-bard-line'></i>
</button>

View file

@ -17,6 +17,7 @@ export default function MoreBox({ children }: { children: VNode | VNode[] }) {
<button
class='islands__more_box__button'
onClick={() => dialog.current?.showModal()}
title={"Afficher plus d'options"}
>
<i class='ri-more-2-line'></i>
</button>

View file

@ -16,12 +16,19 @@ export default function SearchBox() {
<button
class='islands__search_box__button'
onClick={() => dialog.current?.showModal()}
title={'Ouvrir la recherche'}
>
<i class='ri-search-line'></i>
<span>&nbsp;Rechercher</span>
</button>
<dialog ref={dialog} class='islands__search_box__dialog'>
<input type='search' name='' id='' placeholder='Rechercher' autoFocus />
<input
type='search'
name=''
id=''
placeholder='Rechercher'
autoFocus
/>
<div class='islands__search_box__dialog__content'>
<h3>Machines</h3>
<ul>

View file

@ -39,7 +39,7 @@ export default function ThemePicker() {
})
return (
<label class='islands__theme_picker'>
<label class='islands__theme_picker' title={'Sélectionner un thème'}>
<span>{themeIcon}</span>
<select
value={theme}

View file

@ -6,10 +6,28 @@ export async function handler(request: Request, ctx: FreshContext) {
// Update fresh context state with session
ctx.state = { ...ctx.state, session: SessionStore.getFromRequest(request) }
// Allow service worker to serve root scope
// Get response
const response = await ctx.next()
const url = new URL(request.url)
if (url.pathname.endsWith('island-startserviceworker.js')) {
//Add security headers
// See https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/TLS#http_strict_transport_security
response.headers.set('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload')
response.headers.set('Content-Security-Policy', "frame-ancestors 'none'; upgrade-insecure-requests")
//See https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/Referrer_policy
response.headers.set('Referrer-Policy', 'no-referrer, strict-origin-when-cross-origin')
//See https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/MIME_types
response.headers.set('X-Content-Type-Options', 'nosniff')
//See https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/Clickjacking
response.headers.set('X-Frame-Options', 'DENY')
//See https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/CORP
response.headers.set('Cross-Origin-Resource-Policy', 'same-origin')
//See https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity
//? SRI plugin for non local resources only ?
//See https://developer.mozilla.org/en-US/docs/Web/Security/Practical_implementation_guides/CSP
//? fresh useCSP https://fresh.deno.dev/docs/examples/using-csp
// Allow service worker to serve root scope
if (ctx.url.pathname.endsWith('island-startserviceworker.js')) {
response.headers.set('Service-Worker-Allowed', '/')
}
@ -31,7 +49,7 @@ export async function handler(request: Request, ctx: FreshContext) {
// Set session cookie
setCookie(response.headers, {
name: '_SESSION',
name: '__Secure-SESSION',
value: session.uuid,
httpOnly: true,
sameSite: 'Strict',
@ -45,7 +63,7 @@ export async function handler(request: Request, ctx: FreshContext) {
session.set('_csrf', csrf)
setCookie(response.headers, {
name: '_CSRF',
name: '__Host-CSRF',
value: csrf,
httpOnly: false,
sameSite: 'Strict',

View file

@ -58,6 +58,16 @@
scroll-behavior: smooth;
}
@media (prefers-contrast: more) {
:root {
--_font-color: black;
--_accent-color: var(--lime-12);
--_translucent: var(--sand-2);
--_background-color: white;
--_background-image: '';
}
}
@media (prefers-color-scheme: dark) {
:root:has(body:not([data-theme='light'])) {
--_font-color: var(--choco-1);
@ -72,6 +82,26 @@
--_background-color: var(--sand-12);
}
@media (prefers-contrast: more) and (prefers-color-scheme: dark) {
:root:has(body:not([data-theme='light'])) {
--_font-color: white;
--_accent-color: var(--lime-9);
--_translucent: var(--sand-10);
--_background-color: black;
--_background-image: '';
}
}
@media (prefers-contrast: more) {
:root:has(body[data-theme='dark']) {
--_font-color: white;
--_accent-color: var(--lime-9);
--_translucent: var(--sand-10);
--_background-color: black;
--_background-image: '';
}
}
body {
color: var(--_font-color);
font-family: var(--_font-family);

View file

@ -40,7 +40,7 @@ export async function requestApi<
method: 'GET' | 'POST' | 'DELETE' | 'PATCH',
payload?: Payload | null,
): Promise<ApiResponse> {
const csrf = getCookie('_CSRF') ?? ''
const csrf = getCookie('__Host-CSRF') ?? ''
const base = new URL('/api/', location.origin)
const endpoint = new URL(
@ -116,7 +116,7 @@ export async function* requestApiStream<
method: 'GET' | 'POST' | 'DELETE' | 'PATCH',
payload?: Payload | null,
): AsyncGenerator<ApiResponse, void, void> {
const csrf = getCookie('_CSRF') ?? ''
const csrf = getCookie('__Host-CSRF') ?? ''
const base = new URL('/api/', location.origin)
const endpoint = new URL(