motto/src/app/[...file]/content.tsx

122 lines
3 KiB
TypeScript
Raw Normal View History

2024-09-16 19:44:19 +00:00
'use client'
import { useState, useEffect } from 'react'
2024-09-17 07:11:54 +00:00
import NetworkError from './types/error/network';
import ContentTypeError from './types/error/content_type';
2024-09-18 15:39:27 +00:00
import ImageContent from './types/image';
2024-09-17 07:11:54 +00:00
import Terminal from './types/terminal';
import Text from './types/text';
type ContentType<T> = {
content_type: RegExp,
2024-09-18 15:39:27 +00:00
path?: RegExp,
emit: () => void | Processor<T>,
2024-09-17 07:11:54 +00:00
};
type Processor<T> = {
process: (response: Response) => Promise<T>,
postprocess: (data: T) => undefined,
};
function not_match(regex: RegExp | undefined, str: string) {
return !(regex ?? /(?:)/).test(str);
}
2024-09-18 15:39:27 +00:00
function is_type(response: Response, type: ContentType<any>) {
if (not_match(type.content_type, response.headers.get('Content-Type')!.split(';')[0])) {
2024-09-17 07:11:54 +00:00
return false;
} else if (not_match(type.path, window.location.pathname)) {
return false;
}
return true;
}
2024-09-16 19:44:19 +00:00
export default function Content({ src }: { src: string}) {
2024-09-18 15:39:27 +00:00
const [content, set_content] = useState<JSX.Element>();
2024-09-16 19:44:19 +00:00
2024-09-18 15:39:27 +00:00
const recognized_types: ContentType<any>[] = [{
2024-09-17 07:11:54 +00:00
content_type: /image\/\w+/,
2024-09-16 19:44:19 +00:00
emit: () => {
2024-09-18 15:39:27 +00:00
set_content(<ImageContent src={src} />);
2024-09-16 19:44:19 +00:00
},
}, {
2024-09-17 07:11:54 +00:00
content_type: /application\/octet-stream/,
path: /.*\.term/,
emit: () => {
return {
process: (response: Response) => {
return response.text();
},
postprocess: (data: string) => {
set_content(<Terminal text={data} />);
}
};
}
}, {
content_type: /(text\/\w+)|(application\/octet-stream)/,
2024-09-16 19:44:19 +00:00
emit: () => {
return {
process: (response: Response) => {
return response.text();
},
postprocess: (data: string) => {
2024-09-18 21:47:51 +01:00
const languages = {
// "markup",
js: "jsx",
mjs: "jsx",
jsx: "jsx",
// "js-extras",
ts: "tsx",
tsx: "tsx",
swift: "swift",
kt: "kotlin",
kts: "kotlin",
ktm: "kotlin",
// "objectivec",
// "reason",
rs: "rust",
// "graphql",
yml: "yaml",
yaml: "yaml",
go: "go",
c: "cpp",
cpp: "cpp",
cxx: "cpp",
h: "cpp",
hpp: "cpp",
hxx: "cpp",
py: "python",
json: "json",
}
const split = window.location.pathname.split('.');
set_content(<Text language={split.length == 0 ? 'none' : languages[split[split.length - 1]]} text={data} />);
2024-09-16 19:44:19 +00:00
}
};
}
}];
useEffect(() => {
if (content == undefined) {
const result = fetch(src)
.then(response => {
2024-09-17 07:11:54 +00:00
for (const type of recognized_types) {
2024-09-18 15:39:27 +00:00
if (is_type(response, type)) {
2024-09-16 19:44:19 +00:00
const emitted = type.emit();
if (emitted != undefined) {
result.then(emitted.postprocess);
return emitted.process(response);
}
return;
}
}
2024-09-18 15:39:27 +00:00
set_content(<ContentTypeError content_type={response.headers.get('Content-Type')!.split(';')[0]} />);
2024-09-17 07:11:54 +00:00
})
.catch(err => {
set_content(<NetworkError err={err} />);
2024-09-16 19:44:19 +00:00
});
}
2024-09-18 15:39:27 +00:00
});
2024-09-16 19:44:19 +00:00
return content ?? <p>Loading...</p>;
}