pull/3826/merge
Adam 2025-07-10 14:00:58 +02:00 committed by GitHub
commit 67dcdb7052
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 113 additions and 52 deletions

View File

@ -171,6 +171,7 @@ func printSettings(ser *settings.Server, set *settings.Settings, auther auth.Aut
fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode) fmt.Fprintf(w, "\tView mode:\t%s\n", set.Defaults.ViewMode)
fmt.Fprintf(w, "\tSingle Click:\t%t\n", set.Defaults.SingleClick) fmt.Fprintf(w, "\tSingle Click:\t%t\n", set.Defaults.SingleClick)
fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " ")) fmt.Fprintf(w, "\tCommands:\t%s\n", strings.Join(set.Defaults.Commands, " "))
fmt.Fprintf(w, "\tAce editor syntax highlighting theme:\t%s\n", set.Defaults.AceEditorTheme)
fmt.Fprintf(w, "\tSorting:\n") fmt.Fprintf(w, "\tSorting:\n")
fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By) fmt.Fprintf(w, "\t\tBy:\t%s\n", set.Defaults.Sorting.By)
fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc) fmt.Fprintf(w, "\t\tAsc:\t%t\n", set.Defaults.Sorting.Asc)

View File

@ -374,6 +374,7 @@ func quickSetup(flags *pflag.FlagSet, d pythonData) {
Scope: ".", Scope: ".",
Locale: "en", Locale: "en",
SingleClick: false, SingleClick: false,
AceEditorTheme: getParam(flags, "defaults.aceEditorTheme"),
Perm: users.Permissions{ Perm: users.Permissions{
Admin: false, Admin: false,
Execute: true, Execute: true,

View File

@ -77,6 +77,7 @@ func addUserFlags(flags *pflag.FlagSet) {
flags.String("locale", "en", "locale for users") flags.String("locale", "en", "locale for users")
flags.String("viewMode", string(users.ListViewMode), "view mode for users") flags.String("viewMode", string(users.ListViewMode), "view mode for users")
flags.Bool("singleClick", false, "use single clicks only") flags.Bool("singleClick", false, "use single clicks only")
flags.String("aceEditorTheme", "", "ace editor's syntax highlighting theme for users")
} }
func getViewMode(flags *pflag.FlagSet) users.ViewMode { func getViewMode(flags *pflag.FlagSet) users.ViewMode {
@ -99,6 +100,8 @@ func getUserDefaults(flags *pflag.FlagSet, defaults *settings.UserDefaults, all
defaults.ViewMode = getViewMode(flags) defaults.ViewMode = getViewMode(flags)
case "singleClick": case "singleClick":
defaults.SingleClick = mustGetBool(flags, flag.Name) defaults.SingleClick = mustGetBool(flags, flag.Name)
case "aceEditorTheme":
defaults.AceEditorTheme = mustGetString(flags, flag.Name)
case "perm.admin": case "perm.admin":
defaults.Perm.Admin = mustGetBool(flags, flag.Name) defaults.Perm.Admin = mustGetBool(flags, flag.Name)
case "perm.execute": case "perm.execute":

View File

@ -0,0 +1,24 @@
<template>
<select name="selectAceEditorTheme" v-on:change="change" :value="aceEditorTheme">
<option v-for="theme in themes" :value="theme.theme" :key="theme.theme">
{{ theme.name }}
</option>
</select>
</template>
<script setup lang="ts">
import { type SelectHTMLAttributes } from "vue";
import { themes } from "ace-builds/src-noconflict/ext-themelist";
defineProps<{
aceEditorTheme: string;
}>();
const emit = defineEmits<{
(e: "update:aceEditorTheme", val: string | null): void;
}>();
const change = (event: Event) => {
emit("update:aceEditorTheme", (event.target as SelectHTMLAttributes)?.value);
};
</script>

View File

@ -154,6 +154,7 @@
"video": "Video" "video": "Video"
}, },
"settings": { "settings": {
"aceEditorTheme": "Ace editor theme",
"admin": "Admin", "admin": "Admin",
"administrator": "Administrator", "administrator": "Administrator",
"allowCommands": "Execute commands", "allowCommands": "Execute commands",

View File

@ -21,6 +21,7 @@ interface SettingsDefaults {
commands: any[]; commands: any[];
hideDotfiles: boolean; hideDotfiles: boolean;
dateFormat: boolean; dateFormat: boolean;
aceEditorTheme: string;
} }
interface SettingsBranding { interface SettingsBranding {

View File

@ -13,6 +13,7 @@ interface IUser {
dateFormat: boolean; dateFormat: boolean;
viewMode: ViewModeType; viewMode: ViewModeType;
sorting?: Sorting; sorting?: Sorting;
aceEditorTheme: string;
} }
type ViewModeType = "list" | "mosaic" | "mosaic gallery"; type ViewModeType = "list" | "mosaic" | "mosaic gallery";

View File

@ -1,4 +1,6 @@
import { theme } from "./constants"; import { theme } from "./constants";
import "ace-builds";
import { themesByName } from "ace-builds/src-noconflict/ext-themelist";
export const getTheme = (): UserTheme => { export const getTheme = (): UserTheme => {
return (document.documentElement.className as UserTheme) || theme; return (document.documentElement.className as UserTheme) || theme;
@ -32,3 +34,17 @@ export const getMediaPreference = (): UserTheme => {
return "light"; return "light";
} }
}; };
export const getEditorTheme = (themeName: string) => {
if (!themeName.startsWith("ace/theme/")) {
themeName = `ace/theme/${themeName}`;
}
const themeKey = themeName.replace("ace/theme/", "");
if (themesByName[themeKey] !== undefined) {
return themeName;
} else if (getTheme() === "dark") {
return "ace/theme/twilight";
} else {
return "ace/theme/chrome";
}
};

View File

@ -52,7 +52,7 @@ import { useLayoutStore } from "@/stores/layout";
import { inject, onBeforeUnmount, onMounted, ref, watchEffect } from "vue"; import { inject, onBeforeUnmount, onMounted, ref, watchEffect } from "vue";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { getTheme } from "@/utils/theme"; import { getEditorTheme } from "@/utils/theme";
import { marked } from "marked"; import { marked } from "marked";
const $showError = inject<IToastError>("$showError")!; const $showError = inject<IToastError>("$showError")!;
@ -108,7 +108,7 @@ onMounted(() => {
value: fileContent, value: fileContent,
showPrintMargin: false, showPrintMargin: false,
readOnly: fileStore.req?.type === "textImmutable", readOnly: fileStore.req?.type === "textImmutable",
theme: "ace/theme/chrome", theme: getEditorTheme(authStore.user?.aceEditorTheme ?? ""),
mode: modelist.getModeForPath(fileStore.req!.name).mode, mode: modelist.getModeForPath(fileStore.req!.name).mode,
wrap: true, wrap: true,
enableBasicAutocompletion: true, enableBasicAutocompletion: true,
@ -116,10 +116,6 @@ onMounted(() => {
enableSnippets: true, enableSnippets: true,
}); });
if (getTheme() === "dark") {
editor.value!.setTheme("ace/theme/twilight");
}
editor.value.focus(); editor.value.focus();
}); });

