diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts
index 6ee8d11e..3a73b147 100644
--- a/packages/api/src/index.ts
+++ b/packages/api/src/index.ts
@@ -1,11 +1,12 @@
import { Elysia, t } from "elysia";
import { cors } from "@elysiajs/cors";
-import { swagger, onAfterHandle } from "./swagger";
+import { swagger } from "@elysiajs/swagger";
import { addTranscodeJob, addPackageJob } from "@mixwave/artisan/producer";
import {
LangCodeSchema,
VideoCodecSchema,
AudioCodecSchema,
+ scalarCustomCss,
} from "@mixwave/shared";
import { env } from "./env";
import { getJob, getJobs, getJobLogs } from "./jobs";
@@ -16,7 +17,23 @@ export type App = typeof app;
const app = new Elysia()
.use(cors())
- .use(swagger)
+ .use(
+ swagger({
+ documentation: {
+ info: {
+ title: "Mixwave API",
+ description:
+ "The Mixwave API is organized around REST, returns JSON-encoded responses " +
+ "and uses standard HTTP response codes and verbs.",
+ version: "1.0.0",
+ },
+ },
+ scalarConfig: {
+ hideDownloadButton: true,
+ customCss: scalarCustomCss,
+ },
+ }),
+ )
.model({
LangCode: LangCodeSchema,
VideoCodec: VideoCodecSchema,
@@ -260,8 +277,6 @@ const app = new Elysia()
},
);
-app.onAfterHandle(onAfterHandle);
-
app.on("stop", () => {
process.exit(0);
});
diff --git a/packages/api/src/swagger.ts b/packages/api/src/swagger.ts
deleted file mode 100644
index 505fc303..00000000
--- a/packages/api/src/swagger.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-import { swagger as elysiaSwagger } from "@elysiajs/swagger";
-
-const CUSTOM_SCALAR_CSS = `
- .scalar-container.z-overlay {
- padding-left: 16px;
- padding-right: 16px;
- }
-
- .scalar-api-client__send-request-button, .show-api-client-button {
- background: var(--scalar-button-1);
- }
-`;
-
-export const swagger = elysiaSwagger({
- documentation: {
- info: {
- title: "Mixwave API",
- description:
- "The Mixwave API is organized around REST, returns JSON-encoded responses " +
- "and uses standard HTTP response codes and verbs.",
- version: "1.0.0",
- },
- },
- scalarConfig: {
- hideDownloadButton: true,
- customCss: CUSTOM_SCALAR_CSS,
- },
-});
-
-const scalarScript = `
-
-`;
-
-export async function onAfterHandle({
- request,
- response,
-}: {
- request: Request;
- response: Response;
-}) {
- const url = new URL(request.url);
-
- if (url.pathname.endsWith("/swagger")) {
- const text = await response.text();
- const lines = text.split("\n");
- lines.splice(
- lines.findIndex((line) => line.trim() === "
"),
- 0,
- scalarScript,
- );
- return new Response(lines.join(""), {
- headers: {
- "content-type": "text/html; charset=utf8",
- },
- });
- }
-
- return response;
-}
diff --git a/packages/dashboard/src/App.tsx b/packages/dashboard/src/App.tsx
index 3d25029a..a4b3a4c0 100644
--- a/packages/dashboard/src/App.tsx
+++ b/packages/dashboard/src/App.tsx
@@ -12,7 +12,6 @@ import { Suspense } from "react";
import { Toaster } from "@/components/ui/toaster";
import { PlayerPage } from "./pages/PlayerPage";
import { StoragePage } from "./pages/StoragePage";
-import { ThemeProvider } from "@/components/ui/theme-provider";
const queryClient = new QueryClient();
@@ -51,13 +50,11 @@ const router = createBrowserRouter([
export function App() {
return (
-
-
-
-
-
-
-
-
+
+
+
+
+
+
);
}
diff --git a/packages/dashboard/src/components/Editor.tsx b/packages/dashboard/src/components/Editor.tsx
index 44ab1a47..82950b92 100644
--- a/packages/dashboard/src/components/Editor.tsx
+++ b/packages/dashboard/src/components/Editor.tsx
@@ -1,6 +1,5 @@
import MonacoEditor from "@monaco-editor/react";
import { useEffect, useState } from "react";
-import { useTheme } from "@/components/ui/theme-provider";
import type { BeforeMount, OnChange, OnMount } from "@monaco-editor/react";
type EditorProps = {
@@ -16,9 +15,6 @@ export function Editor({
onSave,
localStorageKey,
}: EditorProps) {
- const { theme } = useTheme();
- const style = useMonacoStyle();
-
const [defaultValue] = useState(() => {
const localStorageValue = localStorageKey
? localStorage.getItem(localStorageKey)
@@ -58,14 +54,8 @@ export function Editor({
return (
-
-
- {style}
+
{title}
+
);
}
-
-function useMonacoStyle() {
- const { theme } = useTheme();
-
- if (theme === "dark") {
- return (
-
- );
- }
-
- return null;
-}
diff --git a/packages/dashboard/src/components/JobState.tsx b/packages/dashboard/src/components/JobState.tsx
index df6cb065..2e82b1fa 100644
--- a/packages/dashboard/src/components/JobState.tsx
+++ b/packages/dashboard/src/components/JobState.tsx
@@ -8,31 +8,18 @@ import type { Job } from "@/api";
export function JobState({ state }: { state: Job["state"] }) {
if (state === "completed") {
- return createCircle(
- "bg-emerald-200 text-emerald-800 dark:bg-emerald-400",
- Check,
- );
+ return createCircle("bg-emerald-200 text-emerald-800", Check);
}
if (state === "failed") {
- return createCircle("bg-red-200 text-red-800 dark:bg-red-400", X);
+ return createCircle("bg-red-200 text-red-800", X);
}
if (state === "running") {
- return createCircle(
- "bg-blue-200 text-blue-800 dark:bg-blue-400",
- Loader,
- "animate-spin",
- );
+ return createCircle("bg-blue-200 text-blue-800", Loader, "animate-spin");
}
if (state === "skipped") {
- return createCircle(
- "bg-gray-200 text-gray-800 dark:bg-gray-400",
- CircleOff,
- );
+ return createCircle("bg-gray-200 text-gray-800", CircleOff);
}
- return createCircle(
- "bg-violet-200 text-violet-800 dark:bg-gray-400",
- CircleDotDashed,
- );
+ return createCircle("bg-violet-200 text-violet-800", CircleDotDashed);
}
function createCircle(
diff --git a/packages/dashboard/src/components/JsonHighlight.tsx b/packages/dashboard/src/components/JsonHighlight.tsx
index 544efe8c..20468198 100644
--- a/packages/dashboard/src/components/JsonHighlight.tsx
+++ b/packages/dashboard/src/components/JsonHighlight.tsx
@@ -1,8 +1,10 @@
import { useMemo } from "react";
import { Light as SyntaxHighlighter } from "react-syntax-highlighter";
import json from "react-syntax-highlighter/dist/esm/languages/hljs/json";
-import { useTheme } from "@/components/ui/theme-provider";
-import { styleLight, styleDark } from "@/lib/syntax-styles";
+import style from "react-syntax-highlighter/dist/esm/styles/hljs/stackoverflow-light";
+
+style["hljs"].padding = "1rem";
+delete style["hljs"].background;
SyntaxHighlighter.registerLanguage("json", json);
@@ -11,8 +13,6 @@ type SyntaxHighlightProps = {
};
export function JsonHighlight({ json }: SyntaxHighlightProps) {
- const { theme } = useTheme();
-
const data = useMemo(() => {
const parsed = JSON.parse(json);
return JSON.stringify(parsed, null, 2);
@@ -21,7 +21,7 @@ export function JsonHighlight({ json }: SyntaxHighlightProps) {
return (
{data}
diff --git a/packages/dashboard/src/components/Sidebar.tsx b/packages/dashboard/src/components/Sidebar.tsx
index 92255e8f..5d68d800 100644
--- a/packages/dashboard/src/components/Sidebar.tsx
+++ b/packages/dashboard/src/components/Sidebar.tsx
@@ -5,7 +5,6 @@ import Rows3 from "lucide-react/icons/rows-3";
import Sailboat from "lucide-react/icons/sailboat";
import Play from "lucide-react/icons/play";
import Box from "lucide-react/icons/box";
-import { ModeToggle } from "@/components/ui/mode-toggle";
import { SidebarNavLink } from "./SidebarNavLink";
export function Sidebar() {
@@ -41,9 +40,6 @@ export function Sidebar() {
-
-
-
);
}
diff --git a/packages/dashboard/src/components/ui/mode-toggle.tsx b/packages/dashboard/src/components/ui/mode-toggle.tsx
deleted file mode 100644
index c791b095..00000000
--- a/packages/dashboard/src/components/ui/mode-toggle.tsx
+++ /dev/null
@@ -1,36 +0,0 @@
-import { Moon, Sun } from "lucide-react";
-import { Button } from "@/components/ui/button";
-import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger,
-} from "@/components/ui/dropdown-menu";
-import { useTheme } from "@/components/ui/theme-provider";
-
-export function ModeToggle() {
- const { setTheme } = useTheme();
-
- return (
-
-
-
-
-
- setTheme("light")}>
- Light
-
- setTheme("dark")}>
- Dark
-
- setTheme("system")}>
- System
-
-
-
- );
-}
diff --git a/packages/dashboard/src/components/ui/theme-provider.tsx b/packages/dashboard/src/components/ui/theme-provider.tsx
deleted file mode 100644
index e18440d7..00000000
--- a/packages/dashboard/src/components/ui/theme-provider.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import { createContext, useContext, useEffect, useState } from "react";
-
-type Theme = "dark" | "light" | "system";
-
-type ThemeProviderProps = {
- children: React.ReactNode;
- defaultTheme?: Theme;
- storageKey?: string;
-};
-
-type ThemeProviderState = {
- theme: Theme;
- setTheme: (theme: Theme) => void;
-};
-
-const initialState: ThemeProviderState = {
- theme: "system",
- setTheme: () => null,
-};
-
-const ThemeProviderContext = createContext
(initialState);
-
-export function ThemeProvider({
- children,
- defaultTheme = "system",
- storageKey = "vite-ui-theme",
- ...props
-}: ThemeProviderProps) {
- const [theme, setTheme] = useState(
- () => (localStorage.getItem(storageKey) as Theme) || defaultTheme,
- );
-
- useEffect(() => {
- const root = window.document.documentElement;
-
- root.classList.remove("light", "dark");
-
- if (theme === "system") {
- const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
- .matches
- ? "dark"
- : "light";
-
- root.classList.add(systemTheme);
- return;
- }
-
- root.classList.add(theme);
- }, [theme]);
-
- const value = {
- theme,
- setTheme: (theme: Theme) => {
- localStorage.setItem(storageKey, theme);
- setTheme(theme);
- },
- };
-
- return (
-
- {children}
-
- );
-}
-
-export const useTheme = () => {
- const context = useContext(ThemeProviderContext);
-
- if (context === undefined)
- throw new Error("useTheme must be used within a ThemeProvider");
-
- return context;
-};
diff --git a/packages/dashboard/src/lib/syntax-styles.ts b/packages/dashboard/src/lib/syntax-styles.ts
deleted file mode 100644
index 74bef64c..00000000
--- a/packages/dashboard/src/lib/syntax-styles.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import styleDark from "react-syntax-highlighter/dist/esm/styles/hljs/stackoverflow-dark";
-
-styleDark["hljs"].padding = "1rem";
-delete styleDark["hljs"].background;
-
-import styleLight from "react-syntax-highlighter/dist/esm/styles/hljs/stackoverflow-light";
-
-styleLight["hljs"].padding = "1rem";
-delete styleLight["hljs"].background;
-
-export { styleLight, styleDark };
diff --git a/packages/dashboard/src/pages/ApiPage.tsx b/packages/dashboard/src/pages/ApiPage.tsx
index 6a9a2a7a..32f673cb 100644
--- a/packages/dashboard/src/pages/ApiPage.tsx
+++ b/packages/dashboard/src/pages/ApiPage.tsx
@@ -1,10 +1,8 @@
import { SelectObject } from "@/components/SelectObject";
-import { useTheme } from "@/components/ui/theme-provider";
import { useNavigate, useParams } from "react-router-dom";
export function ApiPage() {
const navigate = useNavigate();
- const { theme } = useTheme();
const { service = "api" } = useParams() as {
service?: string;
};
@@ -14,8 +12,6 @@ export function ApiPage() {
stitcher: window.__ENV__.PUBLIC_STITCHER_ENDPOINT,
}[service];
- const query = `?theme=${theme}`;
-
return (
<>
@@ -39,7 +35,7 @@ export function ApiPage() {
/>
-
+
>
);
}
diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts
index bb1a21da..0f0d9cfa 100644
--- a/packages/shared/src/index.ts
+++ b/packages/shared/src/index.ts
@@ -1,3 +1,5 @@
export * from "./env";
export * from "./typebox";
+
+export * from "./scalar";
diff --git a/packages/shared/src/scalar.ts b/packages/shared/src/scalar.ts
new file mode 100644
index 00000000..5fa69928
--- /dev/null
+++ b/packages/shared/src/scalar.ts
@@ -0,0 +1,10 @@
+export const scalarCustomCss = `
+ .scalar-container.z-overlay {
+ padding-left: 16px;
+ padding-right: 16px;
+ }
+
+ .scalar-api-client__send-request-button, .show-api-client-button {
+ background: var(--scalar-button-1);
+ }
+`;
diff --git a/packages/stitcher/src/index.ts b/packages/stitcher/src/index.ts
index 3a8c42ca..191e5673 100644
--- a/packages/stitcher/src/index.ts
+++ b/packages/stitcher/src/index.ts
@@ -1,6 +1,7 @@
import { Elysia, t } from "elysia";
import { cors } from "@elysiajs/cors";
import { swagger } from "@elysiajs/swagger";
+import { scalarCustomCss } from "@mixwave/shared";
import { env } from "./env";
import { createSession } from "./session";
import { validateFilter } from "./filters";
@@ -11,17 +12,6 @@ import {
formatAssetList,
} from "./playlist";
-const CUSTOM_SCALAR_CSS = `
- .scalar-container.z-overlay {
- padding-left: 16px;
- padding-right: 16px;
- }
-
- .scalar-api-client__send-request-button, .show-api-client-button {
- background: var(--scalar-button-1);
- }
-`;
-
const app = new Elysia()
.use(cors())
.use(
@@ -36,7 +26,7 @@ const app = new Elysia()
},
scalarConfig: {
hideDownloadButton: true,
- customCss: CUSTOM_SCALAR_CSS,
+ customCss: scalarCustomCss,
},
}),
)