Radish alpha
r
rad:z4D5UCArafTzTQpDZNQRuqswh3ury
Radicle desktop app
Radicle
Git
Convert any `localStorage` usage to `useLocalStorage`
Open did:key:z6MkkfM3...sVz5 opened 11 months ago

Changes also the value for one-column-layout-enabled from one-column and two-column to true or false which make more sense.

Rename one-column-layout-enabled localStorage key to camelCase

Add an exclude pattern for typescript bindings to npm run format

14 files changed +84 -128 25c6ab32 b2861012
modified package.json
@@ -16,7 +16,7 @@
    "check-rs": "scripts/check-rs",
    "test:unit": "TZ='UTC' vitest run",
    "test:e2e": "TZ='UTC' playwright test",
-
    "format": "npx prettier '**/*.@(ts|js|svelte|json|css|html|yml)' --write",
+
    "format": "npx prettier '**/*.@(ts|js|svelte|json|css|html|yml)' '!crates/radicle-types/bindings/**' --write",
    "generate-types": "cargo test --manifest-path ./crates/radicle-types/Cargo.toml",
    "tauri": "npx tauri"
  },
modified src/App.svelte
@@ -80,10 +80,12 @@
  $effect(() =>
    document.documentElement.style.setProperty(
      "--font-size",
-
      `${fontSettings.size}px`,
+
      `${fontSettings.value.size}px`,
    ),
  );
-
  $effect(() => document.documentElement.setAttribute("data-theme", $theme));
+
  $effect(() =>
+
    document.documentElement.setAttribute("data-theme", theme.value),
+
  );
</script>

<svelte:document
modified src/components/AnnounceSwitch.svelte
@@ -1,32 +1,16 @@
<script lang="ts" module>
-
  export const announce = writable<boolean>(loadAnnounce());
+
  import useLocalStorage from "@app/lib/useLocalStorage.svelte";
+
  import { boolean } from "zod";

-
  function loadAnnounce(): boolean {
-
    const storedAnnounce = localStorage
-
      ? localStorage.getItem("announce")
-
      : null;
-

-
    if (storedAnnounce === null) {
-
      return true;
-
    } else {
-
      return storedAnnounce === "true";
-
    }
-
  }
-

-
  export function storeAnnounce(newAnnounce: boolean): void {
-
    announce.set(newAnnounce);
-
    if (localStorage) {
-
      localStorage.setItem("announce", newAnnounce.toString());
-
    } else {
-
      console.warn(
-
        "localStorage isn't available, not able to persist the selected announce preference without it.",
-
      );
-
    }
-
  }
+
  export const announce = useLocalStorage(
+
    "announce",
+
    boolean(),
+
    true,
+
    !window.localStorage,
+
  );
</script>

<script lang="ts">
-
  import { writable } from "svelte/store";
  import Button from "./Button.svelte";
</script>

@@ -41,9 +25,9 @@
  <Button
    flatRight
    variant="ghost"
-
    active={$announce}
+
    active={announce.value}
    onclick={() => {
-
      storeAnnounce(true);
+
      announce.value = true;
    }}>
    Right away
  </Button>
@@ -51,9 +35,9 @@
  <Button
    flatLeft
    variant="ghost"
-
    active={!$announce}
+
    active={!announce.value}
    onclick={() => {
-
      storeAnnounce(false);
+
      announce.value = false;
    }}>
    Periodically
  </Button>
modified src/components/FontSizeSwitch.svelte
@@ -23,7 +23,7 @@
  </Button>

  <Button flatRight flatLeft active variant="ghost">
-
    {fontSettings.size}
+
    {fontSettings.value.size}
  </Button>

  <Button
