diff --git a/README.md b/README.md index d5bbb3e..108539c 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,12 @@ Motto presents files from a static file server in a more friendly way ### Configuration -- `ROOT_URL=(url)` - the static file server instance to get files from -- `ENABLE_REPOINTING=(true|default:false)` - enable [repointing](#Repointing) +Configuration is done through environment variables in `.env.local` + +| Variable | type | default | description | +|--------------------|---------|---------|---------------------------------------------------| +| `ROOT_URL` | string | N/A | the static file server instance to get files from | +|`ENABLE_REPOINTING` | boolean | `false` | enable [repointing](#Repointing) | ### Repointing diff --git a/src/app/[...file]/components/content.tsx b/src/app/[...file]/components/content.tsx index b2a2118..fd95921 100644 --- a/src/app/[...file]/components/content.tsx +++ b/src/app/[...file]/components/content.tsx @@ -2,8 +2,10 @@ import { useState, useEffect } from 'react' -import NetworkError from './types/error/network'; +import Loading from './loading'; import ContentTypeError from './types/error/content_type'; +import NetworkError from './types/error/network'; +import StatusError from './types/error/status'; import ImageContent from './types/image'; import MarkdownContent from './types/markdown'; import Terminal from './types/terminal'; @@ -86,17 +88,21 @@ export default function Content({ src }: { src: string}) { if (content == undefined) { const result = fetch(src) .then(response => { - for (const type of recognized_types) { - if (is_type(response, type)) { - const emitted = type.emit(); - if (emitted != undefined) { - result.then(emitted.postprocess); - return emitted.process(response); + if (response.status < 400) { + for (const type of recognized_types) { + if (is_type(response, type)) { + const emitted = type.emit(); + if (emitted != undefined) { + result.then(emitted.postprocess); + return emitted.process(response); + } + return; } - return; } + set_content(); + } else { + set_content(); } - set_content(); }) .catch(err => { set_content(); @@ -104,5 +110,5 @@ export default function Content({ src }: { src: string}) { } }); - return content ??

Loading...

