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 { 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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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'] },
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
|
@ -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>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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)!)
|
||||||
|
|
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 { 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 |
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": [
|
"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",
|
||||||
|
|
Loading…
Reference in a new issue