diff --git a/package.json b/package.json index 09d3d46..ed4d5ef 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,9 @@ "next": "^14.2.12", "prism-react-renderer": "^2.4.0", "react": "^18", - "react-dom": "^18" + "react-dom": "^18", + "react-markdown": "^9.0.1", + "rehype-highlight": "^7.0.0" }, "devDependencies": { "@types/node": "^20", diff --git a/src/app/[...file]/components/content.tsx b/src/app/[...file]/components/content.tsx index 44e37c6..5c87652 100644 --- a/src/app/[...file]/components/content.tsx +++ b/src/app/[...file]/components/content.tsx @@ -5,8 +5,10 @@ import { useState, useEffect } from 'react' import NetworkError from './types/error/network'; import ContentTypeError from './types/error/content_type'; import ImageContent from './types/image'; +import MarkdownContent from './types/markdown'; import Terminal from './types/terminal'; import Text from './types/text'; +import { map_to_type } from './types/text'; type ContentType = { content_type: RegExp, @@ -52,6 +54,19 @@ export default function Content({ src }: { src: string}) { } }; } + }, { + content_type: /application\/octet-stream/, + path: /.*\.md/i, + emit: () => { + return { + process: (response: Response) => { + return response.text(); + }, + postprocess: (data: string) => { + set_content(); + } + }; + } }, { content_type: /(text\/\w+)|(application\/octet-stream)/, emit: () => { @@ -60,36 +75,8 @@ export default function Content({ src }: { src: string}) { return response.text(); }, postprocess: (data: string) => { - 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(); + set_content(); } }; } diff --git a/src/app/[...file]/components/types/markdown.css.ts b/src/app/[...file]/components/types/markdown.css.ts new file mode 100644 index 0000000..1bef7a5 --- /dev/null +++ b/src/app/[...file]/components/types/markdown.css.ts @@ -0,0 +1,33 @@ +import { style } from '@vanilla-extract/css'; + +import * as colors from '../../../colors.css'; + +export const code_bounds = style({ + position: 'relative', + width: '100%', + height: 'max-content', + padding: '0.65em 0 0', + borderTop: `1px solid ${colors.background2}`, + borderBottom: `1px solid ${colors.background2}`, +}); + +export const copy = style({ + position: 'absolute', + right: 0, + display: 'block', + margin: 0, + border: 'none', + padding: '0', + outline: 'inherit', + fontFamily: 'monospace', + fontSize: '1.1em', + lineHeight: '2em', + background: 'none', + color: 'inherit', + transition: 'color 0.15s', + whiteSpace: 'pre-wrap', + ':hover': { + color: colors.accent, + }, + +}); diff --git a/src/app/[...file]/components/types/markdown.tsx b/src/app/[...file]/components/types/markdown.tsx new file mode 100644 index 0000000..5eb67ad --- /dev/null +++ b/src/app/[...file]/components/types/markdown.tsx @@ -0,0 +1,23 @@ +import Markdown from 'react-markdown'; + +import * as style from './markdown.css'; +import Text from './text'; +import { map_to_type } from './text'; + +export default function MarkdownContent({ text }: { text: string }) { + return ( + { + const split = props.className.split('-'); + return ( +
+ + +
+ ); + } + }} + >{text}
+ ); +} diff --git a/src/app/[...file]/components/types/text.css.ts b/src/app/[...file]/components/types/text.css.ts index 762f02d..46f31bf 100644 --- a/src/app/[...file]/components/types/text.css.ts +++ b/src/app/[...file]/components/types/text.css.ts @@ -3,12 +3,14 @@ import { style } from '@vanilla-extract/css' import * as colors from '../../../colors.css' export const group = style({ - display: 'flex', - fontFamily: 'monospace', - fontSize: '1em', - lineHeight: '1.4em', - whiteSpace: 'pre', - tabSize: 4, + display: 'flex', + fontFamily: 'monospace', + fontSize: '1em', + lineHeight: '1.4em', + whiteSpace: 'pre', + tabSize: 4, + overflowX: 'scroll', + paddingBottom: '1em', '@media': { 'screen and (min-width: 768px)': { fontSize: '1.1em', diff --git a/src/app/[...file]/components/types/text.tsx b/src/app/[...file]/components/types/text.tsx index 7bb7182..83371a7 100644 --- a/src/app/[...file]/components/types/text.tsx +++ b/src/app/[...file]/components/types/text.tsx @@ -3,8 +3,51 @@ import { Highlight, themes } from 'prism-react-renderer'; import * as style from './text.css'; -export default function Text({ language, text }: { language: string, text: string }) { - console.log(language); +const type_map = { + // 'markup', + js: 'jsx', + mjs: 'jsx', + jsx: 'jsx', + javascript: 'javascript', + // 'js-extras', + ts: 'tsx', + tsx: 'tsx', + typescript: 'typescript', + swift: 'swift', + kt: 'kotlin', + kts: 'kotlin', + ktm: 'kotlin', + kotlin: 'kotlin', + // 'objectivec', + // 'reason', + rs: 'rust', + rust: 'rust', + // 'graphql', + yml: 'yaml', + yaml: 'yaml', + go: 'go', + c: 'cpp', + cpp: 'cpp', + cxx: 'cpp', + 'c++': 'cpp', + h: 'cpp', + hpp: 'cpp', + hxx: 'cpp', + py: 'python', + python: 'python', + json: 'json', + none: 'none', +} + +export function map_to_type(extension?: string) { + if (extension != undefined) { + return type_map[extension as keyof typeof languages] ?? 'none'; + } else { + return 'none'; + } +} + +export default function Text({ language, text, line_numbers }: { language: string, text: string, line_numbers: boolean }) { const lines = text.split('\n'); const media_matcher = window.matchMedia('(prefers-color-scheme: light)'); @@ -24,7 +67,7 @@ export default function Text({ language, text }: { language: string, text: strin }); return
-

{lines.map((_, index) => `${index}\n`)}

+ {line_numbers ?

{lines.map((_, index) => `${index}\n`)}

: <>} {download_ttys.map((text, index) => )}
- -
- -
+ );