Compare commits
No commits in common. "08ec22113861026118313c8a32d92d276158817a" and "a75de86d68ace375843143acdf32da7d11010ad6" have entirely different histories.
08ec221138
...
a75de86d68
|
@ -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>
|
||||
)
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
import { asset } from '$fresh/runtime.ts'
|
||||
import { Picture } from ':components/Picture.tsx'
|
||||
|
||||
export function SponsorCards() {
|
||||
return (
|
||||
|
@ -14,12 +13,7 @@ function SponsorCard(
|
|||
) {
|
||||
return (
|
||||
<a class='components__sponsor_card' href={href} target='_blank'>
|
||||
<Picture
|
||||
src={asset(src)}
|
||||
alt={alt}
|
||||
loading={'lazy'}
|
||||
formats={['avif']}
|
||||
/>
|
||||
<img src={asset(src)} alt={alt} />
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
":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",
|
||||
|
|
|
@ -3,9 +3,7 @@ import { cssBundler } from '@jotsr/smart-css-bundler/fresh'
|
|||
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
cssBundler(
|
||||
['./src/stylesheets/main.css'], //TODO fix bundler out paths , { bundleSubDir: 'css' }
|
||||
{ externalPaths: ['assets'] },
|
||||
cssBundler(['./src/stylesheets/main.css'] //TODO fix bundler out paths , { bundleSubDir: 'css' }
|
||||
),
|
||||
],
|
||||
})
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
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 { JSX } from 'preact'
|
||||
import { useEffect, useRef } from 'preact/hooks'
|
||||
|
@ -15,6 +15,16 @@ 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
|
||||
|
@ -85,6 +95,7 @@ export default function AiChatBox() {
|
|||
|
||||
return (
|
||||
<>
|
||||
<style dangerouslySetInnerHTML={{ __html: CSS }}></style>
|
||||
<button
|
||||
class='islands__ai_chat_box__button'
|
||||
onClick={() => dialog.current?.showModal()}
|
||||
|
@ -92,9 +103,7 @@ 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'
|
||||
|
@ -130,7 +139,7 @@ async function chatListener(event: Event, history: Signal<JSX.Element[]>) {
|
|||
|
||||
const botEntry = (
|
||||
<span class='islands__ai_chat_box__history_bot'>
|
||||
<Markdown>{botMessage}</Markdown>
|
||||
<MdCell>{botMessage}</MdCell>
|
||||
</span>
|
||||
)
|
||||
|
||||
|
|
|
@ -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 serez vous le prochain</h3>
|
||||
return <h3>Membre inconnu, peut être serai vous le prochain</h3>
|
||||
}
|
||||
|
||||
const carnet = await getCarnet(db.at(id)!)
|
||||
|
|
50
routes/membres/[id]/portfolio/[...path].tsx
Normal file
50
routes/membres/[id]/portfolio/[...path].tsx
Normal 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)
|
||||
},
|
||||
}
|
20
src/utils.ts
20
src/utils.ts
|
@ -1,4 +1,3 @@
|
|||
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'
|
||||
|
@ -172,22 +171,3 @@ 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: 5.9 KiB After Width: | Height: | Size: 36 KiB |
Binary file not shown.
Before Width: | Height: | Size: 200 KiB |
BIN
static/assets/screenshots/pwa_install_ui-desktop.png
Normal file
BIN
static/assets/screenshots/pwa_install_ui-desktop.png
Normal file
Binary file not shown.
After 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.
|
@ -43,7 +43,7 @@
|
|||
],
|
||||
"screenshots": [
|
||||
{
|
||||
"src": "/assets/screenshots/pwa_install_ui-desktop.jpg",
|
||||
"src": "/assets/screenshots/pwa_install_ui-desktop.png",
|
||||
"sizes": "1920x1080",
|
||||
"type": "image/png",
|
||||
"form_factor": "wide",
|
||||
|
|
Loading…
Reference in a new issue