View File

@ -24,6 +24,13 @@
class="input input--block" class="input input--block"
v-model:locale="locale" v-model:locale="locale"
></languages> ></languages>
<h3>{{ t("settings.aceEditorTheme") }}</h3>
<AceEditorTheme
class="input input--block"
v-model:aceEditorTheme="aceEditorTheme"
id="aceTheme"
></AceEditorTheme>
</div> </div>
<div class="card-action"> <div class="card-action">
@ -81,6 +88,7 @@
import { useAuthStore } from "@/stores/auth"; import { useAuthStore } from "@/stores/auth";
import { useLayoutStore } from "@/stores/layout"; import { useLayoutStore } from "@/stores/layout";
import { users as api } from "@/api"; import { users as api } from "@/api";
import AceEditorTheme from "@/components/settings/AceEditorTheme.vue";
import Languages from "@/components/settings/Languages.vue"; import Languages from "@/components/settings/Languages.vue";
import { computed, inject, onMounted, ref } from "vue"; import { computed, inject, onMounted, ref } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
@ -98,6 +106,7 @@ const hideDotfiles = ref<boolean>(false);
const singleClick = ref<boolean>(false); const singleClick = ref<boolean>(false);
const dateFormat = ref<boolean>(false); const dateFormat = ref<boolean>(false);
const locale = ref<string>(""); const locale = ref<string>("");
const aceEditorTheme = ref<string>("");
const passwordClass = computed(() => { const passwordClass = computed(() => {
const baseClass = "input input--block"; const baseClass = "input input--block";
@ -113,13 +122,14 @@ const passwordClass = computed(() => {
return `${baseClass} input--red`; return `${baseClass} input--red`;
}); });
onMounted(() => { onMounted(async () => {
layoutStore.loading = true; layoutStore.loading = true;
if (authStore.user === null) return false; if (authStore.user === null) return false;
locale.value = authStore.user.locale; locale.value = authStore.user.locale;
hideDotfiles.value = authStore.user.hideDotfiles; hideDotfiles.value = authStore.user.hideDotfiles;
singleClick.value = authStore.user.singleClick; singleClick.value = authStore.user.singleClick;
dateFormat.value = authStore.user.dateFormat; dateFormat.value = authStore.user.dateFormat;
aceEditorTheme.value = authStore.user.aceEditorTheme;
layoutStore.loading = false; layoutStore.loading = false;
return true; return true;
}); });
@ -163,6 +173,7 @@ const updateSettings = async (event: Event) => {
hideDotfiles: hideDotfiles.value, hideDotfiles: hideDotfiles.value,
singleClick: singleClick.value, singleClick: singleClick.value,
dateFormat: dateFormat.value, dateFormat: dateFormat.value,
aceEditorTheme: aceEditorTheme.value,
}; };
await api.update(data, [ await api.update(data, [
@ -170,6 +181,7 @@ const updateSettings = async (event: Event) => {
"hideDotfiles", "hideDotfiles",
"singleClick", "singleClick",
"dateFormat", "dateFormat",
"aceEditorTheme",
]); ]);
authStore.updateUser(data); authStore.updateUser(data);
$showSuccess(t("settings.settingsUpdated")); $showSuccess(t("settings.settingsUpdated"));

View File

@ -30,6 +30,7 @@ type userInfo struct {
LockPassword bool `json:"lockPassword"` LockPassword bool `json:"lockPassword"`
HideDotfiles bool `json:"hideDotfiles"` HideDotfiles bool `json:"hideDotfiles"`
DateFormat bool `json:"dateFormat"` DateFormat bool `json:"dateFormat"`
AceEditorTheme string `json:"aceEditorTheme"`
} }
type authToken struct { type authToken struct {
@ -198,6 +199,7 @@ func printToken(w http.ResponseWriter, _ *http.Request, d *data, user *users.Use
Commands: user.Commands, Commands: user.Commands,
HideDotfiles: user.HideDotfiles, HideDotfiles: user.HideDotfiles,
DateFormat: user.DateFormat, DateFormat: user.DateFormat,
AceEditorTheme: user.AceEditorTheme,
}, },
RegisteredClaims: jwt.RegisteredClaims{ RegisteredClaims: jwt.RegisteredClaims{
IssuedAt: jwt.NewNumericDate(time.Now()), IssuedAt: jwt.NewNumericDate(time.Now()),

View File

@ -17,6 +17,7 @@ type UserDefaults struct {
Commands []string `json:"commands"` Commands []string `json:"commands"`
HideDotfiles bool `json:"hideDotfiles"` HideDotfiles bool `json:"hideDotfiles"`
DateFormat bool `json:"dateFormat"` DateFormat bool `json:"dateFormat"`
AceEditorTheme string `json:"aceEditorTheme"`
} }
// Apply applies the default options to a user. // Apply applies the default options to a user.
@ -30,4 +31,5 @@ func (d *UserDefaults) Apply(u *users.User) {
u.Commands = d.Commands u.Commands = d.Commands
u.HideDotfiles = d.HideDotfiles u.HideDotfiles = d.HideDotfiles
u.DateFormat = d.DateFormat u.DateFormat = d.DateFormat
u.AceEditorTheme = d.AceEditorTheme
} }

View File

@ -35,6 +35,7 @@ type User struct {
Rules []rules.Rule `json:"rules"` Rules []rules.Rule `json:"rules"`
HideDotfiles bool `json:"hideDotfiles"` HideDotfiles bool `json:"hideDotfiles"`
DateFormat bool `json:"dateFormat"` DateFormat bool `json:"dateFormat"`
AceEditorTheme string `json:"aceEditorTheme"`
} }
// GetRules implements rules.Provider. // GetRules implements rules.Provider.