Web Editor
A collection of 2 actions bundled together.
Code Snippet
1// ==========================================
2// ACTION GROUP (2 Actions)
3// ==========================================
4
5// ------------------------------------------
6// Action: Web Editor/Editor
7// Description: The UI for web editor
8// ------------------------------------------
9
10const currentTab = await browser.tabs.getCurrent();
11let domain = new URL(currentTab.url).hostname;
12const parts = domain.split('.');
13if (parts.length > 2) {
14 if (parts[parts.length-2].length <= 3 && parts[parts.length-1].length <= 3) {
15 domain = parts.slice(-3).join('.');
16 } else {
17 domain = parts.slice(-2).join('.');
18 }
19}
20const cssNoteTitle = `tee-css://${domain}`;
21
22const notesList = await notes.list();
23const existingCssNote = notesList.find(n => n.title === cssNoteTitle);
24
25// Handle legacy JSON format if present
26let savedContent = existingCssNote ? existingCssNote.content : "";
27try {
28 const jsonMap = JSON.parse(savedContent);
29 savedContent = `/* Converted from previous format */\n`;
30 for (const [selector, css] of Object.entries(jsonMap)) {
31 savedContent += `${selector} {\n ${css}\n}\n\n`;
32 }
33} catch(e) {}
34
35const initialCss = savedContent || `/* Custom CSS for ${domain} */\n\n`;
36
37let cssRuleId = null;
38let finalCss = initialCss;
39
40// If we already have saved CSS, preview it immediately so the page reflects the note!
41if (initialCss.trim()) {
42 cssRuleId = await page.injectCSS(initialCss);
43}
44
45await widget.show([
46 { type: "text", text: `🎨 Theme: ${domain}`, size: "lg", weight: "bold" },
47 { type: "textarea", id: "editor-css", value: initialCss, rows: 14, placeholder: "e.g.\n.header { display: none !important; }\nh1 { color: red !important; }" },
48 { type: "button", id: "preview", text: "Preview Changes", variant: "ghost" },
49 { type: "button", id: "save", text: "Save Stylesheet", variant: "primary" }
50], "bottom-right");
51
52while (true) {
53 const ev = await Promise.race([
54 widget.waitForEvent("preview", "click").then(data => ({ action: "preview", data })),
55 widget.waitForEvent("save", "click").then(data => ({ action: "save", data })),
56 widget.waitForEvent("__widget_closed__", "click").then(() => ({ action: "close" }))
57 ]);
58
59 if (ev.action === "close") {
60 if (cssRuleId) await page.removeCSS(cssRuleId);
61 return;
62 }
63
64 // Retrieve whatever the user has typed so far
65 const currentCss = ev.data ? (ev.data["editor-css"] !== undefined ? ev.data["editor-css"] : initialCss) : initialCss;
66 finalCss = currentCss;
67
68 if (ev.action === "preview" || ev.action === "save") {
69 if (cssRuleId) await page.removeCSS(cssRuleId);
70 if (currentCss) {
71 cssRuleId = await page.injectCSS(currentCss);
72 }
73 }
74
75 if (ev.action === "save") break;
76}
77
78await widget.hide();
79await spinner.show("Saving stylesheet...");
80
81if (finalCss.trim()) {
82 if (existingCssNote) await notes.update(existingCssNote.id, { content: finalCss });
83 else await notes.create({ title: cssNoteTitle, content: finalCss, url: currentTab.url });
84} else if (existingCssNote) {
85 // If the user completely wiped the stylesheet, save the empty state
86 await notes.update(existingCssNote.id, { content: "" });
87}
88
89await spinner.hide();
90notify.show(`Saved stylesheet for ${domain}!`, "success");
91
92
93
94// ------------------------------------------
95// Action: Web Editor/Autoloader
96// Description: The autoloader that applies CSS to websites
97// ------------------------------------------
98
99const currentTab = await browser.tabs.getCurrent();
100if (!currentTab || !currentTab.url) return;
101
102let domain = new URL(currentTab.url).hostname;
103const parts = domain.split('.');
104if (parts.length > 2) {
105 if (parts[parts.length-2].length <= 3 && parts[parts.length-1].length <= 3) {
106 domain = parts.slice(-3).join('.');
107 } else {
108 domain = parts.slice(-2).join('.');
109 }
110}
111
112const notesList = await notes.list();
113
114const cssNote = notesList.find(n => n.title === `tee-css://${domain}`);
115if (cssNote && cssNote.content) {
116 let finalCssToInject = cssNote.content;
117 try {
118 const jsonMap = JSON.parse(finalCssToInject);
119 finalCssToInject = "";
120 for (const [selector, css] of Object.entries(jsonMap)) {
121 finalCssToInject += `${selector} { ${css} }\n`;
122 }
123 } catch(e) {}
124
125 await page.injectCSS(finalCssToInject);
126}
127Submitted on 7/11/2026