Compare commits

..

6 commits

22 changed files with 68 additions and 68 deletions

28
components/Picture.tsx Normal file
View file

@ -0,0 +1,28 @@
import { unwrapSignalOrValue } from ':src/utils.ts'
import { Ensure } from ':types'
import { JSX } from 'preact'
export type PictureProps =
& { formats: string[] }
& Ensure<JSX.HTMLAttributes<HTMLImageElement>, 'src' | 'alt' | 'loading'>
export function Picture(
{ formats, src, ...props }: PictureProps,
) {
const groups = unwrapSignalOrValue(src)?.match(/(?<path>.*)(?<ext>\.\w+)/)
?.groups
if (groups === undefined) {
throw new SyntaxError(`unable to parse path of "${src.valueOf()}"`)
}
const { path } = groups
return (
<picture>
{formats.map((format) => (
<source type={`image/${format}`} srcset={`${path}.${format}`} />
))}
<img src={src} {...props} />
</picture>
)
}

View file

@ -1,4 +1,5 @@
import { asset } from '$fresh/runtime.ts'
import { Picture } from ':components/Picture.tsx'
export function SponsorCards() {
return (
@ -13,7 +14,12 @@ function SponsorCard(
) {
return (
<a class='components__sponsor_card' href={href} target='_blank'>
<img src={asset(src)} alt={alt} />
<Picture
src={asset(src)}
alt={alt}
loading={'lazy'}
formats={['avif']}
/>
</a>
)
}

View file

@ -34,6 +34,7 @@
":components/": "./components/",
":islands/": "./islands/",
":src/": "./src/",
":types": "./types.ts",
"@cohabit/cohamail/": "./packages/@cohabit__cohamail@0.2.1/",
"@cohabit/ressources_manager/": "./packages/@cohabit__ressources_manager@0.1.3/",
"@deno/gfm": "jsr:@deno/gfm@^0.8.2",

View file

@ -3,7 +3,9 @@ import { cssBundler } from '@jotsr/smart-css-bundler/fresh'
export default defineConfig({
plugins: [
cssBundler(['./src/stylesheets/main.css'] //TODO fix bundler out paths , { bundleSubDir: 'css' }
cssBundler(
['./src/stylesheets/main.css'], //TODO fix bundler out paths , { bundleSubDir: 'css' }
{ externalPaths: ['assets'] },
),
],
})

View file

@ -1,5 +1,5 @@
import { JsonParseStream } from '$std/json/mod.ts'
import { CSS, render as renderMd } from '@deno/gfm'
import { Markdown } from ':components/Markdown.tsx'
import { Signal, signal, useSignal } from '@preact/signals'
import { JSX } from 'preact'
import { useEffect, useRef } from 'preact/hooks'
@ -15,16 +15,6 @@ const currentReader = signal<ReadableStreamDefaultReader<BotResponse> | null>(
)
let currentResponse: string[] = []
function MdCell({ children }: { children: Signal<string> }) {
return (
<div
class='markdown-body'
dangerouslySetInnerHTML={{ __html: renderMd(children.value) }}
>
</div>
)
}
type BotMessage = {
role: string
content: string
@ -95,7 +85,6 @@ export default function AiChatBox() {
return (
<>
<style dangerouslySetInnerHTML={{ __html: CSS }}></style>
<button
class='islands__ai_chat_box__button'
onClick={() => dialog.current?.showModal()}
@ -103,7 +92,9 @@ export default function AiChatBox() {
<i class='ri-bard-line'></i>
</button>
<dialog ref={dialog} class='islands__ai_chat_box__dialog'>
<div class='islands__ai_chat_box__dialog__content'>{history}</div>
<div class='islands__ai_chat_box__dialog__content'>
{history}
</div>
<form ref={form} class='islands__ai_chat_box__dialog__form'>
<input
type='text'
@ -139,7 +130,7 @@ async function chatListener(event: Event, history: Signal<JSX.Element[]>) {
const botEntry = (
<span class='islands__ai_chat_box__history_bot'>
<MdCell>{botMessage}</MdCell>
<Markdown>{botMessage}</Markdown>
</span>
)

View file

@ -22,7 +22,7 @@ export default async function Member(_: Request, { params }: PageProps) {
const Member = memberMock.at(id)
if (!Member) {
return <h3>Membre inconnu, peut être serai vous le prochain</h3>
return <h3>Membre inconnu, peut être serez vous le prochain</h3>
}
const carnet = await getCarnet(db.at(id)!)

View file

@ -1,50 +0,0 @@
import { Handlers, RouteConfig } from '$fresh/server.ts'
import { contentType } from '$std/media_types/mod.ts'
import { parse } from '$std/path/mod.ts'
const db = [
'julien.oculi',
]
async function getPortfolio(
user: string,
pathname: string,
): Promise<Response> {
const url = new URL(
pathname,
`https://git.cohabit.fr/${user}/.portfolio/raw/branch/main/`,
)
const { ext } = parse(pathname)
try {
const response = await fetch(url)
if (response.ok) {
return new Response(response.body, {
headers: {
'Content-Type': contentType(ext) ?? 'text/plain; charset=utf-8',
},
})
}
throw new Error(response.statusText)
} catch (error) {
return new Response(
'Portfolio introuvable\n```js\n' + String(error) + '\n```',
)
}
}
export const config: RouteConfig = {
skipAppWrapper: true,
}
export const handler: Handlers = {
GET(req, _ctx) {
const url = new URL(req.url)
const id = Number(url.pathname.split('/')[2])
const user = db[id]
const query = url.pathname.split('/').slice(4).join('/')
return getPortfolio(user, query === '' ? 'index.html' : query)
},
}

View file

@ -1,3 +1,4 @@
import { SignalLike } from '$fresh/src/types.ts'
import { JsonValue } from '$std/json/common.ts'
import { decodeBase64 } from '@std/encoding/base64'
import { JsonStringifyStream } from '@std/json'
@ -171,3 +172,22 @@ export function base64ToString(base64: string): string {
const bytes = decodeBase64(base64)
return new TextDecoder().decode(bytes)
}
export function unwrapSignalOrValue<T>(valueOrSignal: T | SignalLike<T>): T {
if (typeof valueOrSignal !== 'object') {
return valueOrSignal
}
if (valueOrSignal === null) {
return valueOrSignal
}
if (
'value' in valueOrSignal && 'peek' in valueOrSignal &&
'subscribe' in valueOrSignal
) {
return valueOrSignal.value
}
return valueOrSignal
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -43,7 +43,7 @@
],
"screenshots": [
{
"src": "/assets/screenshots/pwa_install_ui-desktop.png",
"src": "/assets/screenshots/pwa_install_ui-desktop.jpg",
"sizes": "1920x1080",
"type": "image/png",
"form_factor": "wide",

View file

@ -4,3 +4,5 @@ export interface User {
mail: string
groupes: string[]
}
export type Ensure<T, K extends keyof T> = T & Required<Pick<T, K>>