diff --git a/src/background/index.ts b/src/background/index.ts
index f6e8416..41a5349 100644
--- a/src/background/index.ts
+++ b/src/background/index.ts
@@ -1,10 +1,11 @@
-import { storage } from "../storage";
+import { get } from "svelte/store";
+import { count } from "../storage";
// Background service workers
// https://developer.chrome.com/docs/extensions/mv3/service_workers/
chrome.runtime.onInstalled.addListener(() => {
- storage.get().then(console.log);
+ console.log(get(count));
});
// NOTE: If you want to toggle the side panel from the extension's action button,
diff --git a/src/components/Options.svelte b/src/components/Options.svelte
index de2b5d6..47e2c17 100644
--- a/src/components/Options.svelte
+++ b/src/components/Options.svelte
@@ -1,35 +1,19 @@
-
Current count: {count}
+
Current count: {$count}
-
-
-
- {#if successMessage}{successMessage}{/if}
+
+
@@ -52,9 +36,4 @@
button:focus {
background-color: #27ae60;
}
-
- .success {
- color: #2ecc71;
- font-weight: bold;
- }
diff --git a/src/components/Overlay.svelte b/src/components/Overlay.svelte
index 3b0f287..b2dbbb8 100644
--- a/src/components/Overlay.svelte
+++ b/src/components/Overlay.svelte
@@ -1,13 +1,6 @@
diff --git a/src/content/index.ts b/src/content/index.ts
index b3e194d..5dfc43d 100644
--- a/src/content/index.ts
+++ b/src/content/index.ts
@@ -1,5 +1,6 @@
+import { get } from "svelte/store";
import Overlay from "../components/Overlay.svelte";
-import { storage } from "../storage";
+import { count } from "../storage";
// Content scripts
// https://developer.chrome.com/docs/extensions/mv3/content_scripts/
@@ -8,7 +9,7 @@ import { storage } from "../storage";
import "./styles.css";
// Some JS on the page
-storage.get().then(console.log);
+console.log(`CONTENT: ${get(count)}`);
// Some svelte component on the page
new Overlay({ target: document.body });
diff --git a/src/options/index.ts b/src/options/index.ts
index 2d2a7c1..de5fb02 100644
--- a/src/options/index.ts
+++ b/src/options/index.ts
@@ -1,5 +1,5 @@
import Options from "../components/Options.svelte";
-import { storage } from "../storage";
+import { count } from "../storage";
// Options
// https://developer.chrome.com/docs/extensions/mv3/options/
@@ -8,11 +8,9 @@ function render() {
const target = document.getElementById("app");
if (target) {
- storage.get().then(({ count }) => {
- new Options({
- target,
- props: { count },
- });
+ new Options({
+ target,
+ props: { count },
});
}
}
diff --git a/src/popup/index.ts b/src/popup/index.ts
index 4a00ba0..d9d125a 100644
--- a/src/popup/index.ts
+++ b/src/popup/index.ts
@@ -1,5 +1,5 @@
import Options from "../components/Options.svelte";
-import { storage } from "../storage";
+import { count } from "../storage";
// Action popup
// https://developer.chrome.com/docs/extensions/reference/action/
@@ -8,11 +8,9 @@ function render() {
const target = document.getElementById("app");
if (target) {
- storage.get().then(({ count }) => {
- new Options({
- target,
- props: { count },
- });
+ new Options({
+ target,
+ props: { count },
});
}
}
diff --git a/src/sidepanel/index.ts b/src/sidepanel/index.ts
index 1fffe4e..f8df213 100644
--- a/src/sidepanel/index.ts
+++ b/src/sidepanel/index.ts
@@ -1,5 +1,5 @@
import Options from "../components/Options.svelte";
-import { storage } from "../storage";
+import { count } from "../storage";
// Side panel
// https://developer.chrome.com/docs/extensions/reference/sidePanel/
@@ -8,11 +8,9 @@ function render() {
const target = document.getElementById("app");
if (target) {
- storage.get().then(({ count }) => {
- new Options({
- target,
- props: { count },
- });
+ new Options({
+ target,
+ props: { count },
});
}
}
diff --git a/src/storage.ts b/src/storage.ts
index 015c59d..5265f4c 100644
--- a/src/storage.ts
+++ b/src/storage.ts
@@ -1,13 +1,58 @@
-type IStorage = {
- count: number;
-};
-
-const defaultStorage: IStorage = {
- count: 0,
-};
-
-export const storage = {
- get: (): Promise =>
- chrome.storage.sync.get(defaultStorage) as Promise,
- set: (value: IStorage): Promise => chrome.storage.sync.set(value),
-};
+import { writable, type Writable } from 'svelte/store';
+
+/**
+ * Creates a persistent Svelte store backed by Chrome's sync storage.
+ * @template T The type of the store's value
+ * @param key The key to use in Chrome's storage
+ * @param initialValue The initial value of the store
+ * @returns A writable Svelte store
+ */
+export function persistentStore(key: string, initialValue: T): Writable {
+ const store = writable(initialValue);
+ // Ensure each value is updated exactly once in store and in chrome storage
+ let storeValueQueue: T[] = [];
+ let chromeValueQueue: T[] = [];
+
+ function watchStore() {
+ store.subscribe((value) => {
+ if (chromeValueQueue.length > 0 && value === chromeValueQueue[0]) {
+ chromeValueQueue.shift();
+ return;
+ }
+
+ storeValueQueue.push(value);
+ chrome.storage.sync.set({ [key]: value });
+ });
+ }
+
+ function watchChrome() {
+ chrome.storage.sync.onChanged.addListener((changes) => {
+ if (!(Object.hasOwn(changes, key))) return;
+
+ const value = changes[key].newValue as T;
+ if (storeValueQueue.length > 0 && value === storeValueQueue[0]) {
+ storeValueQueue.shift();
+ return;
+ }
+
+ chromeValueQueue.push(value);
+ store.set(value);
+ });
+ }
+
+ // Initialize the store with the value from Chrome storage
+ chrome.storage.sync.get(key).then((result) => {
+ let value = Object.hasOwn(result, key) ? result[key] : initialValue;
+ if (!Object.hasOwn(result, key)) {
+ console.log(`Persistent store: couldn't find key [${key}] in chrome storage. Default to initial value [${initialValue}]`)
+ }
+ chromeValueQueue.push(value);
+ store.set(value);
+ watchStore();
+ watchChrome();
+ });
+
+ return store;
+}
+
+export const count = persistentStore("count", 10);
\ No newline at end of file