-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add context menu generation and alert content script
Closes #9
- Loading branch information
Showing
12 changed files
with
427 additions
and
98 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
import type { AliasSettings } from "~utils/state"; | ||
|
||
import { Storage } from "@plasmohq/storage"; | ||
|
||
import { detectLocale, i18n } from "~i18n/i18n-util"; | ||
import { loadLocale } from "~i18n/i18n-util.sync"; | ||
import { CloudflareApiClient } from "~lib/cloudflare/api"; | ||
import { Alias } from "~utils/alias"; | ||
import { detectBrowserLocale, sendTabMessage } from "~utils/background"; | ||
import { StorageKeys } from "~utils/state"; | ||
|
||
const storage = new Storage({ | ||
area: "local", | ||
}); | ||
|
||
const locale = detectLocale(detectBrowserLocale); | ||
loadLocale(locale); | ||
const LL = i18n()[locale]; | ||
|
||
export async function generateAliasInBackground(hostname: string): Promise<Alias> { | ||
const apiToken = await storage.get<string>(StorageKeys.ApiToken); | ||
const zoneId = await storage.get<string>(StorageKeys.ZoneId); | ||
const aliasSettings = await storage.get<AliasSettings>(StorageKeys.AliasSettings); | ||
|
||
if (!apiToken) { | ||
throw new Error(LL.BG_ERROR_NOT_LOGGED_IN()); | ||
} | ||
if (!zoneId) { | ||
throw new Error(LL.BG_ERROR_NO_DOMAIN()); | ||
} | ||
if (!aliasSettings?.destination) { | ||
throw new Error(LL.BG_ERROR_NO_DESTINATION()); | ||
} | ||
if (aliasSettings.format === "custom" || aliasSettings.prefixFormat === "custom") { | ||
throw new Error(LL.BG_ERROR_CUSTOM()); | ||
} | ||
|
||
const apiClient = new CloudflareApiClient(apiToken); | ||
|
||
const zones = await apiClient.getZones(); | ||
const zone = zones.success ? zones.result.find((z) => z.id === zoneId) : undefined; | ||
|
||
if (!zone) { | ||
throw new Error(LL.BG_ERROR_INVALID_DOMAIN()); | ||
} | ||
|
||
const alias = Alias.fromOptions( | ||
{ | ||
...aliasSettings, | ||
hostname, | ||
}, | ||
zone.name, | ||
aliasSettings.destination, | ||
hostname, | ||
); | ||
|
||
const result = await apiClient.createEmailRule(zoneId, alias.toEmailRule()); | ||
|
||
if (result.success) { | ||
console.log("Created new alias in background:", alias.address); | ||
return alias; | ||
} else { | ||
throw new Error(result.errors[0].message); | ||
} | ||
} | ||
|
||
chrome.contextMenus.onClicked.addListener(async (info, tab) => { | ||
console.debug("Context menu click:", info, tab); | ||
|
||
if (info.menuItemId !== "mailflare-generate") return; | ||
|
||
const loadingAlertId = Date.now(); | ||
await sendTabMessage(tab?.id, { | ||
command: "showAlert", | ||
alert: { | ||
id: loadingAlertId, | ||
message: LL.BG_ALERT_LOADING(), | ||
isLoading: true, | ||
}, | ||
}); | ||
|
||
try { | ||
const alias = await generateAliasInBackground(new URL(info.pageUrl).hostname); | ||
await sendTabMessage(tab?.id, { | ||
command: "showAlert", | ||
alert: { | ||
id: Date.now(), | ||
type: "success", | ||
message: LL.BG_ALERT_CREATED({ alias: alias.address }), | ||
timeout: 5000, | ||
}, | ||
}); | ||
await sendTabMessage(tab?.id, { | ||
command: "copyText", | ||
text: alias.toString(), | ||
}); | ||
} catch (error: any) { | ||
await sendTabMessage(tab?.id, { | ||
command: "showAlert", | ||
alert: { id: Date.now(), type: "error", message: error.message }, | ||
}); | ||
} finally { | ||
await sendTabMessage(tab?.id, { | ||
command: "dismissAlert", | ||
id: loadingAlertId, | ||
}); | ||
} | ||
}); | ||
|
||
chrome.runtime.onInstalled.addListener(function () { | ||
chrome.contextMenus.create({ | ||
title: LL.CONTEXT_MENU_ENTRY_TEXT(), | ||
contexts: ["page", "editable"], | ||
id: "mailflare-generate", | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
// noinspection JSUnusedGlobalSymbols | ||
|
||
import type { ContentScriptAlert, TabMessage } from "~utils/background"; | ||
import type { PlasmoCSConfig, PlasmoGetStyle } from "plasmo"; | ||
|
||
import { IconX } from "@tabler/icons-react"; | ||
import { useEffect, useState } from "react"; | ||
import cssText from "data-text:./content-scripts.css"; | ||
|
||
export const getStyle: PlasmoGetStyle = () => { | ||
const style = document.createElement("style"); | ||
style.textContent = cssText; | ||
return style; | ||
}; | ||
|
||
export const config: PlasmoCSConfig = { | ||
matches: ["https://*/*"], | ||
}; | ||
|
||
export default function Inline() { | ||
const [alerts, setAlerts] = useState<ContentScriptAlert[]>([]); | ||
|
||
const removeAlert = (id: number) => setAlerts((current) => current.filter((a) => a.id !== id)); | ||
|
||
useEffect(() => { | ||
async function onMessageListener(msg: TabMessage) { | ||
console.log("[MailFlare] Received tab message:", msg); | ||
switch (msg.command) { | ||
case "copyText": | ||
await window.navigator.clipboard.writeText(msg.text); | ||
break; | ||
case "clearClipboard": | ||
await window.navigator.clipboard.writeText("\u0000"); | ||
break; | ||
case "showAlert": | ||
setAlerts((current) => [msg.alert, ...current]); | ||
if (msg.alert.timeout) { | ||
setTimeout(() => removeAlert(msg.alert.id), msg.alert.timeout); | ||
} | ||
break; | ||
case "dismissAlert": | ||
removeAlert(msg.id); | ||
break; | ||
default: | ||
} | ||
} | ||
|
||
chrome.runtime.onMessage.addListener(onMessageListener); | ||
|
||
return () => chrome.runtime.onMessage.removeListener(onMessageListener); | ||
}, []); | ||
|
||
return ( | ||
<div data-theme="mantine"> | ||
<div className="toast toast-center"> | ||
{alerts.map((alert) => ( | ||
<div | ||
key={alert.id} | ||
className={`alert ${alert.type ? (`alert-${alert.type}` as const) : ""}`}> | ||
{alert.isLoading && <span className="loading loading-spinner loading-sm"></span>} | ||
<span>{alert.message}</span> | ||
<div> | ||
<button | ||
className="btn btn-square btn-sm btn-ghost" | ||
onClick={() => removeAlert(alert.id)}> | ||
<IconX size={14} /> | ||
</button> | ||
</div> | ||
</div> | ||
))} | ||
</div> | ||
</div> | ||
); | ||
} |
File renamed without changes.
Oops, something went wrong.