Compare commits

..

No commits in common. "08ec22113861026118313c8a32d92d276158817a" and "a75de86d68ace375843143acdf32da7d11010ad6" have entirely different histories.

22 changed files with 68 additions and 68 deletions

View file

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

View file

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

View file

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

View file

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

View file

@ -0,0 +1,50 @@
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,4 +1,3 @@
import { SignalLike } from '$fresh/src/types.ts'
import { JsonValue } from '$std/json/common.ts' import { JsonValue } from '$std/json/common.ts'
import { decodeBase64 } from '@std/encoding/base64' import { decodeBase64 } from '@std/encoding/base64'
import { JsonStringifyStream } from '@std/json' import { JsonStringifyStream } from '@std/json'
@ -172,22 +171,3 @@ export function base64ToString(base64: string): string {
const bytes = decodeBase64(base64) const bytes = decodeBase64(base64)
return new TextDecoder().decode(bytes) 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: 5.9 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

Binary file not shown.

View file

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

View file

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