This script allows for choosing the Space in Arc Browser and reuse the same theme for every other Space.
I've created it because I dislike the default theme in Arc but still want to have the same one for every Space I have.
Note: This script modifies Arc Browser's
StorableSidebar.json
file. Use at your peril.
Open arc-default-theme in Script Kit
// Name: arc-default-theme// Description: Pick an Arc Browser's Space and set its theme for all the other Arc Spaces. Tested with Arc v1.10.1.// Note: This script modifies Arc Browser's `StorableSidebar.json` file. Use at your peril.import "@johnlindquist/kit";import { readdir, readFile, writeFile } from "node:fs/promises";import { homedir } from "node:os";import { join } from "node:path";const { rimraf } = await npm("rimraf");const psList = await npm("ps-list");const ARC_LIBRARY_PATH = join(homedir(),"Library","Application Support","Arc");async function listSidebarCacheFiles(): Promise<string[]> {const arcFileNames = await readdir(ARC_LIBRARY_PATH);return arcFileNames.filter((file) =>file.startsWith("StorableSidebar") && file !== "StorableSidebar.json") as string[];}async function removeSidebarCacheFiles(): Promise<void> {const sidebarCacheFileNames = await listSidebarCacheFiles();for (const fileName of sidebarCacheFileNames) {try {await rimraf(join(ARC_LIBRARY_PATH, fileName));} catch (err) {console.error(err);}}}async function findArcProcess(): Promise<{name: string;pid: number;}> {const processes = await psList();const arcProcess = processes.find((process) => process.name === "Arc");return arcProcess;}async function killArcProcess(): Promise<void> {const arcProcess = await findArcProcess();if (arcProcess) {process.kill(arcProcess.pid);}}async function readStorableSidebarJson(): Promise<StorableSidebarJson> {const storableSidebarJson = await readFile(join(ARC_LIBRARY_PATH, "StorableSidebar.json"),"utf-8");return JSON.parse(storableSidebarJson) as StorableSidebarJson;}async function getSourceSpaceTheme(json: StorableSidebarJson,sourceSpaceName: string): Promise<WindowTheme> {const sourceSpace: SpaceModel = json.sidebarSyncState.spaceModels.find((spaceModel) =>typeof spaceModel !== "string" &&spaceModel.value?.title === sourceSpaceName) as SpaceModel;return sourceSpace.value?.customInfo.windowTheme;}async function getTargetSpaces(json: StorableSidebarJson,originalSpaceName: string): Promise<SpaceData[]> {const itemsContainer = json.sidebar.containers.find((container) =>Object.hasOwnProperty.call(container, "items"));if (itemsContainer) {const spaces = itemsContainer.spaces as (string | SpaceData)[];return spaces.filter((space) => typeof space !== "string" && space.title !== originalSpaceName) as SpaceData[];}}async function getTargetSpacesSynced(json: StorableSidebarJson,originalSpaceName: string): Promise<SpaceModel[]> {return json.sidebarSyncState.spaceModels.filter((spaceModel) =>typeof spaceModel !== "string" &&spaceModel.value?.title !== originalSpaceName) as SpaceModel[];}async function writeStorableSidebarJson(json: StorableSidebarJson): Promise<void> {await removeSidebarCacheFiles();await writeFile(join(ARC_LIBRARY_PATH, "StorableSidebar.json"),JSON.stringify(json, null, 2));}async function mapJsonToSpaceNames(json: StorableSidebarJson): Promise<string[]> {const itemsContainer = json.sidebar.containers.find((container) =>Object.hasOwnProperty.call(container, "spaces"));if (itemsContainer) {const spaces = itemsContainer.spaces as (string | SpaceData)[];return (spaces.filter((space) => typeof space !== "string") as SpaceData[]).map((space) => space.title);}}async function main(): Promise<void> {await killArcProcess();await removeSidebarCacheFiles();const storableSidebarJson: StorableSidebarJson =await readStorableSidebarJson();const spaceNames = await mapJsonToSpaceNames(storableSidebarJson);const sourceSpaceName = await arg("Which Space theme you want to use for all the others?",spaceNames);const sourceSpaceTheme: WindowTheme = await getSourceSpaceTheme(storableSidebarJson,sourceSpaceName);const targetSpaces: SpaceData[] = await getTargetSpaces(storableSidebarJson,sourceSpaceName);for (const targetSpace of targetSpaces) {targetSpace.customInfo.windowTheme = sourceSpaceTheme;}const targetSpacesSynced: SpaceModel[] = await getTargetSpacesSynced(storableSidebarJson,sourceSpaceName);for (const targetSpace of targetSpacesSynced) {targetSpace.value.customInfo.windowTheme = sourceSpaceTheme;}writeStorableSidebarJson(storableSidebarJson);}await main();// Interfaces ------------------------------------------------------------------interface Color {colorSpace: string;red: number;alpha: number;blue: number;green: number;}interface ColorSettings {[key: string]: Color;}interface WindowTheme {semanticColorPalette: {appearanceBased: {light: ColorSettings;dark: ColorSettings;};};[key: string]: unknown;}interface CustomInfo {windowTheme: WindowTheme;[key: string]: unknown;}interface SpaceData {title: string;customInfo: CustomInfo;id: string;[key: string]: unknown;}interface SpaceModel {value: SpaceData;[key: string]: unknown;}interface SidebarSyncState {spaceModels: (string | SpaceModel)[];}interface Sidebar {containers: Array<| {spaces: (SpaceData | string)[];}| {[key: string]: unknown;}>;}interface StorableSidebarJson {sidebarSyncState: SidebarSyncState;sidebar: Sidebar;[key: string]: unknown;}