Skip to content

Commit

Permalink
Add custom css support
Browse files Browse the repository at this point in the history
  • Loading branch information
SupertigerDev committed Sep 14, 2024
1 parent bd41e22 commit c857415
Show file tree
Hide file tree
Showing 12 changed files with 1,000 additions and 47 deletions.
8 changes: 8 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
"vite-plugin-solid": "^2.10.2"
},
"dependencies": {
"@codemirror/autocomplete": "^6.18.0",
"@codemirror/commands": "^6.6.1",
"@codemirror/lang-css": "^6.3.0",
"@codemirror/language": "^6.10.2",
"@codemirror/state": "^6.4.1",
"@codemirror/view": "^6.33.0",
"@material-symbols/font-400": "^0.21.3",
"@mbarzda/solid-i18next": "^1.4.1",
"@melloware/coloris": "^0.24.0",
Expand All @@ -58,10 +64,12 @@
"match-sorter": "^6.3.4",
"sass": "^1.78.0",
"socket.io-client": "^4.7.5",
"solid-codemirror": "^2.3.1",
"solid-js": "^1.8.22",
"solid-navigator": "^0.3.14",
"solid-sortablejs": "^2.1.2",
"solid-styled-components": "^0.28.5",
"thememirror": "^2.0.1",
"twemoji": "^14.0.2",
"uzip": "^0.20201231.0",
"voice-activity-detection": "^0.0.5",
Expand Down
702 changes: 702 additions & 0 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions src/common/Settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,14 @@ const settings: Setting[] = [
icon: "brush",
element: lazy(() => import("@/components/settings/InterfaceSettings")),
},
{
path: "/interface/custom-css",
routePath: "/interface/custom-css",
name: "settings.drawer.interface",
icon: "code",
element: lazy(() => import("@/components/settings/CustomCssSettings")),
hide: true,
},
{
path: "notifications",
routePath: "/notifications",
Expand Down
20 changes: 20 additions & 0 deletions src/common/customCss.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { getStorageString, StorageKeys } from "./localStorage";

export const applyCustomCss = () => {
let style = document.getElementById("custom-css");
const css = getStorageString(StorageKeys.CUSTOM_CSS, "");

if (!css.trim().length) {
if (style) {
style.innerHTML = css;
}
return;
}

if (!style) {
style = document.createElement("style");
style.id = "custom-css";
document.head.appendChild(style);
}
style.innerHTML = css;
};
18 changes: 7 additions & 11 deletions src/common/localStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ export enum StorageKeys {
ENABLED_EXPERIMENTS = "enabledExperiments",
DISABLED_ADVANCED_MARKUP = "disabledAdvancedMarkup",
NOTIFICATION_SOUNDS = "notificationSounds",
CUSTOM_CSS = "customCss",
CUSTOM_COLORS = "customColors",
inputDeviceId = "inputDeviceId",
outputDeviceId = "outputDeviceId",
}

export function getStorageBoolean(key: StorageKeys, defaultValue: boolean): boolean {
export function getStorageBoolean(
key: StorageKeys,
defaultValue: boolean
): boolean {
const value = localStorage.getItem(key);
if (!value) return defaultValue;
return JSON.parse(value);
Expand Down Expand Up @@ -51,7 +55,6 @@ export function setStorageNumber(key: StorageKeys, value: number) {
localStorage.setItem(key, value.toString());
}


export function getStorageObject<T>(key: StorageKeys, defaultValue: T): T {
const value = getStorageString(key, null);
if (value === null) {
Expand All @@ -64,16 +67,10 @@ export function setStorageObject<T>(key: StorageKeys, value: T) {
setStorageString(key, JSON.stringify(value));
}



export function removeStorage(key: StorageKeys) {
localStorage.removeItem(key);
}





export function useReactiveLocalStorage<T>(key: StorageKeys, defaultValue: T) {
const [value, setValue] = createSignal<T>(defaultValue);

Expand All @@ -82,9 +79,8 @@ export function useReactiveLocalStorage<T>(key: StorageKeys, defaultValue: T) {

const setCustomValue = (value: T) => {
setValue(() => value);
setStorageString(key, JSON.stringify(value));
setStorageString(key, JSON.stringify(value));
};

return [value, setCustomValue] as const;

}
}
90 changes: 90 additions & 0 deletions src/components/code-mirror/CodeMirror.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { createCodeMirror } from "solid-codemirror";
import { EditorState, Extension } from "@codemirror/state";

import { css } from "@codemirror/lang-css";
import { dracula } from "thememirror";
import {
defaultKeymap,
history,
historyKeymap,
indentWithTab,
} from "@codemirror/commands";
import {
crosshairCursor,
highlightSpecialChars,
keymap,
lineNumbers,
rectangularSelection,
} from "@codemirror/view";
import {
defaultHighlightStyle,
syntaxHighlighting,
indentOnInput,
bracketMatching,
foldGutter,
foldKeymap,
} from "@codemirror/language";
import {
autocompletion,
completionKeymap,
closeBrackets,
closeBracketsKeymap,
} from "@codemirror/autocomplete";
const EDITOR_BASE_SETUP: Extension = [
lineNumbers(),
highlightSpecialChars(),
history(),
foldGutter(),
EditorState.allowMultipleSelections.of(true),
indentOnInput(),
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
bracketMatching(),
closeBrackets(),
autocompletion(),
rectangularSelection(),
crosshairCursor(),
keymap.of([
...closeBracketsKeymap,
...defaultKeymap,
...historyKeymap,
...foldKeymap,
...completionKeymap,
indentWithTab,
]),

css(),
dracula,
];

interface Props {
value: string;
onValueChange: (value: string) => void;
}

export default (props: Props) => {
let containerRef: HTMLDivElement | undefined;
const {
editorView,
ref: editorRef,
createExtension,
} = createCodeMirror({
value: props.value,
onValueChange: (value) => props.onValueChange(value),
});

createExtension(EDITOR_BASE_SETUP);

return (
<div
ref={containerRef}
style={{
"border-radius": "8px",
overflow: "hidden",
height: "100%",
border: "solid 1px rgba(255, 255, 255, 0.1)",
}}
>
<div ref={editorRef} style={{ height: "100%" }} />
</div>
);
};
65 changes: 65 additions & 0 deletions src/components/settings/CustomCssSettings.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { createEffect, createSignal, lazy } from "solid-js";
import { styled } from "solid-styled-components";

import useStore from "@/chat-api/store/useStore";
import Breadcrumb, { BreadcrumbItem } from "../ui/Breadcrumb";
import { t } from "i18next";
import {
getStorageString,
setStorageString,
StorageKeys,
} from "@/common/localStorage";
import Button from "../ui/Button";
import { Notice } from "../ui/Notice/Notice";
import { applyCustomCss } from "@/common/customCss";

const CodeMirror = lazy(() => import("@/components/code-mirror/CodeMirror"));

const Container = styled("div")`
display: flex;
flex-direction: column;
gap: 5px;
padding: 10px;
height: 100%;
`;

export default function CustomCssSettings() {
const { header } = useStore();
const [css, setCss] = createSignal(
getStorageString(StorageKeys.CUSTOM_CSS, "")
);

createEffect(() => {
header.updateHeader({
title: "Settings - Custom CSS",
iconName: "settings",
});
});

const onSaveClick = () => {
setStorageString(StorageKeys.CUSTOM_CSS, css());
applyCustomCss();
};

return (
<Container>
<Breadcrumb style={{ "margin-bottom": "8px" }}>
<BreadcrumbItem href="/app" icon="home" title="Dashboard" />
<BreadcrumbItem title={t("settings.drawer.interface")} href="../" />
<BreadcrumbItem title="Custom CSS" />
</Breadcrumb>

<Notice
type="warn"
description="Do not paste code from people you don't trust."
/>
<CodeMirror value={css()} onValueChange={setCss} />
<Button
label="Save & Apply"
onClick={onSaveClick}
iconName="save"
margin={0}
/>
</Container>
);
}
Loading

0 comments on commit c857415

Please sign in to comment.