mirror of
https://github.com/Vomitblood/stort.git
synced 2024-11-26 13:55:27 +08:00
changed config format from json to toml
This commit is contained in:
parent
515ea481ed
commit
7567e53a85
18
.prettierrc
Normal file
18
.prettierrc
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"arrowParens": "always",
|
||||||
|
"bracketSameLine": false,
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"endOfLine": "lf",
|
||||||
|
"htmlWhitespaceSensitivity": "css",
|
||||||
|
"jsxBracketSameLine": false,
|
||||||
|
"jsxSingleQuote": true,
|
||||||
|
"printWidth": 120,
|
||||||
|
"proseWrap": "preserve",
|
||||||
|
"quoteProps": "consistent",
|
||||||
|
"semi": true,
|
||||||
|
"singleAttributePerLine": true,
|
||||||
|
"singleQuote": false,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"useTabs": false
|
||||||
|
}
|
2
.tool-versions
Normal file
2
.tool-versions
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
bun 1.1.21
|
||||||
|
nodejs 20.6.1
|
5030
package-lock.json
generated
Normal file
5030
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -17,16 +17,16 @@
|
||||||
"@mui/icons-material": "^5.16.6",
|
"@mui/icons-material": "^5.16.6",
|
||||||
"@mui/material": "^5.16.6",
|
"@mui/material": "^5.16.6",
|
||||||
"@tauri-apps/api": "^1.6.0",
|
"@tauri-apps/api": "^1.6.0",
|
||||||
"@types/lodash": "^4.17.7",
|
|
||||||
"jotai": "^2.9.1",
|
"jotai": "^2.9.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lowdb": "^7.0.1",
|
|
||||||
"next": "14.2.5",
|
"next": "14.2.5",
|
||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
|
"smol-toml": "^1.3.0",
|
||||||
"zustand": "^4.5.4"
|
"zustand": "^4.5.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/lodash": "^4.17.7",
|
||||||
"@tauri-apps/cli": "^1.6.0",
|
"@tauri-apps/cli": "^1.6.0",
|
||||||
"@types/node": "^20.14.14",
|
"@types/node": "^20.14.14",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
|
|
|
@ -17,7 +17,7 @@ tauri-build = { version = "1.5.3", features = [] }
|
||||||
[dependencies]
|
[dependencies]
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
tauri = { version = "1.7.0", features = [ "path-all", "window-all", "process-all", "notification-all", "dialog-all"] }
|
tauri = { version = "1.7.0", features = [ "fs-all", "path-all", "window-all", "process-all", "notification-all", "dialog-all"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
|
# this feature is used for production builds or when `devPath` points to the filesystem and the built-in dev server is disabled.
|
||||||
|
|
|
@ -20,6 +20,13 @@
|
||||||
"open": true,
|
"open": true,
|
||||||
"save": true
|
"save": true
|
||||||
},
|
},
|
||||||
|
"fs": {
|
||||||
|
"all": true,
|
||||||
|
"scope": [
|
||||||
|
"$CONFIG/stort/",
|
||||||
|
"$CONFIG/stort/**"
|
||||||
|
]
|
||||||
|
},
|
||||||
"notification": {
|
"notification": {
|
||||||
"all": true
|
"all": true
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,11 +1,23 @@
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { usePathStore } from "../../lib/store/zustand/path";
|
import Paths from "../../lib/path";
|
||||||
|
import { createDir, exists } from "@tauri-apps/api/fs";
|
||||||
|
|
||||||
export const Initialization = () => {
|
export const Initialization = () => {
|
||||||
const setPaths = usePathStore((state) => state.setPaths);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPaths();
|
const initializePaths = async () => {
|
||||||
|
try {
|
||||||
|
await Paths.initialize();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to initialize paths: ${error}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const createDirectories = async () => {
|
||||||
|
const configDirectoryExists = await exists(Paths.getPath("configDirectory"));
|
||||||
|
if (!configDirectoryExists) await createDir(Paths.getPath("configDirectory"));
|
||||||
|
};
|
||||||
|
|
||||||
|
initializePaths().then(() => createDirectories());
|
||||||
});
|
});
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -1,45 +1,27 @@
|
||||||
import {
|
import { createContext, FC, ReactNode, useContext, useEffect, useState } from "react";
|
||||||
createContext,
|
|
||||||
FC,
|
|
||||||
ReactNode,
|
|
||||||
useContext,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useState,
|
|
||||||
} from "react";
|
|
||||||
import { defaultSettings, SettingsType } from "../lib/defaultSettings";
|
|
||||||
import { logcat } from "../lib/logcatService";
|
import { logcat } from "../lib/logcatService";
|
||||||
import { LowDB } from "../lib/lowDB";
|
import { defaultSettings, readConfigFile, SettingsType, writeConfigFile } from "../lib/settings";
|
||||||
|
|
||||||
// settings context
|
// settings context
|
||||||
type SettingsContextProps = {
|
type SettingsContextProps = {
|
||||||
settings: SettingsType;
|
settings: SettingsType;
|
||||||
settingsLoading: boolean;
|
settingsLoading: boolean;
|
||||||
|
updateSettings: (updates: SettingsType) => void;
|
||||||
|
resetSettings: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SettingsContext = createContext<SettingsContextProps | undefined>(
|
const SettingsContext = createContext<SettingsContextProps | undefined>(undefined);
|
||||||
undefined,
|
|
||||||
);
|
|
||||||
|
|
||||||
export const SettingsProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
export const SettingsProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
||||||
logcat.log("Initializing settings...", "INFO");
|
logcat.log("Initializing settings...", "INFO");
|
||||||
|
|
||||||
// useStates
|
// states
|
||||||
const [settings, setSettings] = useState<SettingsType>(defaultSettings);
|
const [settings, setSettings] = useState<SettingsType>(defaultSettings);
|
||||||
const [settingsLoading, setSettingsLoading] = useState<boolean>(true);
|
const [settingsLoading, setSettingsLoading] = useState<boolean>(true);
|
||||||
|
|
||||||
// initialize a new lowdb instance for settings outside of state
|
const updateSettings = async (newSettings: SettingsType) => {
|
||||||
const settingsDB = useMemo(() => {
|
|
||||||
return new LowDB<SettingsType>("settings.json", defaultSettings);
|
|
||||||
}, []); // empty dependency array ensures this is only created once
|
|
||||||
|
|
||||||
// function to update settings
|
|
||||||
const updateSettings = async (updates: Partial<SettingsType>) => {
|
|
||||||
try {
|
try {
|
||||||
await settingsDB.updateData((data) => {
|
await writeConfigFile(newSettings);
|
||||||
Object.assign(data, updates);
|
|
||||||
});
|
|
||||||
const newSettings = await settingsDB.readData();
|
|
||||||
setSettings(newSettings);
|
setSettings(newSettings);
|
||||||
logcat.log("Settings updated successfully", "INFO");
|
logcat.log("Settings updated successfully", "INFO");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -47,13 +29,24 @@ export const SettingsProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// set settings state to default values
|
||||||
|
// and write default values to the settings file
|
||||||
|
const resetSettings = async () => {
|
||||||
|
try {
|
||||||
|
await writeConfigFile(defaultSettings);
|
||||||
|
setSettings(defaultSettings);
|
||||||
|
logcat.log("Settings reset successfully", "INFO");
|
||||||
|
} catch (error) {
|
||||||
|
logcat.log(`Failed to reset settings: ${error}`, "ERROR");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// fetch user settings from local on first load every time
|
// fetch user settings from local on first load every time
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchSettings = async () => {
|
const fetchSettings = async () => {
|
||||||
try {
|
try {
|
||||||
await settingsDB.init();
|
const existingSettings = await readConfigFile();
|
||||||
const storedSettings = await settingsDB.readData();
|
setSettings(existingSettings);
|
||||||
setSettings(storedSettings);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logcat.log(`Failed to load settings: ${error}`, "ERROR");
|
logcat.log(`Failed to load settings: ${error}`, "ERROR");
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -62,13 +55,15 @@ export const SettingsProvider: FC<{ children: ReactNode }> = ({ children }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
fetchSettings();
|
fetchSettings();
|
||||||
}, [settingsDB]);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingsContext.Provider
|
<SettingsContext.Provider
|
||||||
value={{
|
value={{
|
||||||
settings,
|
settings,
|
||||||
settingsLoading,
|
settingsLoading,
|
||||||
|
updateSettings,
|
||||||
|
resetSettings,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
export const defaultSettings = {
|
|
||||||
display: {
|
|
||||||
dark_mode: true as boolean,
|
|
||||||
accent_color: "#8ab4f8" as string,
|
|
||||||
transition_duration: 200 as number,
|
|
||||||
radius: 8 as number,
|
|
||||||
window_height: 60 as number,
|
|
||||||
window_width: 400 as number,
|
|
||||||
font_family: "monospace" as string,
|
|
||||||
font_scaling: 100,
|
|
||||||
},
|
|
||||||
} as const;
|
|
||||||
|
|
||||||
export type SettingsType = typeof defaultSettings;
|
|
|
@ -1,53 +0,0 @@
|
||||||
import { merge } from "lodash";
|
|
||||||
import { Low } from "lowdb";
|
|
||||||
import { JSONFile } from "lowdb/node";
|
|
||||||
|
|
||||||
// define a generic interface for json structure
|
|
||||||
interface Database<T> {
|
|
||||||
data: T;
|
|
||||||
}
|
|
||||||
|
|
||||||
type UpdateCallback<T> = (data: T) => void;
|
|
||||||
|
|
||||||
export class LowDB<T> {
|
|
||||||
private db: Low<Database<T>>;
|
|
||||||
private defaultData: T;
|
|
||||||
|
|
||||||
constructor(filePath: string, defaultData: T) {
|
|
||||||
const adapter = new JSONFile<Database<T>>(filePath);
|
|
||||||
this.db = new Low(adapter, { data: defaultData });
|
|
||||||
this.defaultData = defaultData;
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize the json file and merge with default data if needed
|
|
||||||
async init() {
|
|
||||||
await this.db.read();
|
|
||||||
if (!this.db.data || !this.db.data.data) {
|
|
||||||
// initialize with default data
|
|
||||||
this.db.data = { data: { ...this.defaultData } };
|
|
||||||
} else {
|
|
||||||
// merge existing data with default data to fill in missing properties
|
|
||||||
this.db.data.data = { ...this.defaultData, ...this.db.data.data };
|
|
||||||
}
|
|
||||||
await this.db.write();
|
|
||||||
}
|
|
||||||
|
|
||||||
async readData(): Promise<T> {
|
|
||||||
await this.db.read();
|
|
||||||
// ensure that the data is merged with default values every time it is read
|
|
||||||
this.db.data!.data = merge({}, this.defaultData, this.db.data!.data);
|
|
||||||
return this.db.data!.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
async writeData(data: T): Promise<void> {
|
|
||||||
this.db.data!.data = data;
|
|
||||||
await this.db.write();
|
|
||||||
}
|
|
||||||
|
|
||||||
// update a specific part of the json file
|
|
||||||
async updateData(callback: UpdateCallback<T>): Promise<void> {
|
|
||||||
await this.db.read();
|
|
||||||
callback(this.db.data!.data);
|
|
||||||
await this.db.write();
|
|
||||||
}
|
|
||||||
}
|
|
88
src/lib/path.ts
Normal file
88
src/lib/path.ts
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
type PathsType = {
|
||||||
|
audioDirectory: string;
|
||||||
|
cacheDirectory: string;
|
||||||
|
configDirectory: string;
|
||||||
|
dataDirectory: string;
|
||||||
|
desktopDirectory: string;
|
||||||
|
documentDirectory: string;
|
||||||
|
downloadDirectory: string;
|
||||||
|
executableDirectory: string;
|
||||||
|
fontDirectory: string;
|
||||||
|
homeDirectory: string;
|
||||||
|
logDirectory: string;
|
||||||
|
pictureDirectory: string;
|
||||||
|
templateDirectory: string;
|
||||||
|
videoDirectory: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const programTrailingPath = "stort/";
|
||||||
|
|
||||||
|
class Paths {
|
||||||
|
private static instance: Paths;
|
||||||
|
paths: PathsType | null = null;
|
||||||
|
|
||||||
|
private constructor() {}
|
||||||
|
|
||||||
|
static getInstance(): Paths {
|
||||||
|
if (!Paths.instance) {
|
||||||
|
Paths.instance = new Paths();
|
||||||
|
}
|
||||||
|
return Paths.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
async initialize(): Promise<void> {
|
||||||
|
// avoid reinitialization if already doen
|
||||||
|
if (this.paths) return;
|
||||||
|
|
||||||
|
const {
|
||||||
|
audioDir,
|
||||||
|
cacheDir,
|
||||||
|
configDir,
|
||||||
|
dataDir,
|
||||||
|
desktopDir,
|
||||||
|
documentDir,
|
||||||
|
downloadDir,
|
||||||
|
executableDir,
|
||||||
|
fontDir,
|
||||||
|
homeDir,
|
||||||
|
logDir,
|
||||||
|
pictureDir,
|
||||||
|
templateDir,
|
||||||
|
videoDir,
|
||||||
|
} = await import("@tauri-apps/api/path");
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.paths = {
|
||||||
|
audioDirectory: await audioDir(),
|
||||||
|
cacheDirectory: (await cacheDir()) + programTrailingPath,
|
||||||
|
configDirectory: (await configDir()) + programTrailingPath,
|
||||||
|
dataDirectory: (await dataDir()) + programTrailingPath,
|
||||||
|
desktopDirectory: await desktopDir(),
|
||||||
|
documentDirectory: await documentDir(),
|
||||||
|
downloadDirectory: await downloadDir(),
|
||||||
|
executableDirectory: await executableDir(),
|
||||||
|
fontDirectory: await fontDir(),
|
||||||
|
homeDirectory: await homeDir(),
|
||||||
|
logDirectory: await logDir(),
|
||||||
|
pictureDirectory: await pictureDir(),
|
||||||
|
templateDirectory: await templateDir(),
|
||||||
|
videoDirectory: await videoDir(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// make paths immutable
|
||||||
|
Object.freeze(this.paths);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error initializing paths:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getPath(key: keyof PathsType): string {
|
||||||
|
if (!this.paths) {
|
||||||
|
throw new Error("Paths are not initialized. Call initialize() first.");
|
||||||
|
}
|
||||||
|
return this.paths[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Paths.getInstance();
|
43
src/lib/settings.ts
Normal file
43
src/lib/settings.ts
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import Paths from "./path";
|
||||||
|
import { readTomlFile, writeTomlFile } from "./utils/toml";
|
||||||
|
|
||||||
|
export const defaultSettings = {
|
||||||
|
display: {
|
||||||
|
dark_mode: true as boolean,
|
||||||
|
accent_color: "#8ab4f8" as string,
|
||||||
|
transition_duration: 200 as number,
|
||||||
|
radius: 8 as number,
|
||||||
|
window_height: 60 as number,
|
||||||
|
window_width: 400 as number,
|
||||||
|
font_family: "monospace" as string,
|
||||||
|
font_scaling: 100,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SettingsType = typeof defaultSettings;
|
||||||
|
|
||||||
|
export const readConfigFile = async (): Promise<SettingsType> => {
|
||||||
|
let existingData: SettingsType = defaultSettings;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// try to read the config file
|
||||||
|
const data = await readTomlFile<SettingsType>(Paths.getPath("configDirectory") + "config.toml");
|
||||||
|
if (data) {
|
||||||
|
existingData = data;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
// file does not exist, called function will throw error
|
||||||
|
console.error(`Failed to read settings file: ${error}, using default settings.`);
|
||||||
|
existingData = defaultSettings;
|
||||||
|
}
|
||||||
|
|
||||||
|
// merge the existing data with the default settings
|
||||||
|
// existing data will overwrite the default settings for the properties that exist
|
||||||
|
const mergedSettings = { ...defaultSettings, ...existingData };
|
||||||
|
|
||||||
|
return mergedSettings;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const writeConfigFile = async (settingsValues: SettingsType): Promise<void> => {
|
||||||
|
await writeTomlFile<SettingsType>(Paths.getPath("configDirectory") + "config.toml", settingsValues);
|
||||||
|
};
|
|
@ -1,93 +0,0 @@
|
||||||
import { create } from "zustand";
|
|
||||||
|
|
||||||
type Paths = {
|
|
||||||
audioDirectory: string;
|
|
||||||
cacheDirectory: string;
|
|
||||||
configDirectory: string;
|
|
||||||
dataDirectory: string;
|
|
||||||
desktopDirectory: string;
|
|
||||||
documentDirectory: string;
|
|
||||||
downloadDirectory: string;
|
|
||||||
executableDirectory: string;
|
|
||||||
fontDirectory: string;
|
|
||||||
homeDirectory: string;
|
|
||||||
logDirectory: string;
|
|
||||||
pictureDirectory: string;
|
|
||||||
templateDirectory: string;
|
|
||||||
videoDirectory: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type PathStore = {
|
|
||||||
paths: Paths;
|
|
||||||
setPaths: () => Promise<void>;
|
|
||||||
};
|
|
||||||
|
|
||||||
const programTrailingPath = "stort/";
|
|
||||||
|
|
||||||
const initializePaths = async (): Promise<Paths> => {
|
|
||||||
try {
|
|
||||||
const {
|
|
||||||
audioDir,
|
|
||||||
cacheDir,
|
|
||||||
configDir,
|
|
||||||
dataDir,
|
|
||||||
desktopDir,
|
|
||||||
documentDir,
|
|
||||||
downloadDir,
|
|
||||||
executableDir,
|
|
||||||
fontDir,
|
|
||||||
homeDir,
|
|
||||||
logDir,
|
|
||||||
pictureDir,
|
|
||||||
templateDir,
|
|
||||||
videoDir,
|
|
||||||
} = await import("@tauri-apps/api/path");
|
|
||||||
|
|
||||||
return {
|
|
||||||
audioDirectory: await audioDir(),
|
|
||||||
cacheDirectory: (await cacheDir()) + programTrailingPath,
|
|
||||||
configDirectory: (await configDir()) + programTrailingPath,
|
|
||||||
dataDirectory: (await dataDir()) + programTrailingPath,
|
|
||||||
desktopDirectory: await desktopDir(),
|
|
||||||
documentDirectory: await documentDir(),
|
|
||||||
downloadDirectory: await downloadDir(),
|
|
||||||
executableDirectory: await executableDir(),
|
|
||||||
fontDirectory: await fontDir(),
|
|
||||||
homeDirectory: await homeDir(),
|
|
||||||
logDirectory: await logDir(),
|
|
||||||
pictureDirectory: await pictureDir(),
|
|
||||||
templateDirectory: await templateDir(),
|
|
||||||
videoDirectory: await videoDir(),
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error initializing paths:", error);
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const usePathStore = create<PathStore>((set) => ({
|
|
||||||
paths: {
|
|
||||||
audioDirectory: "",
|
|
||||||
cacheDirectory: "",
|
|
||||||
configDirectory: "",
|
|
||||||
dataDirectory: "",
|
|
||||||
desktopDirectory: "",
|
|
||||||
documentDirectory: "",
|
|
||||||
downloadDirectory: "",
|
|
||||||
executableDirectory: "",
|
|
||||||
fontDirectory: "",
|
|
||||||
homeDirectory: "",
|
|
||||||
logDirectory: "",
|
|
||||||
pictureDirectory: "",
|
|
||||||
templateDirectory: "",
|
|
||||||
videoDirectory: "",
|
|
||||||
},
|
|
||||||
setPaths: async () => {
|
|
||||||
try {
|
|
||||||
const paths = await initializePaths();
|
|
||||||
set({ paths });
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to set paths:", error);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}));
|
|
5
src/lib/testing.ts
Normal file
5
src/lib/testing.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { createDir } from "@tauri-apps/api/fs";
|
||||||
|
|
||||||
|
export const testing = async () => {
|
||||||
|
await createDir("/home/vomitblood/.config/stort/");
|
||||||
|
};
|
21
src/lib/utils/json.ts
Normal file
21
src/lib/utils/json.ts
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
import { readTextFile, writeTextFile } from "@tauri-apps/api/fs";
|
||||||
|
|
||||||
|
export const readJsonFile = async <T>(path: string): Promise<T | null> => {
|
||||||
|
try {
|
||||||
|
const contents = await readTextFile(path);
|
||||||
|
return JSON.parse(contents);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to read JSON file ${path}: ${error}`);
|
||||||
|
throw new Error(`Failed to read JSON file ${path}: ${error}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const writeJsonFile = async <T>(path: string, data: T): Promise<void> => {
|
||||||
|
try {
|
||||||
|
const jsonString = JSON.stringify(data, null, 2);
|
||||||
|
await writeTextFile(path, jsonString);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error writing file ${path}: ${error}`);
|
||||||
|
throw new Error(`Error writing file ${path}: ${error}`);
|
||||||
|
}
|
||||||
|
};
|
22
src/lib/utils/toml.ts
Normal file
22
src/lib/utils/toml.ts
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { readTextFile, writeTextFile } from "@tauri-apps/api/fs";
|
||||||
|
import { parse, stringify } from "smol-toml";
|
||||||
|
|
||||||
|
export const readTomlFile = async <T>(path: string): Promise<T | null> => {
|
||||||
|
try {
|
||||||
|
const contents = await readTextFile(path);
|
||||||
|
return parse(contents) as T;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Failed to read JSON file ${path}: ${error}`);
|
||||||
|
throw new Error(`Failed to read JSON file ${path}: ${error}`);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const writeTomlFile = async <T>(path: string, data: T): Promise<void> => {
|
||||||
|
try {
|
||||||
|
const tomlString = stringify(data);
|
||||||
|
await writeTextFile(path, tomlString);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error writing file ${path}: ${error}`);
|
||||||
|
throw new Error(`Error writing file ${path}: ${error}`);
|
||||||
|
}
|
||||||
|
};
|
|
@ -6,6 +6,7 @@ import { Initialization } from "../components/Generic/Initialization";
|
||||||
import { UserThemeProvider } from "../contexts/ThemeContext";
|
import { UserThemeProvider } from "../contexts/ThemeContext";
|
||||||
import createEmotionCache from "../lib/createEmotionCache";
|
import createEmotionCache from "../lib/createEmotionCache";
|
||||||
import "../styles/global.css";
|
import "../styles/global.css";
|
||||||
|
import { SettingsProvider } from "../contexts/SettingsContext";
|
||||||
|
|
||||||
// Client-side cache, shared for the whole session of the user in the browser.
|
// Client-side cache, shared for the whole session of the user in the browser.
|
||||||
const clientSideEmotionCache = createEmotionCache();
|
const clientSideEmotionCache = createEmotionCache();
|
||||||
|
@ -20,14 +21,19 @@ export default function MyApp(props: MyAppProps) {
|
||||||
<CacheProvider value={emotionCache}>
|
<CacheProvider value={emotionCache}>
|
||||||
<Head>
|
<Head>
|
||||||
<title>Stort</title>
|
<title>Stort</title>
|
||||||
<meta name="viewport" content="initial-scale=1, width=device-width" />
|
<meta
|
||||||
|
name='viewport'
|
||||||
|
content='initial-scale=1, width=device-width'
|
||||||
|
/>
|
||||||
</Head>
|
</Head>
|
||||||
|
<SettingsProvider>
|
||||||
<UserThemeProvider>
|
<UserThemeProvider>
|
||||||
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
|
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */}
|
||||||
<Initialization />
|
<Initialization />
|
||||||
<CssBaseline />
|
<CssBaseline />
|
||||||
<Component {...pageProps} />
|
<Component {...pageProps} />
|
||||||
</UserThemeProvider>
|
</UserThemeProvider>
|
||||||
|
</SettingsProvider>
|
||||||
</CacheProvider>
|
</CacheProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
"use client";
|
|
||||||
|
|
||||||
import { BugReport } from "@mui/icons-material";
|
import { BugReport } from "@mui/icons-material";
|
||||||
import { Box, Button, IconButton, TextField, Typography } from "@mui/material";
|
import { Box, Button, IconButton, TextField, Typography } from "@mui/material";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { usePathStore } from "../lib/store/zustand/path";
|
import { useSettings } from "../contexts/SettingsContext";
|
||||||
|
import { testing } from "../lib/testing";
|
||||||
|
|
||||||
export default function Testing() {
|
export default function Testing() {
|
||||||
|
// contexts
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const { settings, settingsLoading, updateSettings, resetSettings } = useSettings();
|
||||||
|
|
||||||
const paths = usePathStore((state) => state.paths);
|
// states
|
||||||
|
|
||||||
const [text, setText] = useState("");
|
const [text, setText] = useState("");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -23,11 +23,43 @@ export default function Testing() {
|
||||||
<BugReport />
|
<BugReport />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<Button
|
<Button
|
||||||
onClick={async () => {
|
onClick={() => {
|
||||||
console.log(paths);
|
resetSettings();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Button
|
reset settings
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
updateSettings({
|
||||||
|
display: {
|
||||||
|
dark_mode: false as boolean,
|
||||||
|
accent_color: "#8ab4f8" as string,
|
||||||
|
transition_duration: 200 as number,
|
||||||
|
radius: 8 as number,
|
||||||
|
window_height: 60 as number,
|
||||||
|
window_width: 400 as number,
|
||||||
|
font_family: "monospace" as string,
|
||||||
|
font_scaling: 100,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
update settings
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
console.log(settings);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
log settings
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
console.log(testing());
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
testing
|
||||||
</Button>
|
</Button>
|
||||||
<Typography>{text}</Typography>
|
<Typography>{text}</Typography>
|
||||||
<TextField rows={10} />
|
<TextField rows={10} />
|
||||||
|
|
Loading…
Reference in a new issue