; + return content ?? ; } diff --git a/src/app/[...file]/components/copy.css.ts b/src/app/[...file]/components/copy.css.ts index 9207e53..884b659 100644 --- a/src/app/[...file]/components/copy.css.ts +++ b/src/app/[...file]/components/copy.css.ts @@ -10,20 +10,20 @@ export const copy = style({ }); export const copy_button = style({ - display: 'flex', - margin: 0, - border: 'none', - padding: 0, - outline: 'inherit', - fontFamily: 'monospace', - fontSize: '1.1em', - lineHeight: '2em', - color: 'inherit', - whiteSpace: 'pre-wrap', - transition: 'background-color 0.35s', - background: 'none', - width: 'max-content', - height: '100%', + display: 'flex', + margin: 0, + border: 'none', + padding: 0, + outline: 'inherit', + fontFamily: 'monospace', + fontSize: '1.1em', + lineHeight: '2em', + color: 'inherit', + whiteSpace: 'pre-wrap', + transition: 'background-color 0.35s', + background: 'none', + width: 'max-content', + height: '100%', ':hover': { backgroundColor: colors.background2, }, @@ -79,7 +79,9 @@ export const copied_image_light = style([copy_image, { export const copy_text = style({ - margin: 0, + margin: 0, marginLeft: '1em', - width: 'max-content', + width: 'max-content', + fontFamily: 'monospace', + fontSize: '1.2em', }); diff --git a/src/app/[...file]/components/loading.css.ts b/src/app/[...file]/components/loading.css.ts new file mode 100644 index 0000000..33f4ae6 --- /dev/null +++ b/src/app/[...file]/components/loading.css.ts @@ -0,0 +1,35 @@ +import { keyframes, style } from '@vanilla-extract/css'; + +import * as colors from '../../colors.css'; + +export const loading_squares = style({ + display: 'flex', + justifyContent: 'center', + width: '100%', + marginTop: '4em', + height: 'max-content', +}); + +const animation = keyframes({ + '0%': { backgroundColor: colors.background2 }, + '50%': { backgroundColor: colors.foreground }, + '100%': { backgroundColor: colors.background2 }, +}); + +export const square = style({ + margin: '0 1em', + width: '1em', + height: '1em', + backgroundColor: colors.background2, + animationName: animation, + animationDuration: '2s', + animationIterationCount: 'infinite', +}); + +export const loading = [0, 1, 2, 3, 4].map(index => + style([square, { + animationDelay: `${0.2 * index}s` + }]) +); + + diff --git a/src/app/[...file]/components/loading.tsx b/src/app/[...file]/components/loading.tsx new file mode 100644 index 0000000..730c431 --- /dev/null +++ b/src/app/[...file]/components/loading.tsx @@ -0,0 +1,9 @@ +import * as style from './loading.css'; + +export default function Loading() { + return ( +
+ {style.loading.map((style, index) =>
)} +
+ ); +} diff --git a/src/app/[...file]/components/types/error/content_type.tsx b/src/app/[...file]/components/types/error/content_type.tsx index 84c9b29..7c50ccd 100644 --- a/src/app/[...file]/components/types/error/content_type.tsx +++ b/src/app/[...file]/components/types/error/content_type.tsx @@ -1,3 +1,5 @@ +import Error from './error' + export default function ContentTypeError({ content_type }: { content_type: string }) { - return

{`Unrecognised MIME type: ${content_type}`}

+ return {`Unrecognised MIME type: ${content_type}`} } diff --git a/src/app/[...file]/components/types/error/error.css.ts b/src/app/[...file]/components/types/error/error.css.ts new file mode 100644 index 0000000..f8d9a10 --- /dev/null +++ b/src/app/[...file]/components/types/error/error.css.ts @@ -0,0 +1,18 @@ +import { style } from '@vanilla-extract/css' + +export const error = style({ + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + width: '100%', + height: 'max-content', +}); + +export const message = style({ + fontSize: '2em', +}); + +export const sad = style({ + margin: '0em', + fontSize: '3em', +}) diff --git a/src/app/[...file]/components/types/error/error.tsx b/src/app/[...file]/components/types/error/error.tsx new file mode 100644 index 0000000..f00e2bf --- /dev/null +++ b/src/app/[...file]/components/types/error/error.tsx @@ -0,0 +1,13 @@ +import * as style from './error.css' + +const faces = [ + "(•́︵•̀)", + "(╥﹏╥)", +] + +export default function Error({ children }: { children }) { + return
+

{children}

+

{faces[Math.floor(Math.random() * faces.length)]}

+
+} diff --git a/src/app/[...file]/components/types/error/network.tsx b/src/app/[...file]/components/types/error/network.tsx index f8efcb9..e8b044c 100644 --- a/src/app/[...file]/components/types/error/network.tsx +++ b/src/app/[...file]/components/types/error/network.tsx @@ -1,3 +1,6 @@ +import Error from './error' + export default function NetworkError({ err }: { err: string }) { - return

{`Error: ${err}`}

; + console.err(err); + return Network Error; } diff --git a/src/app/[...file]/components/types/error/status.tsx b/src/app/[...file]/components/types/error/status.tsx new file mode 100644 index 0000000..977a3ba --- /dev/null +++ b/src/app/[...file]/components/types/error/status.tsx @@ -0,0 +1,23 @@ +import Error from './error' + +const statuses = { + [400]: "Bad Request", + [401]: "Unauthorized", + [402]: "Payment Required", + [403]: "Forbidden", + [404]: "Not Found", + [405]: "Method Not Allowed", + [500]: "Internal Server Error", + [501]: "Not Implemented", + [502]: "Bad Gateway", + [503]: "Service Unavailable", + [504]: "Gateway Timeout", + [505]: "HTTP Version Not Supported" +} +export default function StatusError({ status }: { status: number }) { + if (status in statuses) { + return {`${status} ${statuses[status as keyof typeof statuses]}`} + } else { + return {status} + } +} diff --git a/src/app/page.tsx b/src/app/page.tsx index 0d40e07..69d19c4 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -2,7 +2,6 @@ import * as style from './page.css'; export default function App() { const supports_repointing = process.env.ENABLE_REPOINTING == 'true'; - console.log(supports_repointing); return (