diff --git a/assets/locales/en/messages.json b/assets/locales/en/messages.json index 967e07e..238effb 100644 --- a/assets/locales/en/messages.json +++ b/assets/locales/en/messages.json @@ -54,7 +54,7 @@ "message": "Full remote updates are disabled due to browser limitations" }, "forMoreRulesJoinUs": { - "message": "For more rules support, join us!" + "message": "For more rules support, join us!" }, "general": { "message": "General" @@ -78,7 +78,7 @@ "message": "No RSS found" }, "rules": { - "message": "Rules" + "message": "Radar Rules" }, "rulesUpdate": { "message": "Rules update" @@ -118,5 +118,8 @@ }, "fillInstanceDomain": { "message": "Please fill in your instance domain" + }, + "totalNumberOfRules": { + "message": "Total number of rules" } } \ No newline at end of file diff --git a/assets/locales/zh/messages.json b/assets/locales/zh/messages.json index e1dc1ce..b964b47 100644 --- a/assets/locales/zh/messages.json +++ b/assets/locales/zh/messages.json @@ -54,7 +54,7 @@ "message": "由于浏览器限制,完整的远程更新被禁用" }, "forMoreRulesJoinUs": { - "message": "更多规则支持中,快来参与我们吧!" + "message": "更多规则支持中,快来参与我们吧!" }, "general": { "message": "常规" @@ -78,7 +78,7 @@ "message": "没有检测到 RSS" }, "rules": { - "message": "规则列表" + "message": "Radar 规则" }, "rulesUpdate": { "message": "规则更新" @@ -118,5 +118,8 @@ }, "fillInstanceDomain": { "message": "请填写你的实例域名" + }, + "totalNumberOfRules": { + "message": "规则总数" } } \ No newline at end of file diff --git a/package.json b/package.json index 7683045..b5fa2ec 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@iconify-json/mingcute": "^1.1.13", "@plasmohq/messaging": "^0.6.1", "@plasmohq/storage": "^1.9.0", + "@radix-ui/react-accordion": "^1.1.2", "@radix-ui/react-label": "^2.0.2", "@radix-ui/react-slot": "^1.0.2", "@radix-ui/react-switch": "^1.0.3", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 28dc24b..51c4388 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ dependencies: '@plasmohq/storage': specifier: ^1.9.0 version: 1.9.0(react@18.2.0) + '@radix-ui/react-accordion': + specifier: ^1.1.2 + version: 1.1.2(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0) '@radix-ui/react-label': specifier: ^2.0.2 version: 2.0.2(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0) @@ -2411,6 +2414,87 @@ packages: '@babel/runtime': 7.23.5 dev: false + /@radix-ui/react-accordion@1.1.2(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-fDG7jcoNKVjSK6yfmuAs0EnPDro0WMXIhMtXdTBWqEioVW206ku+4Lw07e+13lUkFkpoEQ2PdeMIAGpdqEAmDg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-collapsible': 1.0.3(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@radix-ui/react-direction': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@types/react': 18.2.37 + '@types/react-dom': 18.2.15 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-collapsible@1.0.3(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@types/react': 18.2.37 + '@types/react-dom': 18.2.15 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.37)(react@18.2.0) + '@types/react': 18.2.37 + '@types/react-dom': 18.2.15 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.37)(react@18.2.0): resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} peerDependencies: @@ -2439,6 +2523,35 @@ packages: react: 18.2.0 dev: false + /@radix-ui/react-direction@1.0.1(@types/react@18.2.37)(react@18.2.0): + resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@types/react': 18.2.37 + react: 18.2.0 + dev: false + + /@radix-ui/react-id@1.0.1(@types/react@18.2.37)(react@18.2.0): + resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@types/react': 18.2.37 + react: 18.2.0 + dev: false + /@radix-ui/react-label@2.0.2(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-N5ehvlM7qoTLx7nWPodsPYPgMzA5WM8zZChQg8nyFJKnDO5WHdba1vv5/H6IO5LtJMfD2Q3wh1qHFGNtK0w3bQ==} peerDependencies: @@ -2460,6 +2573,28 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.23.5 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.37)(react@18.2.0) + '@types/react': 18.2.37 + '@types/react-dom': 18.2.15 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.15)(@types/react@18.2.37)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} peerDependencies: diff --git a/src/background/index.ts b/src/background/index.ts index 2b36bdc..ce79d88 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -26,6 +26,8 @@ const storage = new Storage({ area: "local" }) +export const getRules = () => storage.get("rules") + export const getRSS = async (tabId, url) => { console.debug("Get RSS", tabId, url) @@ -52,7 +54,7 @@ export const getRSS = async (tabId, url) => { tabId, html, url, - rules: await storage.get("rules"), + rules: await getRules(), } } }) diff --git a/src/background/messages/contentReady.ts b/src/background/messages/contentReady.ts index b4c64d5..a7348e0 100644 --- a/src/background/messages/contentReady.ts +++ b/src/background/messages/contentReady.ts @@ -1,7 +1,7 @@ import type { PlasmoMessaging } from "@plasmohq/messaging" import { getRSS } from "~/background" -const handler: PlasmoMessaging.MessageHandler = async (req, res) => { +const handler: PlasmoMessaging.MessageHandler = (req) => { console.debug("content ready", req) getRSS(req.sender.tab.id, req.sender.tab.url) diff --git a/src/background/messages/popupReady.ts b/src/background/messages/popupReady.ts index 559d706..6417889 100644 --- a/src/background/messages/popupReady.ts +++ b/src/background/messages/popupReady.ts @@ -1,7 +1,7 @@ import type { PlasmoMessaging } from "@plasmohq/messaging" import { getCachedRSS } from "~/background" -const handler: PlasmoMessaging.MessageHandler = async (req, res) => { +const handler: PlasmoMessaging.MessageHandler = (req, res) => { console.debug("popup ready", req) chrome.tabs.query({ diff --git a/src/background/messages/requestRules.ts b/src/background/messages/requestRules.ts new file mode 100644 index 0000000..7b1b0af --- /dev/null +++ b/src/background/messages/requestRules.ts @@ -0,0 +1,10 @@ +import type { PlasmoMessaging } from "@plasmohq/messaging" +import { getRules } from "~/background" + +const handler: PlasmoMessaging.MessageHandler = async (req, res) => { + console.debug("request rules", req) + + res.send(await getRules()) +} + +export default handler \ No newline at end of file diff --git a/src/lib/components/Accordion.tsx b/src/lib/components/Accordion.tsx new file mode 100644 index 0000000..4303273 --- /dev/null +++ b/src/lib/components/Accordion.tsx @@ -0,0 +1,58 @@ +"use client" + +import * as React from "react" +import * as AccordionPrimitive from "@radix-ui/react-accordion" +import { ChevronDown } from "lucide-react" + +import { cn } from "~/lib/utils" + +const Accordion = AccordionPrimitive.Root + +const AccordionItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AccordionItem.displayName = "AccordionItem" + +const AccordionTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + svg]:rotate-180", + className + )} + {...props} + > + {children} + + + +)) +AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName + +const AccordionContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + +
{children}
+
+)) + +AccordionContent.displayName = AccordionPrimitive.Content.displayName + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent } diff --git a/src/lib/rules.ts b/src/lib/rules.ts index d4506dc..06034a5 100644 --- a/src/lib/rules.ts +++ b/src/lib/rules.ts @@ -1,12 +1,13 @@ import _ from 'lodash'; import { defaultRules } from './radar-rules'; import { defaultConfig } from './config'; +import type { Rules } from './types'; -export function parseRules(rules) { +export function parseRules(rules: string, forceJSON?: boolean) { let incomeRules = rules; if (incomeRules) { if (typeof rules === 'string') { - if (defaultConfig.enableFullRemoteRules) { + if (defaultConfig.enableFullRemoteRules && !forceJSON) { incomeRules = window['lave'.split('').reverse().join('')](rules); } else { incomeRules = JSON.parse(rules); @@ -19,23 +20,5 @@ export function parseRules(rules) { } else if (_.isFunction(objValue)) { return objValue; } - }); -} - -export function getList(data) { - const rules = parseRules(data.rules); - for (const rule in rules) { - for (const subrule in rules[rule]) { - if (subrule[0] !== '_') { - rules[rule][subrule].forEach((item) => { - delete item.source; - delete item.target; - delete item.script; - delete item.verification; - delete item.test; - }); - } - } - } - return rules; + }) as Rules; } diff --git a/src/lib/style.css b/src/lib/style.css index 6a75725..b6b644b 100644 --- a/src/lib/style.css +++ b/src/lib/style.css @@ -73,4 +73,8 @@ body { @apply bg-background text-foreground; } + + .content a { + @apply underline text-orange-500; + } } \ No newline at end of file diff --git a/src/options/routes/About.tsx b/src/options/routes/About.tsx index 7bca099..9f40452 100644 --- a/src/options/routes/About.tsx +++ b/src/options/routes/About.tsx @@ -1,32 +1,15 @@ -import { defaultConfig, setConfig } from "~/lib/config" import { Card, CardContent, - CardHeader, - CardTitle, } from "~/lib/components/Card" -import { Switch } from "~/lib/components/Switch" -import { quickSubscriptions } from "~/lib/quick-subscriptions" -import { useStorage } from "@plasmohq/storage/hook" -import _ from 'lodash'; function About() { - const [config] = useStorage("config", (v) => _.merge({}, defaultConfig, v)) - return (

{chrome.i18n.getMessage("about")}

- - +

diff --git a/src/options/routes/Rules.tsx b/src/options/routes/Rules.tsx new file mode 100644 index 0000000..f04c461 --- /dev/null +++ b/src/options/routes/Rules.tsx @@ -0,0 +1,101 @@ +import _ from "lodash" +import { useEffect, useState } from "react" + +import { sendToBackground } from "@plasmohq/messaging" + +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger +} from "~/lib/components/Accordion" +import { Card, CardContent } from "~/lib/components/Card" +import { parseRules } from "~/lib/rules" +import type { Rules as IRules } from "~/lib/types" + +function Rules() { + const [rules, setRules] = useState({}) + useEffect(() => { + sendToBackground({ + name: "requestRules" + }).then((res) => setRules(parseRules(res, true))) + }, []) + + const [count, setCount] = useState(0) + useEffect(() => { + let index = 0; + Object.keys(rules).map((key) => { + const rule = rules[key] + Object.keys(rule).map((item) => { + if (Array.isArray(rule[item])) { + index += rule[item].length + } + }) + }) + setCount(index) + }, [rules]) + + return ( +
+

+ {chrome.i18n.getMessage("rules")} +

+
+

{chrome.i18n.getMessage("totalNumberOfRules")}: {count}

+

+
+
+ + + {Object.keys(rules).map((key) => { + const rule = rules[key] + return ( +
+ + + +
+ {rule._name} - {key} +
+
+ +
+ {Object.keys(rule).map((item) => { + const subdomainRules = rule[item] + if (Array.isArray(subdomainRules)) { + return subdomainRules.map( + (subdomainRule, index) => { + return ( +
+
+
+

+ {subdomainRule.title} +

+
+
+
+ ) + } + ) + } else { + return null + } + })} +
+
+
+
+
+ ) + })} +
+
+
+
+ ) +} + +export { Rules } diff --git a/src/options/routes/index.tsx b/src/options/routes/index.tsx index e301783..e974435 100644 --- a/src/options/routes/index.tsx +++ b/src/options/routes/index.tsx @@ -1,11 +1,13 @@ import { Route, Routes } from "react-router-dom" import { About } from "./About" +import { Rules } from "./Rules" import { General } from "./General" export const Routing = () => ( } /> + } /> } /> ) \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js index 321c208..7580897 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -24,6 +24,20 @@ module.exports = { }, }, extend: { + keyframes: { + "accordion-down": { + from: { height: "0" }, + to: { height: "var(--radix-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--radix-accordion-content-height)" }, + to: { height: "0" }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + }, colors: { border: "hsl(var(--border))", input: "hsl(var(--input))",