modified src/components/Review.svelte
@@ -133,7 +133,7 @@
          verdict,
          labels,
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Editing review failed: ", error);
@@ -161,7 +161,7 @@
          replyTo,
          location,
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Creating comment failed", error);
@@ -182,7 +182,7 @@
          review: review.id,
          embeds,
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Editing comment failed: ", error);
@@ -210,7 +210,7 @@
            ({ did }) => publicKeyFromDid(did) === publicKey,
          ),
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Editing comment reactions failed", error);
@@ -231,7 +231,7 @@
          comment: commentId,
          review: review.id,
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Updating comment status failed: ", error);
modified src/components/Reviews.svelte
@@ -64,7 +64,7 @@
          summary: "",
          labels: [],
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Creating a review failed: ", error);
modified src/components/Revision.svelte
@@ -74,7 +74,7 @@
          description,
          embeds,
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Editing revision failed: ", error);
@@ -101,7 +101,7 @@
            ({ did }) => publicKeyFromDid(did) === publicKey,
          ),
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Editing reactions failed", error);
@@ -119,7 +119,7 @@
      await invoke("create_patch_comment", {
        rid: rid,
        new: { id: patchId, body, embeds, replyTo, revision: revision.id },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Creating comment failed", error);
@@ -140,7 +140,7 @@
          revision: revision.id,
          embeds,
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Editing comment failed: ", error);
@@ -168,7 +168,7 @@
            ({ did }) => publicKeyFromDid(did) === publicKey,
          ),
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Editing comment reactions failed", error);
modified src/components/Sidebar.svelte
@@ -1,7 +1,7 @@
<script lang="ts">
  import * as router from "@app/lib/router";

-
  import { storeLayout, getLayout } from "@app/views/repo/Layout.svelte";
+
  import { oneColumnLayout, storeLayout } from "@app/views/repo/Layout.svelte";

  import Icon from "@app/components/Icon.svelte";
  import Settings from "@app/components/Settings.svelte";
@@ -116,13 +116,13 @@
    styleHeight="2.5rem"
    variant="ghost"
    onclick={() => {
-
      if (getLayout()) {
+
      if (oneColumnLayout.value) {
        storeLayout("two-column");
      } else {
        storeLayout("one-column");
      }
    }}>
-
    {#if getLayout()}
+
    {#if oneColumnLayout.value}
      <Icon name="expand-panel" />
    {:else}
      <Icon name="collapse-panel" />
modified src/components/ThemeSwitch.svelte
@@ -1,34 +1,18 @@
<script lang="ts" module>
-
  type Theme = "dark" | "light";
-

-
  export const theme = writable<Theme>(loadTheme());
-

-
  function loadTheme(): Theme {
-
    const { matches } = window.matchMedia("(prefers-color-scheme: dark)");
-
    const storedTheme = localStorage ? localStorage.getItem("theme") : null;
-

-
    if (storedTheme === null) {
-
      return matches ? "dark" : "light";
-
    } else {
-
      return storedTheme as Theme;
-
    }
-
  }
-

-
  export function storeTheme(newTheme: Theme): void {
-
    theme.set(newTheme);
-
    if (localStorage) {
-
      localStorage.setItem("theme", newTheme);
-
    } else {
-
      console.warn(
-
        "localStorage isn't available, not able to persist the selected theme without it.",
-
      );
-
    }
-
  }
+
  import useLocalStorage from "@app/lib/useLocalStorage.svelte";
+
  import { literal, union } from "zod";
+

+
  export const theme = useLocalStorage(
+
    "theme",
+
    union([literal("dark"), literal("light")]),
+
    window.matchMedia("(prefers-color-scheme: dark)").matches
+
      ? "dark"
+
      : "light",
+
    !window.localStorage,
+
  );
</script>

<script lang="ts">
-
  import { writable } from "svelte/store";
-

  import Icon from "./Icon.svelte";
  import Button from "./Button.svelte";
</script>
@@ -43,10 +27,10 @@
<div class="container">
  <Button
    flatRight
-
    active={$theme === "dark"}
+
    active={theme.value === "dark"}
    variant="ghost"
    onclick={() => {
-
      storeTheme("dark");
+
      theme.value = "dark";
    }}>
    <Icon name="moon" />
    Dark
@@ -55,9 +39,9 @@
  <Button
    flatLeft
    variant="ghost"
-
    active={$theme === "light"}
+
    active={theme.value === "light"}
    onclick={() => {
-
      storeTheme("light");
+
      theme.value = "light";
    }}>
    <Icon name="sun" />
    Light
modified src/lib/appearance.svelte.ts
@@ -1,35 +1,28 @@
-
export const fontSettings = $state({ size: loadFontSize() });
+
import { number, object } from "zod";
+
import useLocalStorage from "./useLocalStorage.svelte";
+

+
export const fontSettings = useLocalStorage(
+
  "fontSettings",
+
  object({ size: number() }),
+
  { size: 16 },
+
  !window.localStorage,
+
);
const step = 2;
const minFontSize = 14;
const maxFontSize = 24;

export function increaseFontSize() {
-
  if (fontSettings.size + step <= maxFontSize) {
-
    setFontSize(fontSettings.size + step);
+
  if (fontSettings.value.size + step <= maxFontSize) {
+
    fontSettings.value = { size: fontSettings.value.size + step };
  }
}

export function decreaseFontSize() {
-
  if (fontSettings.size - step >= minFontSize) {
-
    setFontSize(fontSettings.size - step);
+
  if (fontSettings.value.size - step >= minFontSize) {
+
    fontSettings.value = { size: fontSettings.value.size - step };
  }
}

export function resetFontSize() {
-
  setFontSize(16);
-
}
-

-
function loadFontSize(): number {
-
  const storedFontSize = localStorage ? localStorage.getItem("fontSize") : "16";
-

-
  if (storedFontSize === null) {
-
    return 16;
-
  } else {
-
    return parseInt(storedFontSize);
-
  }
-
}
-

-
function setFontSize(size: number) {
-
  fontSettings.size = size;
-
  localStorage.setItem("fontSize", size.toString());
+
  fontSettings.value = { size: 16 };
}
modified src/views/repo/CreateIssue.svelte
@@ -74,7 +74,7 @@
        assignees: $state.snapshot(assignees.map(a => a.did)),
        embeds,
      },
-
      opts: { announce: $nodeRunning && $announce },
+
      opts: { announce: $nodeRunning && announce.value },
    });
  }
</script>
modified src/views/repo/Issue.svelte
@@ -102,7 +102,7 @@
          type: "label",
          labels,
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Editing labels failed", error);
@@ -122,7 +122,7 @@
          type: "assign",
          assignees,
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Editing assignees failed", error);
@@ -158,7 +158,7 @@
      await invoke("create_issue_comment", {
        rid: repo.rid,
        new: { id: issue.id, body, embeds, replyTo },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
      // Update second column issue comment count without reloading the whole
      // issue list.
@@ -184,7 +184,7 @@
          body,
          embeds,
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Issue comment editing failed: ", error);
@@ -203,7 +203,7 @@
          id: issue.id,
          title: newTitle,
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
      // Update second column issue title without reloading the whole issue list.
      const issueIndex = issues.findIndex(i => i.id === issue.id);
@@ -235,7 +235,7 @@
            ({ did }) => publicKeyFromDid(did) === publicKey,
          ),
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Editing reactions failed", error);
@@ -253,7 +253,7 @@
          type: "lifecycle",
          state,
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
      // Update second column issue icon without reloading the whole issue list.
      const issueIndex = issues.findIndex(i => i.id === issue.id);
modified src/views/repo/Layout.svelte
@@ -1,35 +1,28 @@
<script lang="ts" module>
  type LayoutState = "one-column" | "two-column";

-
  const LAYOUT_KEY = "one-column-layout-enabled";
-

-
  let oneColumnLayout = $state(
-
    localStorage ? localStorage.getItem(LAYOUT_KEY) === "one-column" : false,
+
  import { boolean } from "zod";
+
  import useLocalStorage from "@app/lib/useLocalStorage.svelte";
+

+
  export const oneColumnLayout = useLocalStorage(
+
    "oneColumnLayoutEnabled",
+
    boolean(),
+
    false,
+
    !window.localStorage,
  );

-
  export function getLayout() {
-
    return oneColumnLayout;
-
  }
-

  export function storeLayout(newValue: LayoutState): void {
-
    oneColumnLayout = newValue === "one-column";
-
    if (localStorage) {
-
      localStorage.setItem(LAYOUT_KEY, newValue);
-
    } else {
-
      console.warn(
-
        "localStorage isn't available, not able to persist the selected layout settings without it.",
-
      );
-
    }
+
    oneColumnLayout.value = newValue === "one-column";
  }
</script>

<script lang="ts">
  import type { Snippet } from "svelte";
+
  import type { Config } from "@bindings/config/Config";

  import { onMount } from "svelte";

  import Header from "@app/components/Header.svelte";
-
  import type { Config } from "@bindings/config/Config";

  interface Props {
    children: Snippet;
@@ -150,7 +143,7 @@
    class="secondColumn"
    style:padding-left={hideSidebar ? "1rem" : "0"}
    bind:this={secondColumnContainer}
-
    style:display={oneColumnLayout && !hideSidebar ? "none" : undefined}
+
    style:display={oneColumnLayout.value && !hideSidebar ? "none" : undefined}
    style:overflow={styleSecondColumnOverflow}>
    {@render secondColumn()}
  </div>
modified src/views/repo/Patch.svelte
@@ -124,7 +124,7 @@
          title: newTitle,
          target: "delegates",
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Editing title failed: ", error);
@@ -143,7 +143,7 @@
          type: "label",
          labels,
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Editing labels failed", error);
@@ -163,7 +163,7 @@
          type: "assign",
          assignees,
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Editing assignees failed", error);
@@ -182,7 +182,7 @@
          type: "lifecycle",
          state: newState,
        },
-
        opts: { announce: $nodeRunning && $announce },
+
        opts: { announce: $nodeRunning && announce.value },
      });
    } catch (error) {
      console.error("Changing state failed", error);