62 lines
1.4 KiB
TypeScript
62 lines
1.4 KiB
TypeScript
|
'use client'
|
||
|
|
||
|
import { useState, useEffect } from 'react'
|
||
|
|
||
|
import Error from './types/error';
|
||
|
import Image from './types/image';
|
||
|
import Text from './types/text';
|
||
|
|
||
|
export default function Content({ src }: { src: string}) {
|
||
|
const [content, set_content] = useState();
|
||
|
|
||
|
type ContentType<T> = {
|
||
|
matcher: RegExp,
|
||
|
emit: () => undefined | Processor<T>,
|
||
|
};
|
||
|
type Processor<T> = {
|
||
|
process: (response: Response) => Promise<T>,
|
||
|
postprocess: (data: T) => undefined,
|
||
|
};
|
||
|
|
||
|
const recognized_types: ContentType<Any>[] = [{
|
||
|
matcher: /image\/\w+/,
|
||
|
emit: () => {
|
||
|
set_content(<Image src={src} />);
|
||
|
},
|
||
|
}, {
|
||
|
matcher: /text\/\w+/,
|
||
|
emit: () => {
|
||
|
return {
|
||
|
process: (response: Response) => {
|
||
|
return response.text();
|
||
|
},
|
||
|
postprocess: (data: string) => {
|
||
|
set_content(<Text text={data} />);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
}];
|
||
|
|
||
|
useEffect(() => {
|
||
|
if (content == undefined) {
|
||
|
const result = fetch(src)
|
||
|
.then(response => {
|
||
|
const content_type = response.headers.get('Content-Type').split(';')[0];
|
||
|
for (let type of recognized_types) {
|
||
|
if (type.matcher.test(content_type)) {
|
||
|
const emitted = type.emit();
|
||
|
if (emitted != undefined) {
|
||
|
result.then(emitted.postprocess);
|
||
|
return emitted.process(response);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
set_content(<Error content_type={content_type} />);
|
||
|
});
|
||
|
}
|
||
|
}, []);
|
||
|
|
||
|
return content ?? <p>Loading...</p>;
|
||
|
}
|