Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions backend/app/api/dto/paste_dto.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ class CreatePaste(BaseModel):
max_length=config.MAX_CONTENT_LENGTH,
description="The content of the paste",
)
content_language: PasteContentLanguage = Field(
content_language: str = Field(
min_length=1,
description="The language of the content",
default=PasteContentLanguage.plain_text,
examples=[PasteContentLanguage.plain_text],
Expand Down Expand Up @@ -63,8 +64,9 @@ class EditPaste(BaseModel):
max_length=config.MAX_CONTENT_LENGTH,
description="The content of the paste",
)
content_language: PasteContentLanguage | None = Field(
content_language: str | None = Field(
None,
min_length=1,
description="The language of the content",
examples=[PasteContentLanguage.plain_text],
)
Expand All @@ -88,7 +90,7 @@ class PasteResponse(BaseModel):
content: str | None = Field(
description="The content of the paste, possible null if the content couldnt be read.",
)
content_language: PasteContentLanguage = Field(
content_language: str | None = Field(
description="The language of the content",
)
expires_at: datetime | None = Field(
Expand Down
10 changes: 5 additions & 5 deletions backend/app/services/paste_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
CreatePasteResponse,
EditPaste,
LegacyPasteResponse,
PasteContentLanguage,

Check failure on line 24 in backend/app/services/paste_service.py

View workflow job for this annotation

GitHub Actions / lint

Ruff (F401)

app/services/paste_service.py:24:5: F401 `app.api.dto.paste_dto.PasteContentLanguage` imported but unused
PasteResponse,
)
from app.api.dto.user_meta_data import UserMetaData
Expand Down Expand Up @@ -242,7 +242,7 @@
id=result.id,
title=result.title,
content=content,
content_language=PasteContentLanguage(result.content_language),
content_language=result.content_language,
created_at=result.created_at,
expires_at=result.expires_at,
last_updated_at=result.last_updated_at,
Expand Down Expand Up @@ -288,7 +288,7 @@
if edit_paste.title is not None: # Using ellipsis as sentinel for "not provided"
result.title = edit_paste.title
if edit_paste.content_language is not None:
result.content_language = edit_paste.content_language.value
result.content_language = edit_paste.content_language
if edit_paste.is_expires_at_set():
result.expires_at = edit_paste.expires_at

Expand Down Expand Up @@ -328,7 +328,7 @@
id=result.id,
title=result.title,
content=content,
content_language=PasteContentLanguage(result.content_language),
content_language=result.content_language,
expires_at=result.expires_at,
created_at=result.created_at,
last_updated_at=result.last_updated_at,
Expand Down Expand Up @@ -417,7 +417,7 @@
id=paste_id,
title=paste.title,
content_path=paste_path,
content_language=paste.content_language.value,
content_language=paste.content_language,
expires_at=paste.expires_at,
creator_ip=str(user_data.ip),
creator_user_agent=user_data.user_agent,
Expand All @@ -444,7 +444,7 @@
id=entity.id,
title=entity.title,
content=paste.content,
content_language=PasteContentLanguage(entity.content_language),
content_language=entity.content_language,
created_at=entity.created_at,
last_updated_at=entity.last_updated_at,
expires_at=entity.expires_at,
Expand Down
3 changes: 3 additions & 0 deletions frontend/.env.example
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Backend API config
API_URL=http://localhost:8000
ORIGIN=http://localhost:3000 # prevent cross-site post req forbidden from frontend because node can't resolve it's origin

# frontend config
PUBLIC_CONTENT_CHARACTER_LIMIT=100000
16 changes: 16 additions & 0 deletions frontend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ FROM node:20-slim AS base
ENV PNPM_HOME="/pnpm"
ENV PATH="$PNPM_HOME:$PATH"
ENV CI=true
RUN apt-get update && apt-get install -y \
fontconfig \
fonts-dejavu-core \
--no-install-recommends \
&& fc-cache -f \
&& rm -rf /var/lib/apt/lists/*

# enable corepacks for automatic package manager installation. Keeps things simple
RUN corepack enable
COPY . /app
Expand All @@ -21,6 +28,15 @@ RUN pnpm prune --prod

# We don't want to include artifacts etc. so include only build output
FROM node:20-slim AS prod

# add fontconfig and base fonts for sharp SVG rendering - this is for code preview gen
RUN apt-get update && apt-get install -y \
fontconfig \
fonts-dejavu-core \
--no-install-recommends \
&& fc-cache -f \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /app
COPY --from=build /app/node_modules node_modules
COPY --from=build /app/dist dist
Expand Down
Binary file not shown.
21 changes: 13 additions & 8 deletions frontend/src/lib/components/code-editor.svelte
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<script lang="ts">
import { onMount } from "svelte";
import { EditorView } from "@codemirror/view";
import { basicSetup } from "codemirror";
import { EditorState } from "@codemirror/state";
import { editorSetup } from "$lib/editor-setup";
import { customTheme } from "$lib/editor-theme";
import { getLanguageExtension, type LanguageType } from "$lib/editor-lang";
import { shikiToCodeMirror, updateEffect } from "@cmshiki/shiki";
import { getSingletonHighlighter } from "shiki";
import { shikiToCodeMirror } from "@cmshiki/shiki";
import { createOnigurumaEngine, getSingletonHighlighter } from "shiki";

let {
value = $bindable(""),
Expand All @@ -18,6 +18,13 @@
let editorRef: HTMLDivElement;
let view: EditorView | null = null;

// Cache the engine — creating it per-buildEditor call is wasteful
let enginePromise: ReturnType<typeof createOnigurumaEngine> | null = null;
function getEngine() {
enginePromise ??= createOnigurumaEngine(import("shiki/wasm"));
return enginePromise;
}

async function getThemeBg(themeName: string): Promise<string> {
const highlighter = await getSingletonHighlighter({
themes: [themeName],
Expand All @@ -32,13 +39,14 @@

async function buildEditor(doc: string) {
const shikiLang = toShikiLang(language);

const [bg, shikiResult] = await Promise.all([
getThemeBg(theme),
shikiLang
? shikiToCodeMirror({
lang: shikiLang,
theme,
engine: "javascript",
engine: await getEngine(),
})
: Promise.resolve(null),
]);
Expand All @@ -53,7 +61,7 @@
state: EditorState.create({
doc,
extensions: [
basicSetup,
editorSetup,
...getLanguageExtension(language),
customTheme(bg),
themeExtension,
Expand All @@ -78,13 +86,10 @@
});

$effect(() => {
// reactive deps
const _lang = language;
const _theme = theme;
const _editable = editable;

if (!view) return;

(async () => {
const currentDoc = view!.state.doc.toString();
view!.destroy();
Expand Down
6 changes: 0 additions & 6 deletions frontend/src/lib/editor-lang.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export const languageMap = {
berry: () => [],
bibtex: () => [],
bicep: () => [],
bird2: () => [],
blade: () => [],
bsl: () => [],
c: () => [cpp()],
Expand Down Expand Up @@ -121,7 +120,6 @@ export const languageMap = {
jssm: () => [],
jsx: () => [javascript({ typescript: false, jsx: true })],
julia: () => [],
just: () => [],
kdl: () => [],
kotlin: () => [],
kusto: () => [],
Expand All @@ -147,15 +145,13 @@ export const languageMap = {
move: () => [],
narrat: () => [],
nextflow: () => [],
"nextflow-groovy": () => [],
nginx: () => [],
nim: () => [],
nix: () => [],
nushell: () => [],
"objective-c": () => [],
"objective-cpp": () => [],
ocaml: () => [],
odin: () => [],
openscad: () => [],
pascal: () => [],
perl: () => [],
Expand Down Expand Up @@ -185,7 +181,6 @@ export const languageMap = {
regexp: () => [],
rel: () => [],
riscv: () => [],
ron: () => [],
rosmsg: () => [],
rst: () => [],
ruby: () => [],
Expand All @@ -208,7 +203,6 @@ export const languageMap = {
"ssh-config": () => [],
stata: () => [],
stylus: () => [],
surrealql: () => [sql()],
svelte: () => [],
swift: () => [],
"system-verilog": () => [],
Expand Down
21 changes: 21 additions & 0 deletions frontend/src/lib/editor-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {
lineNumbers,
highlightActiveLineGutter,
highlightSpecialChars,
drawSelection,
dropCursor,
rectangularSelection,
crosshairCursor,
highlightActiveLine,
} from "@codemirror/view";

export const editorSetup = [
lineNumbers(),
highlightActiveLineGutter(),
highlightSpecialChars(),
drawSelection(),
dropCursor(),
rectangularSelection(),
crosshairCursor(),
highlightActiveLine(),
];
5 changes: 0 additions & 5 deletions frontend/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@
<svelte:head>
<title>DevBin</title>
<link rel="icon" href={favicon} />
<meta property="og:image" content={page.url.origin + "/devbin-logo.png"} />
<meta property="og:title" content="DevBin" />
<meta
property="og:description"
content="Paste website for the DevDen discord server"
/>
</svelte:head>

<main class="h-screen max-h-screen max-w-6xl flex flex-col mx-auto p-2">
Expand Down
1 change: 0 additions & 1 deletion frontend/src/routes/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export const actions = {
content_language: content_language.trim(),
content: content.trim(),
};
console.log(cleanedformData);

// validate
if (!cleanedformData.title) {
Expand Down
13 changes: 12 additions & 1 deletion frontend/src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
import { goto } from "$app/navigation";
import CodeEditor from "$lib/components/code-editor.svelte";
import { getLanguageExtension, languageMap } from "$lib/editor-lang";
import { page } from "$app/state";
import { env } from "$env/dynamic/public";

const ERROR_CLEAR_TIMEOUT = 2500;
const MAX_PASTE_CONTENT_LENGTH = 10000;
const MAX_PASTE_CONTENT_LENGTH =
env.PUBLIC_CONTENT_CHARACTER_LIMIT || 100000;

let { form }: PageProps = $props();

Expand All @@ -26,6 +29,14 @@
});
</script>

<svelte:head>
<meta property="og:image" content={page.url.origin + "/devbin-logo.png"} />
<meta
property="og:description"
content="Paste website for the DevDen discord server"
/>
</svelte:head>

<form
method="POST"
action="?/paste"
Expand Down
18 changes: 17 additions & 1 deletion frontend/src/routes/paste/[id]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,26 @@

<svelte:head>
<title>DevBin | {data.title}</title>

<meta property="og:title" content={`DevBin | ${data.title}`} />
<meta
property="og:description"
content={`${data.title?.toLowerCase()}.${data.content_language}`}
/>
<meta
property="og:image"
content={page.url.origin + `/paste/${data.id}/preview.png`}
/>

<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:type" content="image/png" />

<meta name="twitter:card" content="summary_large_image" />
<meta
name="twitter:image"
content={page.url.origin + `/paste/${data.id}/preview.png`}
/>
</svelte:head>

{#if embed}
Expand Down Expand Up @@ -196,7 +211,8 @@
<CodeEditor
bind:value={editorValue}
editable={(!!data?.edit_token && isEditing) || false}
language={"svelte"}
language={(data?.content_language as LanguageType) ||
"plain_text"}
/>
</div>
{/if}
Expand Down
Loading
Loading