From 410004fa8a650f3a41215eb87ab437186fd94401 Mon Sep 17 00:00:00 2001 From: "Collin M. Barrett" Date: Fri, 26 Jul 2019 20:06:42 -0500 Subject: [PATCH] copy over modules & utils folders --- src/web/src/modules/home/Home.tsx | 107 ++++++++++++++++++ src/web/src/modules/home/HomeContainer.tsx | 94 +++++++++++++++ .../src/modules/home/components/Oneliner.tsx | 17 +++ .../src/modules/home/components/TagGroup.tsx | 67 +++++++++++ .../detailsExpander/DetailsExpander.tsx | 27 +++++ .../detailsExpander/IListDetails.ts | 26 +++++ .../detailsExpander/LinkButtonGroup.tsx | 41 +++++++ .../home/components/detailsExpander/index.ts | 7 ++ .../detailsExpander/infoCard/Description.tsx | 16 +++ .../detailsExpander/infoCard/InfoCard.tsx | 57 ++++++++++ .../detailsExpander/infoCard/Languages.tsx | 20 ++++ .../detailsExpander/infoCard/License.tsx | 17 +++ .../infoCard/PublishedDate.tsx | 13 +++ .../detailsExpander/infoCard/RuleCount.tsx | 12 ++ .../detailsExpander/infoCard/Syntax.tsx | 17 +++ .../detailsExpander/infoCard/UpdatedDate.tsx | 15 +++ .../detailsExpander/infoCard/description.css | 1 + .../detailsExpander/infoCard/index.ts | 5 + .../MaintainerAdditionalLists.tsx | 20 ++++ .../MaintainerInfoCard.tsx | 23 ++++ .../MaintainerLinkButtonGroup.tsx | 16 +++ .../MaintainersInfoCard.tsx | 14 +++ .../maintainersInfoCard/index.ts | 5 + src/web/src/modules/home/components/index.ts | 9 ++ .../components/linkButtons/ChatButton.tsx | 14 +++ .../components/linkButtons/DonateButton.tsx | 14 +++ .../components/linkButtons/EmailButton.tsx | 14 +++ .../components/linkButtons/ForumButton.tsx | 14 +++ .../components/linkButtons/HomeButton.tsx | 14 +++ .../components/linkButtons/IssuesButton.tsx | 14 +++ .../components/linkButtons/LinkButton.tsx | 18 +++ .../components/linkButtons/PolicyButton.tsx | 14 +++ .../components/linkButtons/SubmitButton.tsx | 14 +++ .../linkButtons/SubscribeButton.tsx | 62 ++++++++++ .../linkButtons/SubscribeButtonGroup.tsx | 52 +++++++++ .../components/linkButtons/TwitterButton.tsx | 14 +++ .../components/linkButtons/ViewButton.tsx | 24 ++++ .../linkButtons/ViewButtonGroup.tsx | 51 +++++++++ .../home/components/linkButtons/button.css | 11 ++ .../home/components/linkButtons/index.ts | 25 ++++ .../home/components/listsTable/ListsTable.tsx | 104 +++++++++++++++++ .../listsTable/columns/DetailsButton.tsx | 26 +++++ .../listsTable/columns/Languages.tsx | 71 ++++++++++++ .../components/listsTable/columns/License.tsx | 68 +++++++++++ .../listsTable/columns/Maintainers.tsx | 68 +++++++++++ .../components/listsTable/columns/Name.tsx | 22 ++++ .../listsTable/columns/RuleCount.tsx | 28 +++++ .../listsTable/columns/Software.tsx | 74 ++++++++++++ .../listsTable/columns/SubscribeButton.tsx | 24 ++++ .../components/listsTable/columns/Syntax.tsx | 46 ++++++++ .../components/listsTable/columns/Tags.tsx | 63 +++++++++++ .../listsTable/columns/UpdatedDate.tsx | 33 ++++++ .../components/listsTable/columns/index.ts | 25 ++++ .../home/components/listsTable/index.ts | 5 + .../home/components/listsTable/listsTable.css | 13 +++ .../components/softwareIcon/SoftwareIcon.tsx | 89 +++++++++++++++ .../softwareIcon/imgs/01-uBlock-Origin.svg | 1 + .../softwareIcon/imgs/02-Adblock-Plus.svg | 15 +++ .../softwareIcon/imgs/03-AdGuard.png | Bin 0 -> 893 bytes .../softwareIcon/imgs/03-AdGuard.svg | 5 + .../components/softwareIcon/imgs/04-DNS66.png | Bin 0 -> 851 bytes .../softwareIcon/imgs/05-Nano-Adblocker.png | Bin 0 -> 698 bytes .../softwareIcon/imgs/06-AdBlock.png | Bin 0 -> 1268 bytes .../softwareIcon/imgs/07-AdAway.png | Bin 0 -> 658 bytes .../imgs/08-Personal-Blocklist.png | Bin 0 -> 1295 bytes .../softwareIcon/imgs/10-Redirector.png | Bin 0 -> 547 bytes .../imgs/11-Hosts-File-Editor.png | Bin 0 -> 1113 bytes .../softwareIcon/imgs/12-Gas-Mask.png | Bin 0 -> 424 bytes .../softwareIcon/imgs/13-MinerBlock.svg | 34 ++++++ .../softwareIcon/imgs/14-Pi-hole.png | Bin 0 -> 700 bytes .../softwareIcon/imgs/14-Pi-hole.svg | 1 + .../softwareIcon/imgs/15-uBlock.svg | 18 +++ .../imgs/16-Internet-Explorer-TPL.png | Bin 0 -> 1056 bytes .../imgs/16-Internet-Explorer-TPL.svg | 1 + .../imgs/17-Google-Hit-Hider-by-Domain.png | Bin 0 -> 636 bytes .../softwareIcon/imgs/18-FireHOL.png | Bin 0 -> 617 bytes .../softwareIcon/imgs/19-Samsung-Knox.png | Bin 0 -> 476 bytes .../softwareIcon/imgs/20-Little-Snitch.png | Bin 0 -> 1168 bytes .../softwareIcon/imgs/21-Privoxy.png | Bin 0 -> 1286 bytes .../softwareIcon/imgs/22-Diversion.png | Bin 0 -> 403 bytes .../softwareIcon/imgs/23-dnsmasq.png | Bin 0 -> 789 bytes .../softwareIcon/imgs/24-Slimjet.png | Bin 0 -> 1419 bytes .../softwareIcon/imgs/25-uMatrix.png | Bin 0 -> 917 bytes .../softwareIcon/imgs/26-Blokada.png | Bin 0 -> 998 bytes .../softwareIcon/imgs/27-hostsmgr.png | Bin 0 -> 750 bytes .../imgs/28-personalDNSfilter.png | Bin 0 -> 831 bytes .../imgs/28-personalDNSfilter.svg | 20 ++++ .../softwareIcon/imgs/29-Unbound.png | Bin 0 -> 565 bytes .../components/softwareIcon/imgs/30-BIND.png | Bin 0 -> 520 bytes .../softwareIcon/imgs/31-AdGuard-Home.png | Bin 0 -> 878 bytes .../softwareIcon/imgs/32-AdNauseam.png | Bin 0 -> 713 bytes .../imgs/33-Legacy-Unix-Derivatives.png | Bin 0 -> 867 bytes .../imgs/34-Windows-command-line.png | Bin 0 -> 470 bytes .../components/softwareIcon/imgs/imgs.d.ts | 9 ++ .../components/softwareIcon/imgs/index.ts | 69 +++++++++++ .../home/components/softwareIcon/index.ts | 5 + src/web/src/modules/home/index.ts | 5 + .../home/interfaces/IColumnVisibility.ts | 4 + .../src/modules/home/interfaces/ILanguage.ts | 6 + .../src/modules/home/interfaces/ILicense.ts | 6 + src/web/src/modules/home/interfaces/IList.ts | 24 ++++ .../modules/home/interfaces/IMaintainer.ts | 8 ++ .../src/modules/home/interfaces/ISoftware.ts | 7 ++ .../src/modules/home/interfaces/ISyntax.ts | 7 ++ src/web/src/modules/home/interfaces/ITag.ts | 6 + src/web/src/modules/home/interfaces/index.ts | 19 ++++ src/web/src/modules/index.ts | 5 + src/web/src/utils/GetContrast.ts | 8 ++ src/web/src/utils/index.ts | 5 + src/web/src/utils/loader.css | 68 +++++++++++ 110 files changed, 2130 insertions(+) create mode 100644 src/web/src/modules/home/Home.tsx create mode 100644 src/web/src/modules/home/HomeContainer.tsx create mode 100644 src/web/src/modules/home/components/Oneliner.tsx create mode 100644 src/web/src/modules/home/components/TagGroup.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/DetailsExpander.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/IListDetails.ts create mode 100644 src/web/src/modules/home/components/detailsExpander/LinkButtonGroup.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/index.ts create mode 100644 src/web/src/modules/home/components/detailsExpander/infoCard/Description.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/infoCard/InfoCard.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/infoCard/Languages.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/infoCard/License.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/infoCard/PublishedDate.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/infoCard/RuleCount.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/infoCard/Syntax.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/infoCard/UpdatedDate.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/infoCard/description.css create mode 100644 src/web/src/modules/home/components/detailsExpander/infoCard/index.ts create mode 100644 src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerAdditionalLists.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerInfoCard.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerLinkButtonGroup.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainersInfoCard.tsx create mode 100644 src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/index.ts create mode 100644 src/web/src/modules/home/components/index.ts create mode 100644 src/web/src/modules/home/components/linkButtons/ChatButton.tsx create mode 100644 src/web/src/modules/home/components/linkButtons/DonateButton.tsx create mode 100644 src/web/src/modules/home/components/linkButtons/EmailButton.tsx create mode 100644 src/web/src/modules/home/components/linkButtons/ForumButton.tsx create mode 100644 src/web/src/modules/home/components/linkButtons/HomeButton.tsx create mode 100644 src/web/src/modules/home/components/linkButtons/IssuesButton.tsx create mode 100644 src/web/src/modules/home/components/linkButtons/LinkButton.tsx create mode 100644 src/web/src/modules/home/components/linkButtons/PolicyButton.tsx create mode 100644 src/web/src/modules/home/components/linkButtons/SubmitButton.tsx create mode 100644 src/web/src/modules/home/components/linkButtons/SubscribeButton.tsx create mode 100644 src/web/src/modules/home/components/linkButtons/SubscribeButtonGroup.tsx create mode 100644 src/web/src/modules/home/components/linkButtons/TwitterButton.tsx create mode 100644 src/web/src/modules/home/components/linkButtons/ViewButton.tsx create mode 100644 src/web/src/modules/home/components/linkButtons/ViewButtonGroup.tsx create mode 100644 src/web/src/modules/home/components/linkButtons/button.css create mode 100644 src/web/src/modules/home/components/linkButtons/index.ts create mode 100644 src/web/src/modules/home/components/listsTable/ListsTable.tsx create mode 100644 src/web/src/modules/home/components/listsTable/columns/DetailsButton.tsx create mode 100644 src/web/src/modules/home/components/listsTable/columns/Languages.tsx create mode 100644 src/web/src/modules/home/components/listsTable/columns/License.tsx create mode 100644 src/web/src/modules/home/components/listsTable/columns/Maintainers.tsx create mode 100644 src/web/src/modules/home/components/listsTable/columns/Name.tsx create mode 100644 src/web/src/modules/home/components/listsTable/columns/RuleCount.tsx create mode 100644 src/web/src/modules/home/components/listsTable/columns/Software.tsx create mode 100644 src/web/src/modules/home/components/listsTable/columns/SubscribeButton.tsx create mode 100644 src/web/src/modules/home/components/listsTable/columns/Syntax.tsx create mode 100644 src/web/src/modules/home/components/listsTable/columns/Tags.tsx create mode 100644 src/web/src/modules/home/components/listsTable/columns/UpdatedDate.tsx create mode 100644 src/web/src/modules/home/components/listsTable/columns/index.ts create mode 100644 src/web/src/modules/home/components/listsTable/index.ts create mode 100644 src/web/src/modules/home/components/listsTable/listsTable.css create mode 100644 src/web/src/modules/home/components/softwareIcon/SoftwareIcon.tsx create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/01-uBlock-Origin.svg create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/02-Adblock-Plus.svg create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/03-AdGuard.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/03-AdGuard.svg create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/04-DNS66.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/05-Nano-Adblocker.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/06-AdBlock.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/07-AdAway.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/08-Personal-Blocklist.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/10-Redirector.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/11-Hosts-File-Editor.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/12-Gas-Mask.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/13-MinerBlock.svg create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/14-Pi-hole.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/14-Pi-hole.svg create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/15-uBlock.svg create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/16-Internet-Explorer-TPL.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/16-Internet-Explorer-TPL.svg create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/17-Google-Hit-Hider-by-Domain.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/18-FireHOL.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/19-Samsung-Knox.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/20-Little-Snitch.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/21-Privoxy.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/22-Diversion.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/23-dnsmasq.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/24-Slimjet.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/25-uMatrix.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/26-Blokada.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/27-hostsmgr.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/28-personalDNSfilter.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/28-personalDNSfilter.svg create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/29-Unbound.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/30-BIND.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/31-AdGuard-Home.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/32-AdNauseam.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/33-Legacy-Unix-Derivatives.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/34-Windows-command-line.png create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/imgs.d.ts create mode 100644 src/web/src/modules/home/components/softwareIcon/imgs/index.ts create mode 100644 src/web/src/modules/home/components/softwareIcon/index.ts create mode 100644 src/web/src/modules/home/index.ts create mode 100644 src/web/src/modules/home/interfaces/IColumnVisibility.ts create mode 100644 src/web/src/modules/home/interfaces/ILanguage.ts create mode 100644 src/web/src/modules/home/interfaces/ILicense.ts create mode 100644 src/web/src/modules/home/interfaces/IList.ts create mode 100644 src/web/src/modules/home/interfaces/IMaintainer.ts create mode 100644 src/web/src/modules/home/interfaces/ISoftware.ts create mode 100644 src/web/src/modules/home/interfaces/ISyntax.ts create mode 100644 src/web/src/modules/home/interfaces/ITag.ts create mode 100644 src/web/src/modules/home/interfaces/index.ts create mode 100644 src/web/src/modules/index.ts create mode 100644 src/web/src/utils/GetContrast.ts create mode 100644 src/web/src/utils/index.ts create mode 100644 src/web/src/utils/loader.css diff --git a/src/web/src/modules/home/Home.tsx b/src/web/src/modules/home/Home.tsx new file mode 100644 index 000000000..06daee6a3 --- /dev/null +++ b/src/web/src/modules/home/Home.tsx @@ -0,0 +1,107 @@ +import * as React from "react"; +import { IColumnVisibility, ILanguage, ILicense, IList, IMaintainer, ISoftware, ISyntax, ITag } from "./interfaces"; +import { ListsTable, Oneliner } from "./components"; + +const columnVisibilityDefaults: IColumnVisibility[] = [ + { column: "Software", visible: true }, + { column: "Languages", visible: true }, + { column: "Tags", visible: true }, + //{ column: "Updated", visible: false }, + //{ column: "Rules", visible: false }, + { column: "License", visible: false }, + { column: "Maintainers", visible: false }, + { column: "Subscribe", visible: false } +]; + +interface IProps { + languages: ILanguage[]; + licenses: ILicense[]; + lists: IList[]; + maintainers: IMaintainer[]; + //ruleCount: number; + software: ISoftware[]; + syntaxes: ISyntax[]; + tags: ITag[]; +}; + +interface IState { + columnVisibility: IColumnVisibility[]; + pageSize: number; +}; + +export class Home extends React.Component { + constructor(props: IProps) { + super(props); + this.state = { + columnVisibility: columnVisibilityDefaults, + pageSize: 20 + }; + this.updatePageSize = this.updatePageSize.bind(this); + } + + componentDidMount() { + this.setMobileColumnVisibility(); + this.updatePageSize(); + }; + + setMobileColumnVisibility() { + if (window.innerWidth < 768) { + this.state.columnVisibility.forEach((c: IColumnVisibility) => { + c.visible = false; + }); + } + }; + + updatePageSize() { + this.setState({ + pageSize: Math.max(Math.floor((window.innerHeight - 400) / 52), 5) + }); + }; + + render() { + return
+ + + {this.renderColumnVisibilityCheckboxes()} +
; + }; + + renderColumnVisibilityCheckboxes() { + return this.props.lists.length > 0 + ?
+ Visible:  {this.state.columnVisibility.map( + (c: IColumnVisibility, i: number) => this.renderColumnVisibilityCheckbox(c, i))} +
+ : null; + }; + + renderColumnVisibilityCheckbox(props: IColumnVisibility, key: number) { + return
+ this.checkColumn(props)}/> + +
; + }; + + checkColumn(props: IColumnVisibility) { + const columnVisibility = this.state.columnVisibility; + const index = this.findWithAttr(columnVisibility, "column", props.column); + columnVisibility[index].visible = !columnVisibility[index].visible; + this.forceUpdate(); + }; + + findWithAttr(array: any, attr: string, value: string) { + for (let i = 0; i < array.length; i += 1) { + if (array[i][attr] === value) { + return i; + } + } + return -1; + }; +}; \ No newline at end of file diff --git a/src/web/src/modules/home/HomeContainer.tsx b/src/web/src/modules/home/HomeContainer.tsx new file mode 100644 index 000000000..b5a34ba0e --- /dev/null +++ b/src/web/src/modules/home/HomeContainer.tsx @@ -0,0 +1,94 @@ +import * as React from "react"; +import "isomorphic-fetch"; +import { ILanguage, ILicense, IList, IMaintainer, ISoftware, ISyntax, ITag } from "./interfaces"; +import { Home } from "./Home"; + +interface IState { + languages: ILanguage[]; + licenses: ILicense[]; + lists: IList[]; + maintainers: IMaintainer[]; + ruleCount: number; + software: ISoftware[]; + syntaxes: ISyntax[]; + tags: ITag[]; +}; + +export class HomeContainer extends React.Component<{}, IState> { + constructor(props: any) { + super(props); + this.state = { + languages: [], + licenses: [], + lists: [], + maintainers: [], + ruleCount: 0, + software: [], + syntaxes: [], + tags: [] + }; + } + + componentDidMount() { + this.fetchLanguages(); + this.fetchLicenses(); + this.fetchLists(); + this.fetchMaintainers(); + this.fetchSoftware(); + this.fetchSyntaxes(); + this.fetchTags(); + // this.fetchRuleCount(); + }; + + fetchLanguages() { + fetch("/api/v1/languages") + .then(r => r.json() as Promise) + .then(p => { this.setState({ languages: p }); }); + }; + + fetchLicenses() { + fetch("/api/v1/licenses") + .then(r => r.json() as Promise) + .then(p => { this.setState({ licenses: p }); }); + }; + + fetchLists() { + fetch("/api/v1/lists") + .then(r => r.json() as Promise) + .then(p => { this.setState({ lists: p }); }); + }; + + fetchMaintainers() { + fetch("/api/v1/maintainers") + .then(r => r.json() as Promise) + .then(p => { this.setState({ maintainers: p }); }); + }; + + fetchSoftware() { + fetch("/api/v1/software") + .then(r => r.json() as Promise) + .then(p => { this.setState({ software: p }); }); + }; + + fetchSyntaxes() { + fetch("/api/v1/syntaxes") + .then(r => r.json() as Promise) + .then(p => { this.setState({ syntaxes: p }); }); + }; + + fetchTags() { + fetch("/api/v1/tags") + .then(r => r.json() as Promise) + .then(p => { this.setState({ tags: p }); }); + }; + + fetchRuleCount() { + fetch("/api/v1/rules") + .then(r => r.json() as Promise) + .then(p => { this.setState({ ruleCount: p }); }); + }; + + render() { + return ; + }; +}; \ No newline at end of file diff --git a/src/web/src/modules/home/components/Oneliner.tsx b/src/web/src/modules/home/components/Oneliner.tsx new file mode 100644 index 000000000..5ad124110 --- /dev/null +++ b/src/web/src/modules/home/components/Oneliner.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; + +interface IProps { + listCount: number; + //ruleCount: number; +}; + +export const Oneliner = (props: IProps) => + props.listCount > 0/* && props.ruleCount > 0*/ + ?

+ The independent, comprehensive directory of {/*}{props.ruleCount.toLocaleString() + } unique rules across */}{props.listCount.toLocaleString() + } filter and host lists for advertisements, trackers, malware, and annoyances. +

+ :

+ The independent, comprehensive directory of filter and host lists for advertisements, trackers, malware, and annoyances. +

; \ No newline at end of file diff --git a/src/web/src/modules/home/components/TagGroup.tsx b/src/web/src/modules/home/components/TagGroup.tsx new file mode 100644 index 000000000..5f7a609da --- /dev/null +++ b/src/web/src/modules/home/components/TagGroup.tsx @@ -0,0 +1,67 @@ +import * as React from "react"; +import { ITag } from "../interfaces"; +import { getContrast } from "../../../utils"; + +interface IProps { + tags: ITag[]; +}; + +export const TagGroup = (props: IProps) => + props.tags && props.tags.length > 0 + ?
+ {props.tags.map((t: ITag, i: number) => )} +
+ : null; + +interface ITagProps { + tag: ITag; +}; + +const Tag = (props: ITagProps) => { + if (props.tag) { + const hexColor = kelly_colors_hex[props.tag.id % kelly_colors_hex.length]; + return + {props.tag.name} + ; + } else { + return null; + } +}; + +//https://stackoverflow.com/a/4382138/2343739 +const kelly_colors_hex = [ + "FFB300", // Vivid Yellow + "803E75", // Strong Purple + "FF6800", // Vivid Orange + "A6BDD7", // Very Light Blue + "C10020", // Vivid Red + "CEA262", // Grayish Yellow + "817066", // Medium Gray + "007D34", // Vivid Green + "F6768E", // Strong Purplish Pink + "00538A", // Strong Blue + "FF7A5C", // Strong Yellowish Pink + "53377A", // Strong Violet + "FF8E00", // Vivid Orange Yellow + "B32851", // Strong Purplish Red + "F4C800", // Vivid Greenish Yellow + "7F180D", // Strong Reddish Brown + "93AA00", // Vivid Yellowish Green + "593315", // Deep Yellowish Brown + "F13A13", // Vivid Reddish Orange + "232C16", // Dark Olive Green + "000000", // Black + "FFFFFF", // White + "C2F4BE", // Light Green + "1EDBB9", // Medium Greenish Blue + "890000", // Dark Red + "474747", // Dark Grey + "BFA125", // Matte Gold + "A7823C", // Dark Beige + "035A5C" // Dark Greenish Blue +]; diff --git a/src/web/src/modules/home/components/detailsExpander/DetailsExpander.tsx b/src/web/src/modules/home/components/detailsExpander/DetailsExpander.tsx new file mode 100644 index 000000000..852dbea32 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/DetailsExpander.tsx @@ -0,0 +1,27 @@ +import * as React from "react"; +import { IColumnVisibility, ISoftware } from "../../interfaces"; +import { IListDetails } from "./IListDetails"; +import { InfoCard } from "./infoCard"; +import { LinkButtonGroup } from "./LinkButtonGroup"; +import { MaintainersInfoCard } from "./maintainersInfoCard"; + +interface IProps { + columnVisibility: IColumnVisibility[]; + list: IListDetails; + software: ISoftware[]; +}; + +export const DetailsExpander = (props: IProps) => +
+
+
+
+ + +
+
+ +
+
+
+
; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/IListDetails.ts b/src/web/src/modules/home/components/detailsExpander/IListDetails.ts new file mode 100644 index 000000000..5b87aa51f --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/IListDetails.ts @@ -0,0 +1,26 @@ +import { ILanguage, ILicense, IMaintainer, ISyntax, ITag } from "../../interfaces"; + +export interface IListDetails { + id: number; + chatUrl: string; + description: string; + descriptionSourceUrl: string; + donateUrl: string; + emailAddress: string; + forumUrl: string; + homeUrl: string; + issuesUrl: string; + languages: ILanguage[]; + license: ILicense; + maintainers: IMaintainer[]; + name: string; + policyUrl: string; + publishedDate: string; + //ruleCount: number; + submissionUrl: string; + syntax: ISyntax; + tags: ITag[]; + //updatedDate: string; + viewUrl: string; + viewUrlMirrors: string[]; +}; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/LinkButtonGroup.tsx b/src/web/src/modules/home/components/detailsExpander/LinkButtonGroup.tsx new file mode 100644 index 000000000..528d21029 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/LinkButtonGroup.tsx @@ -0,0 +1,41 @@ +import * as React from "react"; +import { + ChatButton, + DonateButton, + EmailButton, + ForumButton, + HomeButton, + IssuesButton, + PolicyButton, + SubmitButton, + SubscribeButtonGroup, + ViewButtonGroup +} from "../linkButtons"; + +interface IProps { + chatUrl: string; + donateUrl: string; + emailAddress: string; + forumUrl: string; + homeUrl: string; + issuesUrl: string; + name: string; + policyUrl: string; + submissionUrl: string; + viewUrl: string; + viewUrlMirrors: string[]; +}; + +export const LinkButtonGroup = (props: IProps) => +
+ + + + + + + + + + +
; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/index.ts b/src/web/src/modules/home/components/detailsExpander/index.ts new file mode 100644 index 000000000..6b887a094 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/index.ts @@ -0,0 +1,7 @@ +import { DetailsExpander } from "./DetailsExpander"; +import { IListDetails } from "./IListDetails"; + +export { + DetailsExpander, + IListDetails + }; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/infoCard/Description.tsx b/src/web/src/modules/home/components/detailsExpander/infoCard/Description.tsx new file mode 100644 index 000000000..983c14924 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/infoCard/Description.tsx @@ -0,0 +1,16 @@ +import * as React from "react"; +import "./description.css"; + +interface IProps { + description: string; + url: string; +}; + +export const Description = (props: IProps) => + props.description + ?

+ {props.url + ?
{props.description}
+ : props.description} +

+ : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/infoCard/InfoCard.tsx b/src/web/src/modules/home/components/detailsExpander/infoCard/InfoCard.tsx new file mode 100644 index 000000000..9e8ba3ae2 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/infoCard/InfoCard.tsx @@ -0,0 +1,57 @@ +import * as React from "react"; +import { IColumnVisibility } from "../../../interfaces"; +import { ILanguage, ILicense, ISoftware, ISyntax, ITag } from "../../../interfaces"; +import { Description } from "./Description"; +import { Languages } from "./Languages"; +import { License } from "./License"; +import { PublishedDate } from "./PublishedDate"; +import { RuleCount } from "./RuleCount"; +import { SoftwareIcon } from "../../softwareIcon"; +import { Syntax } from "./Syntax"; +import { TagGroup } from "../../TagGroup" +import { UpdatedDate } from "./UpdatedDate"; + +interface IProps { + columnVisibility: IColumnVisibility[]; + description: string; + descriptionSourceUrl: string; + languages: ILanguage[]; + license: ILicense; + name: string; + publishedDate: string; + //ruleCount: number; + software: ISoftware[]; + syntax: ISyntax; + tags: ITag[]; + //updatedDate: string; +}; + +export const InfoCard = (props: IProps) => +
+ {props.columnVisibility.filter((c: IColumnVisibility) => c.column === "Tags")[0].visible + ? null + : } +
+ {props.columnVisibility.filter((c: IColumnVisibility) => c.column === "Software")[0].visible + ? null + : props.syntax + ? props.software.filter((s: ISoftware) => s.syntaxIds.indexOf(props.syntax.id) > -1) + .map((s: ISoftware, i: number) => ) + : null} +
+ +
    + + {/*{props.columnVisibility.filter((c: IColumnVisibility) => c.column === "Rules")[0].visible + ? null + : } + {props.columnVisibility.filter((c: IColumnVisibility) => c.column === "Updated")[0].visible + ? null + : }*/} + + + {props.columnVisibility.filter((c: IColumnVisibility) => c.column === "License")[0].visible + ? null + : } +
+
; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/infoCard/Languages.tsx b/src/web/src/modules/home/components/detailsExpander/infoCard/Languages.tsx new file mode 100644 index 000000000..c3390c299 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/infoCard/Languages.tsx @@ -0,0 +1,20 @@ +import * as React from "react"; +import { ILanguage } from "../../../interfaces"; + +interface IProps { + languages: ILanguage[]; +}; + +export const Languages = (props: IProps) => + props.languages && props.languages.length > 0 + ? props.languages.length > 1 + ?
  • +

    Languages:

    +
      + {props.languages.map((language: ILanguage, i: number) =>
    • {language.name}
    • )} +
    +
  • + :
  • +

    Language: {props.languages[0].name}

    +
  • + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/infoCard/License.tsx b/src/web/src/modules/home/components/detailsExpander/infoCard/License.tsx new file mode 100644 index 000000000..a6222c8a9 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/infoCard/License.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +import { ILicense } from "../../../interfaces"; + +interface IProps { + license: ILicense; +}; + +export const License = (props: IProps) => + props.license.name + ? (props.license.descriptionUrl + ?
  • +

    License: {props.license.name}

    +
  • + :
  • +

    License: {props.license.name}

    +
  • ) + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/infoCard/PublishedDate.tsx b/src/web/src/modules/home/components/detailsExpander/infoCard/PublishedDate.tsx new file mode 100644 index 000000000..530a08950 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/infoCard/PublishedDate.tsx @@ -0,0 +1,13 @@ +import * as React from "react"; +import * as moment from "moment"; + +interface IProps { + date: string; +}; + +export const PublishedDate = (props: IProps) => + props.date + ?
  • +

    Published: {moment(props.date).format("l")}

    +
  • + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/infoCard/RuleCount.tsx b/src/web/src/modules/home/components/detailsExpander/infoCard/RuleCount.tsx new file mode 100644 index 000000000..1fb5944bf --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/infoCard/RuleCount.tsx @@ -0,0 +1,12 @@ +import * as React from "react"; + +interface IProps { + ruleCount: number; +}; + +export const RuleCount = (props: IProps) => + props.ruleCount > 0 + ?
  • +

    Rule Count: {props.ruleCount.toLocaleString()}

    +
  • + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/infoCard/Syntax.tsx b/src/web/src/modules/home/components/detailsExpander/infoCard/Syntax.tsx new file mode 100644 index 000000000..3a3356b85 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/infoCard/Syntax.tsx @@ -0,0 +1,17 @@ +import * as React from "react"; +import { ISyntax } from "../../../interfaces"; + +interface IProps { + syntax: ISyntax; +}; + +export const Syntax = (props: IProps) => + props.syntax + ? (props.syntax.definitionUrl + ?
  • +

    Syntax: {props.syntax.name}

    +
  • + :
  • +

    Syntax: {props.syntax.name}

    +
  • ) + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/infoCard/UpdatedDate.tsx b/src/web/src/modules/home/components/detailsExpander/infoCard/UpdatedDate.tsx new file mode 100644 index 000000000..7e72853f0 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/infoCard/UpdatedDate.tsx @@ -0,0 +1,15 @@ +import * as React from "react"; +import * as moment from "moment"; + +interface IProps { + updatedDate: string; +}; + +export const UpdatedDate = (props: IProps) => + props.updatedDate + ?
  • +

    Updated: {moment(props.updatedDate).isValid() + ? moment(props.updatedDate).format("l") + : "N/A"}

    +
  • + : null; diff --git a/src/web/src/modules/home/components/detailsExpander/infoCard/description.css b/src/web/src/modules/home/components/detailsExpander/infoCard/description.css new file mode 100644 index 000000000..2a1267485 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/infoCard/description.css @@ -0,0 +1 @@ +.fl-description { margin: 0 0 .5rem; } \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/infoCard/index.ts b/src/web/src/modules/home/components/detailsExpander/infoCard/index.ts new file mode 100644 index 000000000..f90900e68 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/infoCard/index.ts @@ -0,0 +1,5 @@ +import { InfoCard } from "./InfoCard"; + +export { + InfoCard + }; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerAdditionalLists.tsx b/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerAdditionalLists.tsx new file mode 100644 index 000000000..96cc74f85 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerAdditionalLists.tsx @@ -0,0 +1,20 @@ +import * as React from "react"; + +//interface IProps { +// name: string; +// additionalLists: IMaintainerAdditionalListDto[]; +//}; + +export const MaintainerAdditionalLists = (/*props: IProps*/) => +
    + { /*props.additionalLists && props.additionalLists.length > 0 + ?
    +

    More by {props.name}:

    +
      + {props.additionalLists.map( + (l: IMaintainerAdditionalListDto, i: number) =>
    • {l.name}
    • )} +
    + +
    + : null*/ } +
    ; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerInfoCard.tsx b/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerInfoCard.tsx new file mode 100644 index 000000000..c2315b1a6 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerInfoCard.tsx @@ -0,0 +1,23 @@ +import * as React from "react"; +import { IMaintainer } from "../../../interfaces"; +import { MaintainerAdditionalLists } from "./MaintainerAdditionalLists"; +import { MaintainerLinkButtonGroup } from "./MaintainerLinkButtonGroup"; + +interface IProps { + maintainer: IMaintainer; +}; + +export const MaintainerInfoCard = (props: IProps) => + props.maintainer.name + ?
    +
    +

    Maintained by {props.maintainer.name}

    +
    +
    + + +
    +
    +
    +
    + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerLinkButtonGroup.tsx b/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerLinkButtonGroup.tsx new file mode 100644 index 000000000..9bd900bef --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerLinkButtonGroup.tsx @@ -0,0 +1,16 @@ +import * as React from "react"; +import { EmailButton, HomeButton, TwitterButton } from "../../linkButtons"; + +interface IProps { + emailAddress: string; + homeUrl: string; + name: string; + twitterHandle: string; +}; + +export const MaintainerLinkButtonGroup = (props: IProps) => +
    + + + +
    ; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainersInfoCard.tsx b/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainersInfoCard.tsx new file mode 100644 index 000000000..cb95cbcf9 --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainersInfoCard.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; +import { IMaintainer } from "../../../interfaces"; +import { MaintainerInfoCard } from "./MaintainerInfoCard"; + +interface IProps { + maintainers: IMaintainer[]; +}; + +export const MaintainersInfoCard = (props: IProps) => + props.maintainers && props.maintainers.length > 0 + ?
    + {props.maintainers.map((m: IMaintainer, i: number) => )} +
    + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/index.ts b/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/index.ts new file mode 100644 index 000000000..03a112e6e --- /dev/null +++ b/src/web/src/modules/home/components/detailsExpander/maintainersInfoCard/index.ts @@ -0,0 +1,5 @@ +import { MaintainersInfoCard } from "./MaintainersInfoCard"; + +export { + MaintainersInfoCard + }; \ No newline at end of file diff --git a/src/web/src/modules/home/components/index.ts b/src/web/src/modules/home/components/index.ts new file mode 100644 index 000000000..180723286 --- /dev/null +++ b/src/web/src/modules/home/components/index.ts @@ -0,0 +1,9 @@ +import { DetailsExpander } from "./detailsExpander"; +import { ListsTable } from "./listsTable"; +import { Oneliner } from "./Oneliner"; + +export { + DetailsExpander, + ListsTable, + Oneliner + }; \ No newline at end of file diff --git a/src/web/src/modules/home/components/linkButtons/ChatButton.tsx b/src/web/src/modules/home/components/linkButtons/ChatButton.tsx new file mode 100644 index 000000000..f04b23e12 --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/ChatButton.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; +import { LinkButton } from "./LinkButton"; + +interface IProps { + name: string; + url: string; +}; + +export const ChatButton = (props: IProps) => + props.url + ? + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/linkButtons/DonateButton.tsx b/src/web/src/modules/home/components/linkButtons/DonateButton.tsx new file mode 100644 index 000000000..03713ae48 --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/DonateButton.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; +import { LinkButton } from "./LinkButton"; + +interface IProps { + name: string; + url: string; +}; + +export const DonateButton = (props: IProps) => + props.url + ? + : null; diff --git a/src/web/src/modules/home/components/linkButtons/EmailButton.tsx b/src/web/src/modules/home/components/linkButtons/EmailButton.tsx new file mode 100644 index 000000000..edc8e9972 --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/EmailButton.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; +import { LinkButton } from "./LinkButton"; + +interface IProps { + name: string; + emailAddress: string; +}; + +export const EmailButton = (props: IProps) => + props.emailAddress + ? + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/linkButtons/ForumButton.tsx b/src/web/src/modules/home/components/linkButtons/ForumButton.tsx new file mode 100644 index 000000000..0bf0bacfc --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/ForumButton.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; +import { LinkButton } from "./LinkButton"; + +interface IProps { + name: string; + url: string; +}; + +export const ForumButton = (props: IProps) => + props.url + ? + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/linkButtons/HomeButton.tsx b/src/web/src/modules/home/components/linkButtons/HomeButton.tsx new file mode 100644 index 000000000..e1f40b366 --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/HomeButton.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; +import { LinkButton } from "./LinkButton"; + +interface IProps { + name: string; + url: string; +}; + +export const HomeButton = (props: IProps) => + props.url + ? + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/linkButtons/IssuesButton.tsx b/src/web/src/modules/home/components/linkButtons/IssuesButton.tsx new file mode 100644 index 000000000..038ab763f --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/IssuesButton.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; +import { LinkButton } from "./LinkButton"; + +interface IProps { + name: string; + url: string; +}; + +export const IssuesButton = (props: IProps) => + props.url + ? + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/linkButtons/LinkButton.tsx b/src/web/src/modules/home/components/linkButtons/LinkButton.tsx new file mode 100644 index 000000000..66af40654 --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/LinkButton.tsx @@ -0,0 +1,18 @@ +import * as React from "react"; +import "./button.css"; + +interface IProps { + href: string; + title?: string; + buttonClass?: string; + text: string; +}; + +export const LinkButton = (props: IProps) => + props.href + ? + {props.text} + + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/linkButtons/PolicyButton.tsx b/src/web/src/modules/home/components/linkButtons/PolicyButton.tsx new file mode 100644 index 000000000..60b87d795 --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/PolicyButton.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; +import { LinkButton } from "./LinkButton"; + +interface IProps { + name: string; + url: string; +}; + +export const PolicyButton = (props: IProps) => + props.url + ? + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/linkButtons/SubmitButton.tsx b/src/web/src/modules/home/components/linkButtons/SubmitButton.tsx new file mode 100644 index 000000000..e4baef971 --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/SubmitButton.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; +import { LinkButton } from "./LinkButton"; + +interface IProps { + name: string; + url: string; +}; + +export const SubmitButton = (props: IProps) => + props.url + ? + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/linkButtons/SubscribeButton.tsx b/src/web/src/modules/home/components/linkButtons/SubscribeButton.tsx new file mode 100644 index 000000000..f7f3d4c1b --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/SubscribeButton.tsx @@ -0,0 +1,62 @@ +import * as React from "react"; +import { LinkButton } from "./LinkButton"; + +interface IProps { + name: string; + url: string; + text?: string; +}; + +export const SubscribeButton = (props: IProps) => { + let buttonClass: string | undefined; + let titlePrefix: string; + + if (props.url.indexOf(".onion/") > 0) { + buttonClass = "btn-success"; + titlePrefix = "Tor address - "; + } else if (props.url.indexOf("http://") === 0) { + buttonClass = "btn-danger"; + titlePrefix = "Not Secure - "; + } else { + buttonClass = undefined; + titlePrefix = ""; + } + + const hrefTitle = `${encodeURIComponent(props.name)}`; + let href; +if (props.url.indexOf(".tpl") > 0) +{ + href = `javascript:window.external.msAddTrackingProtectionList('${encodeURIComponent(props.url)}', '${hrefTitle}')`; +} else if (props.url.indexOf(".lsrules") > 0) +{ + href = `x-littlesnitch:subscribe-rules?url=${encodeURIComponent(props.url)}`; +} else if (props.url.indexOf("?hostformat=littlesnitch") > 0) +{ + href = `x-littlesnitch:subscribe-rules?url=${encodeURIComponent(props.url)}`; +} else { + href = `abp:subscribe?location=${encodeURIComponent(props.url)}&title=${hrefTitle}`; +}; + + + + let title; +if (props.url.indexOf(".tpl") > 0) +{ + title = `${titlePrefix}Subscribe to ${props.name} with Internet Explorer's Tracking Protection List feature.`; +} else if (props.url.indexOf(".lsrules") > 0) +{ + title = `${titlePrefix}Subscribe to ${props.name} with Little Snitch's rule group subscription feature.`; +} else if (props.url.indexOf("?hostformat=littlesnitch") > 0) +{ + title = `${titlePrefix}Subscribe to ${props.name} with Little Snitch's rule group subscription feature.`; +} else { + title = `${titlePrefix}Subscribe to ${props.name} with a browser extension supporting the \"abp:\" protocol (e.g. uBlock Origin, Adblock Plus).`; +}; + + return props.url + ? + : null; +}; diff --git a/src/web/src/modules/home/components/linkButtons/SubscribeButtonGroup.tsx b/src/web/src/modules/home/components/linkButtons/SubscribeButtonGroup.tsx new file mode 100644 index 000000000..e6315284c --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/SubscribeButtonGroup.tsx @@ -0,0 +1,52 @@ +import * as React from "react"; +import { SubscribeButton } from "./SubscribeButton"; + +interface IProps { + name: string; + url: string; + urlMirrors?: string[]; +}; + +export const SubscribeButtonGroup = (props: IProps) => + props.url + ? (props.urlMirrors && props.urlMirrors.length > 0) + ? + : + : null; + +interface ISubscribeButtonGroupDropdownProps { + name: string; + url: string; + urlMirrors: string[]; +}; + +const SubscribeButtonGroupDropdown = (props: ISubscribeButtonGroupDropdownProps) => { + let firstButtonText: string = "Original"; + let mirrorIndex: number = 0; + + if (props.url.indexOf("web.archive.org") !== -1) { + firstButtonText = "Mirror 1"; + mirrorIndex++; + } + + return
    + +
    + + {props.urlMirrors.map( + (m: string, i: number) => + )} +
    +
    ; +}; + +const BtnGroupDropSubscribe = () => + ; \ No newline at end of file diff --git a/src/web/src/modules/home/components/linkButtons/TwitterButton.tsx b/src/web/src/modules/home/components/linkButtons/TwitterButton.tsx new file mode 100644 index 000000000..8c7f7a71a --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/TwitterButton.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; +import { LinkButton } from "./LinkButton"; + +interface IProps { + name: string; + twitterHandle: string; +}; + +export const TwitterButton = (props: IProps) => + props.twitterHandle + ? + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/linkButtons/ViewButton.tsx b/src/web/src/modules/home/components/linkButtons/ViewButton.tsx new file mode 100644 index 000000000..0e33dab9b --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/ViewButton.tsx @@ -0,0 +1,24 @@ +import * as React from "react"; +import { LinkButton } from "./LinkButton"; + +interface IProps { + name: string; + url: string; + text?: string; +}; + +export const ViewButton = (props: IProps) => { + + let title; + if (props.url.indexOf(".onion/") > 0) { title = `Tor address - View ${props.name} in its raw format.`; } + else if (props.url.indexOf(".zip") > 0) { title = `Download ${props.name} as a ZIP compressed archive.`; } + else if (props.url.indexOf(".7z") > 0) { title = `Download ${props.name} as a 7Z compressed archive.`; } + else if (props.url.indexOf(".tar.gz") > 0) { title = `Download ${props.name} as a compressed tarball archive.`; } + else { title = `View ${props.name} in its raw format`; }; + +return props.url + ? + : null; +} diff --git a/src/web/src/modules/home/components/linkButtons/ViewButtonGroup.tsx b/src/web/src/modules/home/components/linkButtons/ViewButtonGroup.tsx new file mode 100644 index 000000000..60669fa82 --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/ViewButtonGroup.tsx @@ -0,0 +1,51 @@ +import * as React from "react"; +import { ViewButton } from "./ViewButton"; + +interface IProps { + name: string; + url: string; + urlMirrors?: string[]; +}; + +export const ViewButtonGroup = (props: IProps) => + props.url + ? (props.urlMirrors && props.urlMirrors.length > 0) + ? + : + : null; + +interface IViewButtonGroupDropdownProps { + name: string; + url: string; + urlMirrors: string[]; +}; + +const ViewButtonGroupDropdown = (props: IViewButtonGroupDropdownProps) => { + let firstButtonText: string = "Original"; + let mirrorIndex: number = 0; + + if (props.url.indexOf("web.archive.org") !== -1) { + firstButtonText = "Mirror 1"; + mirrorIndex++; + } + + return
    + +
    + + {props.urlMirrors.map( + (m: string, i: number) => + )} +
    +
    ; +}; + +const BtnGroupDropView = () => + ; \ No newline at end of file diff --git a/src/web/src/modules/home/components/linkButtons/button.css b/src/web/src/modules/home/components/linkButtons/button.css new file mode 100644 index 000000000..bace69595 --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/button.css @@ -0,0 +1,11 @@ +.fl-btn-link { + margin-bottom: .2rem; + max-width: 100px; + width: 100px; +} + +.dropdown-menu { + border: 0; + min-width: 0; + padding: 0; +} \ No newline at end of file diff --git a/src/web/src/modules/home/components/linkButtons/index.ts b/src/web/src/modules/home/components/linkButtons/index.ts new file mode 100644 index 000000000..c0525f2df --- /dev/null +++ b/src/web/src/modules/home/components/linkButtons/index.ts @@ -0,0 +1,25 @@ +import { ChatButton } from "./ChatButton"; +import { DonateButton } from "./DonateButton"; +import { EmailButton } from "./EmailButton"; +import { ForumButton } from "./ForumButton"; +import { HomeButton } from "./HomeButton"; +import { IssuesButton } from "./IssuesButton"; +import { PolicyButton } from "./PolicyButton"; +import { SubmitButton } from "./SubmitButton"; +import { SubscribeButtonGroup } from "./SubscribeButtonGroup"; +import { TwitterButton } from "./TwitterButton"; +import { ViewButtonGroup } from "./ViewButtonGroup"; + +export { + ChatButton, + DonateButton, + EmailButton, + ForumButton, + HomeButton, + IssuesButton, + PolicyButton, + SubmitButton, + SubscribeButtonGroup, + TwitterButton, + ViewButtonGroup + }; \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/ListsTable.tsx b/src/web/src/modules/home/components/listsTable/ListsTable.tsx new file mode 100644 index 000000000..859673237 --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/ListsTable.tsx @@ -0,0 +1,104 @@ +import * as React from "react"; +import { IColumnVisibility, ILanguage, ILicense, IList, IMaintainer, ISoftware, ISyntax, ITag } from "../../interfaces"; +import "../../../../utils/loader.css"; +import ReactTable from "react-table"; +import "react-table/react-table.css"; +import "./listsTable.css"; +import { + DetailsButton, + Languages, + License, + Maintainers, + Name, + //RuleCount, + Software, + SubscribeButton, + Tags, + //UpdatedDate +} from "./columns"; +import { IListDetails } from "../../components/detailsExpander"; +import { DetailsExpander } from "../../components"; + +interface IProps { + languages: ILanguage[]; + licenses: ILicense[]; + lists: IList[]; + maintainers: IMaintainer[]; + software: ISoftware[]; + syntaxes: ISyntax[]; + tags: ITag[]; + columnVisibility: IColumnVisibility[]; + pageSize: number; +}; + +export const ListsTable = (props: IProps) => + props.languages.length > 0 && props.lists.length > 0 && props.software.length > 0 && props.tags.length > 0 + ? + } + className="-striped -highlight"/> + :
    Loading...
    ; + +interface ICreateListDtoProps { + list: IList; + languages: ILanguage[]; + licenses: ILicense[]; + maintainers: IMaintainer[]; + syntaxes: ISyntax[]; + tags: ITag[]; +}; + +const mapListDetails = (props: ICreateListDtoProps): IListDetails => +({ + id: props.list.id, + chatUrl: props.list.chatUrl, + description: props.list.description, + descriptionSourceUrl: props.list.descriptionSourceUrl, + donateUrl: props.list.donateUrl, + emailAddress: props.list.emailAddress, + forumUrl: props.list.forumUrl, + homeUrl: props.list.homeUrl, + issuesUrl: props.list.issuesUrl, + languages: props.list.languageIds + ? props.languages.filter((l: ILanguage) => props.list.languageIds.indexOf(l.id) > -1) + : undefined, + license: props.licenses.filter((l: ILicense) => props.list.licenseId === l.id)[0], + maintainers: props.list.maintainerIds + ? props.maintainers.filter((m: IMaintainer) => props.list.maintainerIds.indexOf(m.id) > -1) + : undefined, + name: props.list.name, + policyUrl: props.list.policyUrl, + publishedDate: props.list.publishedDate, + //ruleCount: props.list.ruleCount, + submissionUrl: props.list.submissionUrl, + syntax: props.syntaxes.filter((s: ISyntax) => props.list.syntaxId === s.id)[0], + tags: props.list.tagIds ? props.tags.filter((t: ITag) => props.list.tagIds.indexOf(t.id) > -1) : undefined, + //updatedDate: props.list.updatedDate, + viewUrl: props.list.viewUrl, + viewUrlMirrors: props.list.viewUrlMirrors +} as IListDetails); \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/columns/DetailsButton.tsx b/src/web/src/modules/home/components/listsTable/columns/DetailsButton.tsx new file mode 100644 index 000000000..7c7955fb6 --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/columns/DetailsButton.tsx @@ -0,0 +1,26 @@ +import * as React from "react"; +import { Column, RowRenderProps } from "react-table"; +import "../../linkButtons/button.css"; + +export const DetailsButton = { + Header: Details, + accessor: "id", + sortable: false, + expander: true, + Expander: ({ isExpanded, row }: RowRenderProps) => Expander({ isExpanded, row }), + style: { textAlign: "center" }, + width: 110 +} as Column; + +const Expander = (props: RowRenderProps) => +
    + {props.isExpanded + ? + : } +
    ; \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/columns/Languages.tsx b/src/web/src/modules/home/components/listsTable/columns/Languages.tsx new file mode 100644 index 000000000..828b2fd54 --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/columns/Languages.tsx @@ -0,0 +1,71 @@ +import * as React from "react"; +import { Column, Filter } from "react-table"; +import { IColumnVisibility, ILanguage } from "../../../interfaces"; + +export const Languages = (columnVisibility: IColumnVisibility[], languages: ILanguage[]) => { + const languagesSorted = languages.sort((a, b) => a.name.localeCompare(b.name)); + return ({ + Header: Languages, + accessor: "languageIds", + filterable: true, + filterMethod: (f: Filter, r: any[]) => filterMethod(f, r), + Filter: ({ onChange, filter }: any) => Filter({ onChange, filter }, languagesSorted), + sortMethod: (a: number[], b: number[]) => sortMethod(a, b, languagesSorted), + Cell: (c: any) => Cell(c.value, languagesSorted), + style: { whiteSpace: "inherit" }, + width: 95, + show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Languages")[0].visible + } as Column); +}; + +const filterMethod = (f: Filter, r: any[]): boolean => { + const listLanguageIds = r[f.id as any]; + return f.value === "any" || + (listLanguageIds + ? listLanguageIds.join(",").split(",").includes(f.value) + : f.value === "none"); +}; + +const Filter = (props: any, languages: ILanguage[]) => + ; + +const sortMethod = (a: number[], b: number[], languages: ILanguage[]) => { + if (a && a.length > 0) { + if (b && b.length > 0) { + const aLanguageNames = + languages.filter((l: ILanguage) => a.indexOf(l.id) > -1).map((l: ILanguage) => l.name).join(); + const bLanguageNames = + languages.filter((l: ILanguage) => b.indexOf(l.id) > -1).map((l: ILanguage) => l.name).join(); + return aLanguageNames.toLowerCase() > bLanguageNames.toLowerCase() ? 1 : -1; + } else { + return -1; + } + } else { + return 1; + } +}; + +const Cell = (languageIds: number[], languages: ILanguage[]) => + languageIds + ?
    + {languageIds.map((id: number, i: number) => { + const language = languages.filter((l: ILanguage) => l.id === id)[0]; + return + {language.iso6391} + ; + })} +
    + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/columns/License.tsx b/src/web/src/modules/home/components/listsTable/columns/License.tsx new file mode 100644 index 000000000..359e1e777 --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/columns/License.tsx @@ -0,0 +1,68 @@ +import * as React from "react"; +import { Column, Filter } from "react-table"; +import { IColumnVisibility, ILicense } from "../../../interfaces"; + +export const License = (columnVisibility: IColumnVisibility[], licenses: ILicense[]) => +({ + Header: License, + accessor: "licenseId", + filterable: true, + filterMethod: (f: Filter, r: any[]) => filterMethod(f, r, licenses), + Filter: ({ filter, onChange }: any) => Filter({ onChange, filter }, licenses), + sortMethod: (a: number, b: number) => sortMethod(a, b, licenses), + Cell: (c: any) => Cell(c.value, licenses), + width: 75, + show: columnVisibility.filter((c: IColumnVisibility) => c.column === "License")[0].visible +} as Column); + +const filterMethod = (f: Filter, r: any[], licenses: ILicense[]): boolean => { + const listLicenseId: number = r[f.id as any]; + if (f.value === "any") { + return true; + } else if (listLicenseId) { + const licenseFiltered = licenses.filter((l: ILicense) => l.id === parseInt(f.value))[0]; + return listLicenseId === licenseFiltered.id; + } else { + return false; + } +}; + +const Filter = (props: any, licenses: ILicense[]) => + ; + +const sortMethod = (a: number, b: number, licenses: ILicense[]) => { + if (a) { + if (b) { + const aLicenseName = licenses.filter((l: ILicense) => l.id === a)[0].name.replace(/['"]+/g, ""); + const bLicenseName = licenses.filter((l: ILicense) => l.id === b)[0].name.replace(/['"]+/g, ""); + return aLicenseName.toLowerCase() > bLicenseName.toLowerCase() ? 1 : -1; + } else { + return -1; + } + } else { + return 1; + } +}; + +const Cell = (licenseId: number, licenses: ILicense[]) => { + const license = licenses.filter((l: ILicense) => licenseId === l.id)[0]; + return license + ?
    + + {license.descriptionUrl ? {license.name} : license.name} + +
    + : null; +}; \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/columns/Maintainers.tsx b/src/web/src/modules/home/components/listsTable/columns/Maintainers.tsx new file mode 100644 index 000000000..2476f84e2 --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/columns/Maintainers.tsx @@ -0,0 +1,68 @@ +import * as React from "react"; +import { Column, Filter } from "react-table"; +import { IColumnVisibility, IMaintainer } from "../../../interfaces"; + +export const Maintainers = (columnVisibility: IColumnVisibility[], maintainers: IMaintainer[]) => +({ + Header: Maintainers, + accessor: "maintainerIds", + filterable: true, + filterMethod: (f: Filter, r: any[]) => filterMethod(f, r, maintainers), + Filter: ({ filter, onChange }: any) => Filter({ onChange, filter }, maintainers), + sortMethod: (a: number[], b: number[]) => sortMethod(a, b, maintainers), + Cell: (c: any) => Cell(c.value, maintainers), + width: 140, + show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Maintainers")[0].visible +} as Column); + +const filterMethod = (f: Filter, r: any[], maintainers: IMaintainer[]): boolean => { + const listMaintainerIds: number[] = r[f.id as any]; + return f.value === "any" || + (listMaintainerIds + ? f.value === "none" + ? false + : listMaintainerIds.indexOf(maintainers.filter((m: IMaintainer) => m.id === parseInt(f.value))[0].id) > -1 + : f.value === "none"); +}; + +const Filter = (props: any, maintainers: IMaintainer[]) => + ; + +const sortMethod = (a: number[], b: number[], maintainers: IMaintainer[]) => { + if (a && a.length > 0) { + if (b && b.length > 0) { + const aFirstMaintainerName = maintainers.filter((m: IMaintainer) => m.id === a[0])[0].name; + const bFirstMaintainerName = maintainers.filter((m: IMaintainer) => m.id === b[0])[0].name; + return aFirstMaintainerName.toLowerCase() > bFirstMaintainerName.toLowerCase() ? 1 : -1; + } else { + return -1; + } + } else { + return 1; + } +}; + +const Cell = (maintainerIds: number[], maintainers: IMaintainer[]) => + maintainerIds + ?
    + {maintainers.filter((m: IMaintainer) => maintainerIds.indexOf(m.id) > -1) + .map((m: IMaintainer, i: number) => { + return m.homeUrl + ? {m.name} + : {m.name}; + }).reduce(((prev: JSX.Element, curr: JSX.Element): any => [prev, ", ", curr]) as any)} +
    + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/columns/Name.tsx b/src/web/src/modules/home/components/listsTable/columns/Name.tsx new file mode 100644 index 000000000..12ad09716 --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/columns/Name.tsx @@ -0,0 +1,22 @@ +import * as React from "react"; +import { Column, Filter } from "react-table"; + +export const Name = { + Header: Name, + accessor: "name", + filterable: true, + filterMethod: (f: Filter, r: any[]) => filterMethod(f, r), + sortMethod: (a: string, b: string) => sortMethod(a, b), + Cell: (c: any) => Cell(c.value) +} as Column; + +const filterMethod = (f: Filter, r: any[]): boolean => + r[f.id as any].toUpperCase().includes(f.value.toUpperCase()); + +const sortMethod = (a: string, b: string) => + a.toLowerCase() > b.toLowerCase() ? 1 : -1; + +const Cell = (name: string) => + name + ?

    {name}

    + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/columns/RuleCount.tsx b/src/web/src/modules/home/components/listsTable/columns/RuleCount.tsx new file mode 100644 index 000000000..33689baa9 --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/columns/RuleCount.tsx @@ -0,0 +1,28 @@ +import * as React from "react"; +import { Column } from "react-table"; +import { IColumnVisibility } from "../../../interfaces"; + +export const RuleCount = (columnVisibility: IColumnVisibility[]) => +({ + Header: Rules, + accessor: "ruleCount", + sortMethod: (a: string, b: string) => sortMethod(a, b), + Cell: (c: any) => Cell(c.value), + style: { whiteSpace: "inherit" }, + width: 85, + show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Rules")[0].visible +} as Column); + +const sortMethod = (a: string, b: string) => + a + ? b + ? a > b + ? -1 + : 1 + : -1 + : 1; + +const Cell = (ruleCount: number) => + ruleCount + ? { ruleCount.toLocaleString() } + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/columns/Software.tsx b/src/web/src/modules/home/components/listsTable/columns/Software.tsx new file mode 100644 index 000000000..485af2731 --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/columns/Software.tsx @@ -0,0 +1,74 @@ +import * as React from "react"; +import { Column, Filter } from "react-table"; +import { IColumnVisibility, ISoftware } from "../../../interfaces"; +import { SoftwareIcon } from "../../softwareIcon"; + +export const Software = (columnVisibility: IColumnVisibility[], software: ISoftware[]) => { + const softwareSorted = software.sort((a, b) => a.name.localeCompare(b.name)); + return ({ + Header: + Software, + accessor: "syntaxId", + filterable: true, + filterMethod: (f: Filter, r: any[]) => filterMethod(f, r, softwareSorted), + Filter: ({ filter, onChange }: any) => Filter({ onChange, filter }, softwareSorted), + sortMethod: (a: number, b: number) => sortMethod(a, b, softwareSorted), + Cell: (c: any) => Cell(c.value, software), + width: 155, + show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Software")[0].visible + } as Column); +}; + +const filterMethod = (f: Filter, r: any[], software: ISoftware[]): boolean => { + const isAny = f.value === "any"; + const softwareFiltered = isAny ? software : software.filter((s: ISoftware) => s.id === parseInt(f.value)); + const listSyntaxId: number = r[f.id as any]; + const isMatch = softwareFiltered[0].syntaxIds ? softwareFiltered[0].syntaxIds.indexOf(listSyntaxId) > -1 : false; + return isAny || (listSyntaxId ? isMatch : false); +}; + +const Filter = (props: any, software: ISoftware[]) => + ; + +const sortMethod = (a: number, b: number, software: ISoftware[]) => { + if (a) { + if (b) { + const aSoftwareNames = + software.filter((s: ISoftware) => s.syntaxIds.indexOf(a) > -1).map((s: ISoftware) => s.name); + const bSoftwareNames = + software.filter((s: ISoftware) => s.syntaxIds.indexOf(b) > -1).map((s: ISoftware) => s.name); + if (aSoftwareNames.length === bSoftwareNames.length) { + return aSoftwareNames.join().toLowerCase() > bSoftwareNames.join().toLowerCase() ? 1 : -1; + } else if (aSoftwareNames.length > bSoftwareNames.length) { + return -1; + } else { + return 1; + } + } else { + return -1; + } + } else { + return 1; + } +}; + +const Cell = (listSyntaxId: number, software: ISoftware[]) => + listSyntaxId + ?
    + {software.filter((s: ISoftware) => s.syntaxIds.indexOf(listSyntaxId) > -1) + .map((s: ISoftware, i: number) => + s.homeUrl + ? + + + : )} +
    + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/columns/SubscribeButton.tsx b/src/web/src/modules/home/components/listsTable/columns/SubscribeButton.tsx new file mode 100644 index 000000000..2df9408e2 --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/columns/SubscribeButton.tsx @@ -0,0 +1,24 @@ +import * as React from "react"; +import { Column, Filter } from "react-table"; +import { IColumnVisibility } from "../../../interfaces"; +import { SubscribeButtonGroup } from "../../linkButtons"; + +export const SubscribeButton = (columnVisibility: IColumnVisibility[]) => ({ + Header: + Subscribe + , + accessor: "viewUrl", + filterable: true, + filterMethod: (f: Filter, r: any[]) => filterMethod(f, r), + sortMethod: (a: string, b: string) => sortMethod(a, b), + Cell: (c: any) => , + style: { textAlign: "center" }, + width: 110, + show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Subscribe")[0].visible +} as Column); + +const filterMethod = (f: Filter, r: any[]): boolean => + r[f.id as any].toUpperCase().includes(f.value.toUpperCase()); + +const sortMethod = (a: string, b: string) => + a.toLowerCase() > b.toLowerCase() ? 1 : -1; \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/columns/Syntax.tsx b/src/web/src/modules/home/components/listsTable/columns/Syntax.tsx new file mode 100644 index 000000000..25f9ff832 --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/columns/Syntax.tsx @@ -0,0 +1,46 @@ +import * as React from "react"; +import { Column, Filter } from "react-table"; +import { IColumnVisibility, ISyntax } from "../../../interfaces"; + +//TODO: https://github.com/collinbarrett/FilterLists/issues/488 +export const Syntax = (columnVisibility: IColumnVisibility[], syntaxes: ISyntax[]) => ({ + Header: Syntax, + accessor: "syntaxId", + filterable: true, + filterMethod: (f: Filter, r: any[]) => filterMethod(f, r, syntaxes), + Filter: ({ filter, onChange }: any) => Filter({ onChange, filter }, syntaxes), + Cell: (c: any) => Cell(c.value, syntaxes), + width: 155, + show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Syntax")[0].visible +} as Column); + +const filterMethod = (f: Filter, r: any[], syntaxes: ISyntax[]): boolean => { + const listSyntaxId: number = r[f.id as any]; + if (f.value === "any") { + return true; + } else if (listSyntaxId) { + const syntaxFiltered = syntaxes.filter((s: ISyntax) => s.id === parseInt(f.value)); + return syntaxFiltered[0].id + ? syntaxFiltered[0].id === listSyntaxId + : false; + } else { + return false; + } +}; + +const Filter = (props: any, syntaxes: ISyntax[]) => + ; + +const Cell = (listSyntaxId: number, syntaxes: ISyntax[]) => + listSyntaxId + ? syntaxes.filter((s: ISyntax) => s.id === listSyntaxId)[0].name + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/columns/Tags.tsx b/src/web/src/modules/home/components/listsTable/columns/Tags.tsx new file mode 100644 index 000000000..2031860dc --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/columns/Tags.tsx @@ -0,0 +1,63 @@ +import * as React from "react"; +import { Column, Filter } from "react-table"; +import { TagGroup } from "../../TagGroup"; +import { IColumnVisibility, ITag } from "../../../interfaces"; + +export const Tags = (columnVisibility: IColumnVisibility[], tags: ITag[]) => { + const tagsSorted = tags.sort((a: ITag, b: ITag) => a.name.localeCompare(b.name)); + return ({ + Header: + Tags, + accessor: "tagIds", + filterable: true, + filterMethod: (f: Filter, r: any[]) => filterMethod(f, r), + Filter: ({ onChange, filter }: any) => Filter({ onChange, filter }, tagsSorted), + sortMethod: (a: number[], b: number[]) => sortMethod(a, b, tagsSorted), + Cell: (c: any) => Cell(c.value, tagsSorted), + width: 260, + show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Tags")[0].visible + } as Column); +}; + +const filterMethod = (f: Filter, r: any[]): boolean => { + const listTagIds = r[f.id as any]; + return f.value === "any" || + (listTagIds + ? listTagIds.join(",").split(",").includes(f.value) + : f.value === "none"); +}; + +const Filter = (props: any, tags: ITag[]) => + ; + +const sortMethod = (a: number[], b: number[], tags: ITag[]): any => { + return a + ? b + ? a.length === b.length + ? tags.filter((t: ITag) => a.indexOf(t.id) > -1).map((t: ITag) => t.name).join() + .toLowerCase() > + tags.filter((t: ITag) => b.indexOf(t.id) > -1).map((t: ITag) => t.name).join().toLowerCase() + ? 1 + : -1 + : a.length > b.length + ? -1 + : 1 + : -1 + : 1; +}; + +const Cell = (tagIds: number[], tags: ITag[]) => + tagIds + ? tagIds.indexOf(t.id) > -1)}/> + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/columns/UpdatedDate.tsx b/src/web/src/modules/home/components/listsTable/columns/UpdatedDate.tsx new file mode 100644 index 000000000..0542a50cf --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/columns/UpdatedDate.tsx @@ -0,0 +1,33 @@ +import * as React from "react"; +import { Column } from "react-table"; +import * as moment from "moment"; +import { IColumnVisibility } from "../../../interfaces"; + +export const UpdatedDate = (columnVisibility: IColumnVisibility[]) => +({ + Header: Updated, + accessor: "updatedDate", + sortMethod: (a: string, b: string) => sortMethod(a, b), + Cell: (c: any) => Cell(c.value), + style: { whiteSpace: "inherit" }, + width: 100, + show: columnVisibility.filter((c: IColumnVisibility) => c.column === "Updated")[0].visible +} as Column); + +const sortMethod = (a: string, b: string) => + a && moment(a).isValid() + ? (b && moment(b).isValid() + ? (moment(a).isBefore(b) + ? 1 + : -1) + : -1) + : 1; + +const Cell = (updatedDate: string) => + updatedDate + ?
    + {moment(updatedDate).isValid() + ? moment(updatedDate).format("l") + : null} +
    + : null; \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/columns/index.ts b/src/web/src/modules/home/components/listsTable/columns/index.ts new file mode 100644 index 000000000..050780af2 --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/columns/index.ts @@ -0,0 +1,25 @@ +import { DetailsButton } from "./DetailsButton"; +import { Languages } from "./Languages"; +import { License } from "./License"; +import { Maintainers } from "./Maintainers"; +import { Name } from "./Name"; +import { RuleCount } from "./RuleCount"; +import { Software } from "./Software"; +import { SubscribeButton } from "./SubscribeButton"; +import { Syntax } from "./Syntax"; +import { Tags } from "./Tags"; +import { UpdatedDate } from "./UpdatedDate"; + +export { + DetailsButton, + Languages, + License, + Maintainers, + Name, + RuleCount, + Software, + SubscribeButton, + Syntax, + Tags, + UpdatedDate + }; \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/index.ts b/src/web/src/modules/home/components/listsTable/index.ts new file mode 100644 index 000000000..48483597b --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/index.ts @@ -0,0 +1,5 @@ +import { ListsTable } from "./ListsTable"; + +export { + ListsTable, + }; \ No newline at end of file diff --git a/src/web/src/modules/home/components/listsTable/listsTable.css b/src/web/src/modules/home/components/listsTable/listsTable.css new file mode 100644 index 000000000..0436aa6bf --- /dev/null +++ b/src/web/src/modules/home/components/listsTable/listsTable.css @@ -0,0 +1,13 @@ +.rt-tr { + -ms-align-items: center; + -o-align-items: center; + -webkit-align-items: center; + align-items: center; +} + +div.rt-tbody, div.rt-thead.-filters, div.rt-thead.-header { min-width: 320px !important; } + +.fl-wrap-cell { + line-height: 1; + white-space: normal; +} \ No newline at end of file diff --git a/src/web/src/modules/home/components/softwareIcon/SoftwareIcon.tsx b/src/web/src/modules/home/components/softwareIcon/SoftwareIcon.tsx new file mode 100644 index 000000000..03aff3b5d --- /dev/null +++ b/src/web/src/modules/home/components/softwareIcon/SoftwareIcon.tsx @@ -0,0 +1,89 @@ +import * as React from "react"; +import { + img1, + img2, + img3, + img4, + img5, + img6, + img7, + img8, + img10, + img11, + img12, + img13, + img14, + img15, + img16, + img17, + img18, + img19, + img20, + img21, + img22, + img23, + img24, + img25, + img26, + img27, + img28, + img29, + img30, + img31, + img32, + img33, + img34 +} from "./imgs"; + +interface IProps { + id: number; +}; + +export const SoftwareIcon = (props: IProps) => + icons[props.id] + ? {icons[props.id].imageTitle} + : null; + +interface IIcon { + image: any; + imageTitle: string; +}; + +const icons: { [id: number]: IIcon; } = { + 1: { image: img1, imageTitle: "uBlock Origin" }, + 2: { image: img2, imageTitle: "Adblock Plus" }, + 3: { image: img3, imageTitle: "AdGuard" }, + 4: { image: img4, imageTitle: "DNS66" }, + 5: { image: img5, imageTitle: "Nano Adblocker" }, + 6: { image: img6, imageTitle: "AdBlock" }, + 7: { image: img7, imageTitle: "AdAway" }, + 8: { image: img8, imageTitle: "Personal Blocklist" }, + 10: { image: img10, imageTitle: "Redirector" }, + 11: { image: img11, imageTitle: "Hosts File Editor" }, + 12: { image: img12, imageTitle: "Gas Mask" }, + 13: { image: img13, imageTitle: "MinerBlock" }, + 14: { image: img14, imageTitle: "Pi-hole" }, + 15: { image: img15, imageTitle: "uBlock" }, + 16: { image: img16, imageTitle: "Internet Explorer (TPL)" }, + 17: { image: img17, imageTitle: "Google Hit Hider by Domain" }, + 18: { image: img18, imageTitle: "FireHOL" }, + 19: { image: img19, imageTitle: "Samsung Knox" }, + 20: { image: img20, imageTitle: "Little Snitch" }, + 21: { image: img21, imageTitle: "Privoxy" }, + 22: { image: img22, imageTitle: "Diversion" }, + 23: { image: img23, imageTitle: "dnsmasq" }, + 24: { image: img24, imageTitle: "Slimjet" }, + 25: { image: img25, imageTitle: "uMatrix" }, + 26: { image: img26, imageTitle: "Blokada" }, + 27: { image: img27, imageTitle: "hostsmgr" }, + 28: { image: img28, imageTitle: "personalDNSfilter" }, + 29: { image: img29, imageTitle: "Unbound" }, + 30: { image: img30, imageTitle: "BIND" }, + 31: { image: img31, imageTitle: "AdGuard Home" }, + 32: { image: img32, imageTitle: "AdNauseam" }, + 33: { image: img33, imageTitle: "Legacy Unix derivatives" }, + 34: { image: img34, imageTitle: "Windows command line" }, +}; diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/01-uBlock-Origin.svg b/src/web/src/modules/home/components/softwareIcon/imgs/01-uBlock-Origin.svg new file mode 100644 index 000000000..03e7a9ebb --- /dev/null +++ b/src/web/src/modules/home/components/softwareIcon/imgs/01-uBlock-Origin.svg @@ -0,0 +1 @@ + diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/02-Adblock-Plus.svg b/src/web/src/modules/home/components/softwareIcon/imgs/02-Adblock-Plus.svg new file mode 100644 index 000000000..71ab1252f --- /dev/null +++ b/src/web/src/modules/home/components/softwareIcon/imgs/02-Adblock-Plus.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/03-AdGuard.png b/src/web/src/modules/home/components/softwareIcon/imgs/03-AdGuard.png new file mode 100644 index 0000000000000000000000000000000000000000..61471018cc3319f632d898e32669e1ad3e352168 GIT binary patch literal 893 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc3?z4jzqMyzU_2Dy6XNQVS(v`3Fl}=Mh}?uu zA_O;9Wb7?U+Xz;$u_A3_B~S_^3uXXG2qR+;Pz{ugEQ`#>RDdjt%tlcObm6WdWLZo$ z#0@}kh!lhiC*iUvjNM=dLp%=lOUj1wlnoWB8!A#ZmZgGyn!2eR7&6&gYEyUTrS8s8 z13F_@QSR3Iv_1LhyNmL+HUO;y22SSQ;)3msS$j*f_m!6HXvsfNS#Y4La#v^N?vAGY z6YGz)wH}<(bfT;C^o0InbEjUIJ?HYGMORm@xVd)qtqtpLZ{B=w$Ci6L_uM^l`pLx; z&(B#O(QKD_(>{`1c-Uw?i5^Y8D!fB*jf|3B@= z@gu-UjV=lD3ua(sVrF4sWn*XO;NcaOkdRhXR8rG7a&&QX_X-ROjfjX!Ov%bGC@Lwf zs&43>G8wmbqR8h%d~#}Exs)`PeEE(I_!9I$*YvgXdF19?Xz_qeYA&)pxZPRd!k&YW{9A~Z%$eX{4|UiRBp zwZ9$Tp`D?-`dq;elUw;kBJFD`S6a=wzi|GitZLsi|6~_`m3P```E}h>vxk+sD{to; zZOqu-^<3t)K6j_Lo!Z+_!L-d$k80$;1l$$gR~t34V8?f>BV`GOe>+*)FPv`Gi8!~< z+@s*`+|PL@4*mK3hlSH*wifT^mnC&V}s`A;IDZ-zDF~H#I>gTe~ HDWM4f$?eZ? literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/03-AdGuard.svg b/src/web/src/modules/home/components/softwareIcon/imgs/03-AdGuard.svg new file mode 100644 index 000000000..b9cb8ebd4 --- /dev/null +++ b/src/web/src/modules/home/components/softwareIcon/imgs/03-AdGuard.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/04-DNS66.png b/src/web/src/modules/home/components/softwareIcon/imgs/04-DNS66.png new file mode 100644 index 0000000000000000000000000000000000000000..a32dc2c2f3c759927816550cd39690ee71e80721 GIT binary patch literal 851 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc3?z4jzqMyzU|b&H6XNQVS;#Q0gJF6nh@9CC zB7q19APgWmwVh!~8$*8+LwqPhZ6QNfEyJW11~Ws32~7;){vcV9UND*t*4tdp&{W9~ z;=|Bd$>3ze5a7wsR>?5AmBG~xWM*|f15kmdBSTF-gQFGHaG-2oBS^NPgrO>zAvuB} zDT1M=9waic1!NJB0aOpPD>@Kl6i_h`0Too{GIZ2{oClNwayzOSGU7mNpn9OCKyq>$ zNEYILpiw{(ARFj@AOoZflmhY`D|Mwvt)+V`lZUtX7kLOsJUV;^Q_+3J)8Zu zt!19w%QCx9V8LYexf8Tj&U4z61ko5en-pJVQX=slZP`7uiZBPFOL$S;`T zkKRM(iC5STEPL|z&r|EZ(;wwu*mO`tZ;F*RqL8b#`#FXm-n@T%+!TYT}^si_^)R|cKv=t$uT z4Lh^xs)+yGiTn&2*8_ug1u+a_YJo> zqm<-P9oIT%{_Fn^f0f<-{K>hmt|kqVzY1IB*Ej8+r~Cio%eSAGyZnt<_Wr@@*N z@2*tnN_z2lE}Nmf=H9#PHSX`GZsnc-{nN|Vs$&MGjy;0@J%;nrk4StiP2OW%8x*a7 zA!K^i*Ru?(yuO@Vwtfv`Lz9#9A)d;k7hj)R)vM!mCL&P8dW!K(-LlnJ^9*P2IP&#D gPTw`L_P6u@F?1^>C_b_&i~(f?Pgg&ebxsLQ0Nk8urT_o{ literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/05-Nano-Adblocker.png b/src/web/src/modules/home/components/softwareIcon/imgs/05-Nano-Adblocker.png new file mode 100644 index 0000000000000000000000000000000000000000..cd2b2a06d82f444b7bfd2e2df40b0bd2f93597f2 GIT binary patch literal 698 zcmV;r0!96aP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0#8XqK~y+Tm6Y2{ zR8bVhXCe^FATndDA)JelnNgk+AG9QC9-Jtli(TwNDta(_P%AIPHF)_Nrn`p#0?_lq5XX{x#<~6U(A&kDU8+_OC*{{1?unMlT6_!iv1k}=Hc?oywpgoFa&hHiF6FS znt$pv0p&%9(R#s$kt;V)oR^O?o_%=V+#b17)<~@|1mwS4UJdkfJIXM{)f8lIhvsy{ znQTLT##SUJu0rjRl1LD1q*fSQsZd{q<(I<#6F^N6*50iUt~g5W=SQcHAthF!I!$^A}-XlY|c~50?a)j(@Ui0H-}( z1bp>sYoi!y^dmPt10Tad{~Z6KALI|h!cR!v&8K^vn3by|p2!cfK|rxzkzPKC+nKu} zI~?wD)?TGj1tbyIr4eQ1 zK@6t#iM8k?{-K5tOEhXxp%fLB0ttC5UNk9+* z!ypiw&2BKjCX>@@byzGwgCM4+P@4^!n1Dd5*AuO+L_>o^BEe6cLhI__swyx+YHJ-e zHAG8`qpHf)*a%4^m{yDQ_S(C;;M=#MTel#E0#&JA%jIZK528|`N+kwbg`$7?@BCg&T^4I3G;|~^>@kaFrqNzSMD%gFCOUnB$+XewRtDn@oo){ge-IS~hlfux zm~WU&n9hJ03=^9TF`1)WF3e=!;qxEG#5h zaJdkVcPBB?!Q%1V= z$C9zJ4|8%zKHnpVBL#wKLEQ9)4Ucnkeev;6^73A8+2Tt`m`P0ZCMC^m+<333$eWTf zo0Q~9O?|d~`)qQuCoRpJmgY}MA=A_Ssi}d~G%_P2ke=?#%nW8^OlM^UGc$dgvmJSP zGuhex>}($pd3mmafF4bau|(xCzcQ zrdIpqa&RoWQaPs4Al=<2jYfa}KBiXVYIU%?8`WrnJw3QqYaSSI3=9PN`d*KZL*wI~ zkr7y@Lx9%nfk~WtJ!~*Ij7G?0n%3zcv)QNDBW5$O6JoJ=jYeQC%xcB0))|utvDr7(uvP z3ke7Sce_2HxEDZpJOoLqlCf;?84|u1i;5|3;cac_q*7^nd;9rLfE&SJ@a_Nj z2Vnj`B-j7Iqfiz}3b$=7sWQa0Jr{(05iwxRAheUg-iqHgJs2t&Y#D5l$y~w-FI)dt z{rV^4xv{15A<~CiyLT~^_j2h%UBc|}Rf)C2q6>YP*-TDf5xqE|T)L^c>B}+OgQUGO zXUCcH=2B_%8$7PPx$(ov(?1<9J*#rP)XU#)oGTkl=s0A#G&;%r^%J&$=sX)r(~JJR zbi{ilzAP|LeZuzLc`a?I~s1*RDYIHTlsV>N7W;- y>{}m@>T(_0fC7C7#fHK5j}nyT+mV%P<`%DbWxNqQI`j=VAf+&0w5=<*to~nN)ZktK literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/07-AdAway.png b/src/web/src/modules/home/components/softwareIcon/imgs/07-AdAway.png new file mode 100644 index 0000000000000000000000000000000000000000..0826b747828b5f5c68248b913283ca6b65ba2153 GIT binary patch literal 658 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc3?z4jzqMyzU^ETz332twEZi<40z^AuXosjM zVI(5*_Wj3qpT2At7Ty6w;^Mm$6yARL^!DTDoe~l|B_(&s$?cMt->s;)TSeveij~i= z-+1-(`RiA2-n@SM?(^5}0s=ckgm+3w?UIq%t*pF9LvxR&=3Z^>eR_KPjEwdf8y_$? zKVWHjz{cjFt?eO4rz2io$3w%8hlig`NI030crq#ZR7&cp)YQ{y>1T5D&K4G(D=s-# zT6VF%;bLRsx#pHDJ-t^aOu9OG%C#v|ug{oyW6s=LOP1bRy6pP$6?Zpmytirdy)9cG z?AiNZ&%Rp+4?o<0@bQV0k58R`dhWv0^B107x%TYp_2)Nly}0+_)uSh`pS^hU>dosH zuin1@@b2U1cOSpJ`}8$QwV@Cgj)EmYe!&ca!Xl#LQ>M+HyJXGJU%&tSW1eek3zYor z>EaloaX$6p(W1ivJZ_0sGw&SfoBd~!VwuG0Gc$~gjkmx5&k_6N)?1$~f6}&G5EK;5 zWVFzE8qXvJ@8NvEomm@l1t#|I=NCN7JPJ6AeG+4smvkB>L*J$v(_fRjh>iR3g- z$%KTjj~>4JmZp8%ymVJ^QUk+>6J=kIZP{WsG^*%(f3F*Pp_;+{7R z=oLv#h63?{eU8@o%(uyIbEd+<^GE)Ap4`%lb$ b|AW>2pQ_tNE&p&}Ffe$!`njxgN@xNAk|#v| literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/08-Personal-Blocklist.png b/src/web/src/modules/home/components/softwareIcon/imgs/08-Personal-Blocklist.png new file mode 100644 index 0000000000000000000000000000000000000000..9b6888a1b5f1716d987fa850f0aea972f8a17b66 GIT binary patch literal 1295 zcmV+q1@QWbP)xN#00093P)t-sOlfhN z006rs6TBr8xD*Px6$-v36SoHdx)=(%5(2&@6TKx9xe@`rB@?(21G^OjzaVR!PY~GR{>;&sa>uB@@FX6Vqs2&s9m&W?RD~6U|OQ!zB~M zB@@78t711db(kT_xDizf#71S#j*D4p*EEwD?7u_ot z<185DEEwf1809S(=PeoPEEnl580;(;?l2nfFdFeN8SgP0@-Z6oF&p(U8ul?7`7#^o zIVJ2lC;K!W{WKo@H6H9eD*HJi|2QK3IU~+YJ^wl*@k1{8LoMq}I`T_5-c?5VOE=(E zM*2%P@K8SNRYdJrN$p%r{aQx>Of_UzKbNza3@`HEyfpqPLd-{ZU`-FJ#i+}Nth4hYt`HzJ8 zkcRD-kNA{{{ga6EnUC?Bk?)(5{FjXIoRjLGm+POG_nVUToRa^Wko2LL{hpNdqM7)i znDC{Y`lFivqL}ojpZ}zq`lz4xtE2y^p!2S${;HwyvaA2Bqxi3<_Oh${v#kEKto69D z`nIt6xU%oPx9`5W^1Zn9y|?hcx%#`b`MkFGy|?ney7s=e`n|XFz`OCmy!^el`@XpM zz`Ojvxb(xl^2NaV!o2p!!Sl(*`NzWg$HMr?!}iI<@yyBe%*gf4$n?(1_0Y`r(9HGK z()ZTV^xN3?-P-rv+xOnv_~GC9gf9G>ig^I`|Rra?d<#Q>-z5O z`|j=f@9+EX@B8rY`|p>{QUp^{{R2~15NtL0000@bW%=J009IA z2M7ua4ips`8Xq4ePgz=BUteWqYHM{@C|(vH$=9aY;l$R45e%!98!&KpY3)-~I259U40g zgtSSiM1{i3!otA7z{teFXJBGw1lE2VU}a}VhzY5ns#QyDN)!_N?0Y}+JPZI>Q53~X zd}!*X1^@;i9nbdO%?14OxLj@=z<|NQ(eb#C3_Y>GZ_i5&j`ZNcd$OLmaZb^*AF7QU z(|d2C^Vj)gHC?yHKlxrO8tuI@+OU0{QO>;6=Jk9i@_Fp8Q9@Frq)l`oOs_=oyrsL7 z6S@&I(JJdhcyUR2uzo$!Znw{zY>#%VjX6D4(pBc6nx?Z@??3L0R0BF`tyEtYlY~>o zA1$lS%E(8t=dr$j3jn_}`t+|`U93c7HepC#4*{_8*{SIo+fZ$S)&3#^fd8zW4RTFQ zX|#1$e*oayX*61wirbK9VBPOU;(vYISY@iSh9NmzjgS*s2J{sYy}(=a)tQ|tf$002ovPDHLk FV1i*rzcl~= literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/10-Redirector.png b/src/web/src/modules/home/components/softwareIcon/imgs/10-Redirector.png new file mode 100644 index 0000000000000000000000000000000000000000..33fa33b018a4ded7f300ce79fd9a938722d52c81 GIT binary patch literal 547 zcmV+;0^I$HP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0k}y-K~y+TrPRqz z!ax`Y@FHF{dMRNkOChWR2NDkiLehkUc<4b>m*~M)@CkSXqZjuV;O2X9Byr>F77ZFM zibC-J)frQvmLmV;OEc5XkC{#fAs&ynLZMJwmgR{n5{a|~U_Fn=)AxG4lU5JtDS=(q z(Lps)SEI`3^IhZmhSD*#yTDEgg~GfJ(hP&a;7ulzSrA3hWmSH^-y0soEy7eXBd46jbgDVvD@ac0yRx@ zCK8D?z7eSRSS+@ys_G1TWH@%-A&!&=jH4eou6vbAWtQFk9XlZ6z;ahPijDdF6SWEI z!LvUzW$3;U#XDad3q%}1Ht_zxwPEM)i;~ah lm#`W47}uk*ykuE^{sKh}Al)HD?Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y9E;VFFSW*B01IkH6K~y+TjgxCklV=!)KlWow-2P0X%a*u> zjqISK+hk)N7dB0_v&=9+NynxO%y>WzZk#;O+0s%#DN==YJy4)fptL}RwiH?@S`bPR zkU+yuP$9SGb zJN$MLD)+C*SW<*0_z4TfJOtX3Wb}(N5ep z{}fp`(|VW)*W=oSc#Md*U{LfajOSu8sbs-%@iSPs>*@OSOP`~PmjSt~8u`46sgxXb z(Z+AY8;BZCJz388~1@nj(k`5=%s|Ox^ znWd1eOXWQOzi_H41Cy6OfnD$(?EH6^VJzMXxwa49#lJB&e;;a_8zP+(Coh}9RrSF* zJ;xFf7h_ zSY19S45N?UWC^#@!U^@aFr8itpEezL4VfX#>JLGpbwFdArYAFv`q4S;gRE;D9oO8j zjrq{y^wQ$p$7>|CaJ-I797l=9 z0hQ?nWSuSu8?Hi7KY*jcb}KC$Q|-f*yftKP65(x1hNpfHTJzpQuP`1OP67nvof>;5 z;hGJg)jo~03LCO7nP48CL*Li}Ip>it?Lj8DwUZXQlqoP5tVY+*>(E`qAS?4eT5_Xd z5yYXRkb#_1HF720FgV<(AyXYF)`QK}V$Z1tB{>9@?SH2xX0i@%yWzMWz3w*6EVAvy%5bTj(wfU-?DZ` f$!kmXrBKv=yHP=5KObGw00000NkvXXu0mjf^|AzZ literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/12-Gas-Mask.png b/src/web/src/modules/home/components/softwareIcon/imgs/12-Gas-Mask.png new file mode 100644 index 0000000000000000000000000000000000000000..062dcbd76c5fe62ea6c97a78261f27c00ee2109c GIT binary patch literal 424 zcmV;Z0ayNsP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0X<1XK~xwS1;MdP zlmP$-(D!*+CTWHcsMHPB(h)%s4&D}RLeS78IA{5XSa(Zd%%aL1;IfCn1;2D$0rdIm zqaJX>JD~2jAI<`Jr0u@K32(gthHcn43SeGzeYU1D1JtaD5BgEKXir2$Gy!gk(ie{{ zXo-l3(g*-gm7-FKi0In3stuu#7M%fr9s}lV zdE%K$M3klg0H`}}O+-Z3Gynjcvn3*8#|Qub)GRm<|9o>D007{m2bR4u3jYBg&xqv* S&-8Wx0000 + + + + + Created by potrace 1.15, written by Peter Selinger 2001-2017 + + + + + + + \ No newline at end of file diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/14-Pi-hole.png b/src/web/src/modules/home/components/softwareIcon/imgs/14-Pi-hole.png new file mode 100644 index 0000000000000000000000000000000000000000..99c6753a2473dd2491096686473afd82224f1cc6 GIT binary patch literal 700 zcmV;t0z>_YP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0#QjsK~y+Tjgrkv zR8bhlfA`Lv4ggT2(@Aiu8YI5!j}dwTwW~%1Q`}(uzJzR!E!bIyf20>S6OI)6Cu#p!lxeXo5- z=)mEB6>17q1zLly)9qij`<$r#&OVpbz{L_9M9{3PDAXJ}9cT+K$~Fv=yO{9;lA&+}B@O{V-``Cs{WTm8NoYsem8#J<3|)k2)l ze5Zmd9Pmp1RIVo%Ur9OpdJ8$W7wddl*Vp{;NxZOllfVs#z63k#Dl zDO1*SEoiX|&=x7}ZW$Mng>GHfHod7ZKBlt4tnIQ6kniW;6!J^`i`^ ictLy=XN7IjM(`WfNewVortex diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/15-uBlock.svg b/src/web/src/modules/home/components/softwareIcon/imgs/15-uBlock.svg new file mode 100644 index 000000000..6488ebb04 --- /dev/null +++ b/src/web/src/modules/home/components/softwareIcon/imgs/15-uBlock.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/16-Internet-Explorer-TPL.png b/src/web/src/modules/home/components/softwareIcon/imgs/16-Internet-Explorer-TPL.png new file mode 100644 index 0000000000000000000000000000000000000000..2b8189c8d61f672e43068f02c39c82882351d79f GIT binary patch literal 1056 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc3?z4jzqMyzVEi566XNQVStzmRy~OT!Aac)p z(TxwG+}&?Mj9p+7q5!5w0wM*I72Ea#s9kLPOPI!Y61(0=?0hY@4I~?hKOx`0u&V6_8h1NNJ8`iLq>G%ZLlto zcSJYb2Ppu#AM6;Adw_xuVSaf5(gk%7I2geJ0@4n&3mjZvV}UMw3K0Q&0Tez!agY>9 z*;|AmAofd;8lX84*8<%J3P5;J07Doo3l)Tg#?Ch&aZvaGRl)>8&VC;&8QBg@4J%55 z{DK*N?tK59=g<6OUnc$iwQ`>eF@ypYq+vQMLe z+p~_DBjo5QF5WqJ&);3fq;Zp9ykpX*)CiSD0kc*3g1Ez`XWfZ3@fU8D-h5=PScqPB zL^}K9RZ+*An)okHU;avSzWMsIm!D1Yco13)Ou9OrE{-7@=VSXXm$@*CI2-3IzjkF? z?rkvI{qxMa>f4#Scilf%=TX!U&$cYAY|VK+e?QYhhmCh_s`l8qtF)l7?$1)4=D#5# z8zPL4Kb-nPY0;BEZu|D^tXJ9L!CcuClzesbYw4yQPye2!E4S=ic&B5@)h{v)6Lvf? zc@|>Mv^7;yrJ9ZLhuYFfrn*U0opLKpm>=Y&IUQaW*6OtI#TtFpNR9(%+f7zxT^D;H zFfEdKCgUG>#tUg)L5t#-e08>KTl(mk!=Kc|J^oIY6g>893hL=C{=7kb_8ZmA7jOAf zj<<9D7k^wmdKI;Vst E06jV;wEzGB literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/16-Internet-Explorer-TPL.svg b/src/web/src/modules/home/components/softwareIcon/imgs/16-Internet-Explorer-TPL.svg new file mode 100644 index 000000000..69780795f --- /dev/null +++ b/src/web/src/modules/home/components/softwareIcon/imgs/16-Internet-Explorer-TPL.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/17-Google-Hit-Hider-by-Domain.png b/src/web/src/modules/home/components/softwareIcon/imgs/17-Google-Hit-Hider-by-Domain.png new file mode 100644 index 0000000000000000000000000000000000000000..ca830def3b20dc4ab04f8c43bb30bde507d3f790 GIT binary patch literal 636 zcmV-?0)zdDP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y9E;VFFSW*B00qsddK~y+T<&#ZIRZ$p)S2QzBksuHn6i$P} znFM7d1SS0dA@D~C4TL5aDVp>%q6l&5Aew|9w-5Wqo7tBjB7&%J3mx2^wa>ft+)Li3 zK?@dVpS{*zd++x>NB=pVO5N|IOABxb&Pk_3+Q&<&*V^;oS6G!!h1?7RE@N)Ihbs`{ z-H;MqNF4-Dd=HQL1I|nL(Ykz~uom!+HobzMA%T^U63`zkO7+)hAA%k;Ux%B7{tRmY z2Xf^Gr)c=3InXDAk666DTm)3{^rK&4T-z?@R+$@4K^biVyWpNr^cHf18rrBeu6uo5 z8fWcIzc-;>Ali;K=2GqAsyC=-|2^qg3TVY)fi&wl+Lt$+(i$5i+UusExhWkfq>RG? z!4W>CZuA*<*w<#9Lft?&iucFiJwThl1nPC}lQcxot#9FBqrAZmoDOS&zXfIxc!D}s zc$&+UA_doASPBp@&=Pq2nbb)GuCm$SpZ*F0ryS%pK570W5?OT3lZ;$hB%~p=bJ?PEVqr&&EnCUGQ1yWHOY%bw}8+$;;{Ny%3gv9@1}9 WS4!g$Nt%-Y0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0scuuK~y+Tjg&t~ zR$&yz4~Fmw72l#DX6WW%;G$??gXo}8i=v_pp^~W()X)%=qT=GHAU4(#IJoELKTvUP z2~sx^70mP#|75@C>%4TkUdaPL-uIsKoaf&6d@r9}7nf%DU=TK(_fYKR{|DkcXoVFx zhf7EMRcM1emtPHvxljY2;TVEJ9Mzr(3-ncKjxoyG z4v#^apg+f>MPF162cba2C)QH<3WqQbcVHR5!2>iOS%c9JcxV~35;mKW!V9>KcoL@B z*ZPn0i04_>XV3#dzlBGs1iCk0JoyWBPnuvCPGP`}>R?aLpnE2*dgkEIz2Z$ee|Up# z@DtE|Ibh&5Zd3^Kp!vOnte)Pntcij|J^b|I8k8UyV%@{2+BJ8fAId>DTw3)sWK9%2 zq+!8}`ee=KKD^}@sdtTx%HRWpW2q;dH3>mNLk`zKtIpmDl~4g4o{MVwy!~&G%m>Xt zqQDtwz(V_IP1<~K|2HT!f|{ZYNl4S^ZC8V04!nUANHP$rNt5Gk$$=mR!;pcviE<-w z{r^!k5X$T&Y(p^7Ub&RZZWc7?n3~zTqx~%}$HMG45Aeys#tXq^00000NkvXXu0mjf D*nAZX literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/19-Samsung-Knox.png b/src/web/src/modules/home/components/softwareIcon/imgs/19-Samsung-Knox.png new file mode 100644 index 0000000000000000000000000000000000000000..bdb2f96a10eb5df7bd0400fb6b05a171225a84b8 GIT binary patch literal 476 zcmV<20VDp2P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0dYx0K~y+Tom4?9 zL{StzgN;AHMrrPOBT5#squvjYmBze#&)CZkAcdKfWFt$8k|g;Dlg-Eu|ADZiD3%)M zzIU4U%)9S3eD&3IzVADI_w*WYLYZk$bOfkx!DFI6h7mm@Y7WZfUO;mI9O|66Skuu>mEs4xYJd&(Z9Qy92{|lo(iR?IhBbJ>IobR0~1$LI#?O(}Q&5UV!>pqA?UbrG428K47Ta zFHs18d-R_6Wi5!rU5VQ#>|}WI7MLxG+i#@q_T()n>N$y9&#cpvyI?#RlsLddb-?M# zJz}vs|BKEensC8IO6Zn~F71IP+u!(KXfrC9ir!cPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y9E-_;&oJ#-z1OZ7zK~y+TrIl+;TV)u>-;Sb*XtS7zOWYTA ziJ6*caM3y47r)FzKP*P#ZHmjB6DLN&FOuODU4kf)c^M;v1~%QLRBl1CPNZ&-Q7Qww z(sC(f6x#Kaw&&2&o?d9r-{)&J4OGabkDycd3YML>$@Ud3M*C6>j=u&T?)U|Y2)JQ8XoGwFi^`mI1FN5i9FWig%+{YAlJ zjjAg8rp-({-N}sJp@$%OyCKI`kxIx&hT0LI(?E7JB!aD26~mafPoVevN;K^+#+Q5V z@zmGXRo2!XdUe;Xsv=d#n5T=?i{q~$B}b6WWS}TnC}|(yT@S^}RCLHB7Lb(VkOF@E zY3|3#n#a-n4r@>~`FKvT`^EFmuBDSPDA_E?mPgnFTw%b13a|aI(@X|ysT5*T7;c*t z-Jh3aj=#$`sXE4l6S_|lf{ktz2eN4*10+0vy%2Da#Hqq-djaVEIcYYXKwJ!9&eDhe z>e~*gI>rK~^6perfRb7P(lOAx0QaZB2nj|Bs|v3zgu9w%l5~L>GIAJ_Zx;3wZ*-|T zrtyvZG?ae7`P7J8{C|mQIZnvEJF@mf$O(p1FDZ{oTDaV zQk+M2)dwX`H)^f9^aX{dNESebcI40;oFn~bR3Bp7%l3FHlkgH*Syz4!pV~~yO`VIyFIOk%T*m?_Z1Zt+s=3UV}cWMa0Y4f zA!Hk9=^I);OniF{rIF>%(u1`$JBt{}>=$}{59)Mxs=8b>WzRkHvdd~puXt^U8Y>X5 zp&#-=hU8}qsoFfe<~@EE?RXD-*7b)e_4dvkFK|a*buEQEx0UQQ8(SiRem8<2FoZv3 z5G(%)@9{H1|0V{FEh{fRy=6D;YV(SJr?6P7ee$Di8+yB**T~M@40C%J+;8P^QSG2! zC!JM2wV~&3t@a7pxuNXu@T=cm$k<~K-?6UhrF%7P`!;L(IK1XPIxFEb>g-L0|0Uc) i+^Rw@wvM<#82by_X+H8x#>0aE0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y9E-_;&oJ#-z1b0b9K~y+Tjg)&(RAm^(j|zw^1)G+`C1$`u z6NjiNbR2=h!rqF@E{J&9U0i`(7SJI}htkY~`a^THaT2E~!NxXQS(Vfj0~UjT72RYa4*wZ`^!P97AMLMy zYx^EcoxxlR}S(bI1i9K0&@7k9hFSlLL1asSR)I}9hiF9wq9`1dboy^6)4PH;O8uUE4$E0H1VQgq zFg`xQ8H`KxO}r16_J5N3DR^Uju{(q++=;^vhS{pUh*?*O zW$bAP{4^zmneU>Jt~3s(s0tdVMC*TqXx(Kbs>^VH(vIfNKTy*!$h)@b7J3KnVCvx% zzCHUZV$&)iT3?0ObPN1nEqO4{YnhCP4Gj$mijVYNly9zwXhSVT=~YP5e9Z&(g>{HY zyTCh|^SU4K`Bzu)aLNIt&VtyDHHh0(hu0FTAqY^NC!7akw>y{S?CuziSJxp<^%FrY zNZxGZfjRFs&;*sUyf)JayL}4V_O|h`cs2E?8?kVC@hF`-m}%)6O;GP>gILo*#d?C) zAz5p}1OW~2S?O5Sj~ut58ipMvOiw$oseoz(i_d5xTM@Xr)H!dyznHOD@8~za-45|) zE8;a&Br7w`{DgX3fHgSL}Tk6#A$wZ!6+xuUd0lT37*fqoWV4< zj^?O#c0;UfA!swi8O=~+nfVDPA2?{8=6!GSA#UBCfVpxI$vIac;Xzi2x3oZ#*@ocQ zQ}7goshAss_Y!p<*qqX=R!FGGft9+`{DfOS?4V#1Z!y0TfP1EixIV65N-%MDCjwR- zbGW%Jie{WnXXu{8H-=?83TL-NlGTP3T?Id3UQv&0@)=9C%>+tRNqBSok-0&&rg_NY=e{wKJM%`*Tw{r>AE1%_aIzR ziv@m(CkW`eG+J%ruWu+E7?m5kA=h^!#c;uO(0-B=j0f1FvccqI?x zM1MW^Lnj7zDhv7@ZyIb!D`O{d|zy#I^SFmgSHQeGu#V5EN7H@LUwLmoT%h zw2_gKXSaWP^W%7Z-?S`$0McB7QAlne2ygDW53<}os@cG1_2NbLl*7v}=_tj$U6g-_ zCiPmawkpF@ntxlPr3nliluU4W?ls8su0fP-LwIUEo{u;%;<<2jA;ko)^ixF8xtns0 zLccYpg23pCrVz>HiKTB?oT1VxXF$}+N#Tm3UT^=@gN*y)71Tc0mHHnd@SL!)Fb{zs ws1xF8}}l literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/22-Diversion.png b/src/web/src/modules/home/components/softwareIcon/imgs/22-Diversion.png new file mode 100644 index 0000000000000000000000000000000000000000..511c8c8cd4392e5a57dc3eb6c4eb4e1bf8bf60eb GIT binary patch literal 403 zcmeAS@N?(olHy`uVBq!ia0vp^d_XM1!3HGvvhwHvDaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheoCO|{#XwDmL74G){)!Z!1`SUa#}EtuWQNAptSmF`sZ+SbR;_R_n6Nj( zm)EEHX23?(tgLwnyb1>4K}Ni%R5V7<8}~FDot*Ym#(nI{NAr?{O|}OV4XN zE*)}WebFm2M@nBO>PT(*x12(Od;9C{xkDs)roDWTVvti%V9@^Q;e-GG|Hr(RmF=DW z@^yOihoxOy2kZa;D|A|_$Z*$ff!egEY;2Pk#8}MG*S^h@>U2Qh(hiT%Q2A3V&HulC z^_gvBlLM5D$jr%M144@9lBwRc3mh?NDJg!Njy<)qnwxMehO^Tt t;v%D-(gzXQ(_gPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y9E;VFFSW*B00)|OMK~y+TV;BXr0sl8i%Kh6SlKf?b!j#+H zmRqm3xgNdR>T(ps{=8ga>c4H`$=|j}$U~Lm2ER9px<8m?x&L5U$-fneEC0`lJn?@~ z%Gv*mQ-K&rFGx7^e@5W3|BJ$x{oj>c`0q}S<$-@&L_MI|5#ZlWaqidiw3cs5ZT&wh z^!Wd|(Wm~;jXL#z4hTmAam300vq3og6t9a*p=O|NBLG zz=r)l!@&A@vhjgwZfpKe4>;D>+o&THl_x$g$*#Eywa_j$c;kp0sPc%9Ff0Y&+!;kfnWz!tz{-5A-_fz~e$!3MeRF=miYj@lSBr?|Njh( zFXw2jY*w6vqM$}{#{V6O(O+N8(pdqtwBX-Xv3y|iShgc6>PrnU!jRQADop_zipz*AXh_$Z~~B;??AQxHj0Tug+>8Y00RR6Q6|QG T8_oU%00000NkvXXu0mjf*ou!v literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/24-Slimjet.png b/src/web/src/modules/home/components/softwareIcon/imgs/24-Slimjet.png new file mode 100644 index 0000000000000000000000000000000000000000..00f899268302075546918b1d7d73cc50995882a9 GIT binary patch literal 1419 zcmV;61$6p}P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y9E;VFFSW*B01pG-vK~y+Tjgx6mQ)d*0FUsaJ+R6{6#Gy1g^+oFCsg&pGG&?j`<7d_I4&THE)5Sk<{jV|aQ%`q1Rh z6xFYb%B+}49y?5A{SU1U$#jZLmwF{~)$07J_TN?dK6DL?!Z!K}mZ6uBH=2eS!iIt* zUhNt({olc}zKrnCl|BFHd#ETG^bQclK3S5^oBUw-jc~dVstfOc!4#H^r z4Xr&R$P{ae7l&PTu~Y0?c67SqQZL=-$8TcuNfx$6aj@ew7rSD3@S_QFujvW$)sIoz zIgAI!5ojL&3a#lmbUiQ7WFCPZmCGb4@2v0cNq1REfqO6m%R-r0buTwG-JfJE9)mu(o9$1yd0v%eU1x#KVxgzU0^9IQ2&#=pFE@Zj z78aB>auvGzt4zhqbW^%nL8Y^niRg?%_}gw*Y}^{^4ANC-YIR(xSb?0F%jt zmNo+#+RR9;Fd<1|M68H(p%K(V1ETXg5z1(GNPd@*B^{tC`;b~Uh!oNZssY5w`f@req! z`tTS8F!8rIdvSNn3zLlbW@&Ml--;Dy1aJ$@!omnPyb}vRm3NN=Gh0X)34I;Y8lE9q zV#c=QTD%u1>?gj?et#S`AvjE>}X|w?GHP*M#@o5`} z@h!R0{Ns{QXP@ltcF;T8Aa|VZC%EcCt$Y=nqesFoHpJZP##fgsu{BkWD~&^M*G{P) zL}>0KEdH^4#ML*~*G~95!C?x8=e^*#q}wxHgVW^}B-RX&cWOo2gQ4*l%++I4LJj5| zE~;_z=B%<8{)aZ)cAZM$A6yVoTI3O1X<1KKVNI-J?Bj^C*4aU#n=U@QO|P5Vv)>Ux Z{0TNbdz!Dp?=S!W002ovPDHLkV1f%4lY0OF literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/25-uMatrix.png b/src/web/src/modules/home/components/softwareIcon/imgs/25-uMatrix.png new file mode 100644 index 0000000000000000000000000000000000000000..82663fc9ec327af371eb1f62382d9f3545e23c8e GIT binary patch literal 917 zcmV;G18V$Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y9E;VFFSW*B00|rS%K~y+TU6IRA6Hye#XUE2kt_UF^ER_X_ zBsH+ps2dmVNsJnm#JDv61#VfIXiOA08r=Yf@UV|5Q`!!l>EqscwWZT3FfB}5XlL4K zOTxl)XXsFDemOar-h03AJBNDm20eIw$>Rm#>3e1Vog9eO>nE0N+pSjXy#K4$>oiSs z90xU@&r|Uqq1ck&BkBwC;sg-?BBp#f|~j=HU4pYklWv; z@BO?l@msZ$ESVA@o1_s<5$Ynp=v(rkCQ2$vN@*yH<&ljSV}9fhE8(h`Ia0;MVS?Rf z<)#exxiSY;F_o;9l}wpjHgj@&080_oc;tX%Em1Huaugml4wZIZv2&!h^Vv2uIXRn7 zQMMp-F?Q)7bU@Q3I#iBC+6Wn{fSUj|ib7WqTB#J&3oy>{JY`E#&qEYjnal~t={r$) zw5DBThVVUE?uuepCXIVImrN4n9zq@`EURyCml?)Js7jPE>MO&)o@@`}LOSi(hOZ75 z&lmjx)$gxFB6cQYsMxuTj3Nm|Y(qNdGC8d4l-;)hz(dC@TL^{pXv`KxaO*CqR#IHs z#B<-dRW4uJhR4d=+Z86F1%u!ml&{#vxSdW9+BPqg9lDZKOC(PC(U zax)XD4qWTog!3lJJfLhPlZ`|ox4EeXf(@QO+RNaEGi{Zq!4!z5tBep)Ztm=u;joLk zyj)ya(bv{0>l=19*Em$m4Gl2MrCzDjDHNa*H0?~&EW@Buqoe%LkVoqJ4cX@tCMKGz zt8O-8%4x_(`d^?Y%6MibGcw{KO-{;lv(lYubA8>L1uOy@3kC*_J0npfdrppx@z<`o rq=$#asVM;8x_L#}9kQ$JW!Ck7O*ytvM#VPt00000NkvXXu0mjfdvu%G literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/26-Blokada.png b/src/web/src/modules/home/components/softwareIcon/imgs/26-Blokada.png new file mode 100644 index 0000000000000000000000000000000000000000..cfd376114e59b77b695522882b3ad47615c2e0b0 GIT binary patch literal 998 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D1A9qCK~y+Tm6L5~ zm1P*me~V==Q!BJ4QG_rl25Hon!K8CGJ^uZq2i|^4QchG+$VAN8RrJ_t~Slu&4`e4(GnF=XYP%|N7tbMYum1 zWGOd@Q&E_o%ZXhG!<@thyK{Z@Px)Q<&pX z%vcO_GRACgh)?=LZ2hg03xb&oPh$i#Q(Dt;%%%01be#9;3DM9OW~MVpa_~A>%EGh+ zYZ?uaTeY0r1Etg^BYdHYdQQa{)Nh;Gni6z39YK1!f}C~pSlsNe`DlboBLe;`U`jv> zI}v3}6%~52*vQsepmmcf91^IPLuCxLmy^mIL)O+pRtwxed>u@hnG-QCOZ+#Ca=hG3 zNVg+`jqpP${fEmr-w~p+!Q~cv7|123xrB`xLfXQP{RJ~>>01rr?hHktK@6X*W`KPz z3Bl5P9rjD7iLMauc9pY2IawbSQXma`M*j}0WK655#YeV4Q>UwFqA5UKTPddAkFPPn z=Yko*?6exSBF{a@qCGC}sMTo;vlF#24Pjho>kO(lQ7S9|Av&goz-N&ezOP`Bvg@n}NtY9OFH7xPAdFdgR>~Uz6w=yuj0^6pM!>{P_wO-o1$okUH2Tcw} zlWfxjbG&_g4{)pge{5kAJOh)an{+hKoY%sBu&aoc49uZf&*ygUh`N>Jw7HC0d+c}F zoj>Fx%d5E4OaJ$HJ)dQ&tTO|1=#p-| z)@uoe_SaT&kC*n};)RE~>nlGE9?X1GOrzcNj{jd+9k#9J?d^~AUS8hZgT8UVpMcQH U^2Mz=7ytkO07*qoM6N<$f;}bU1ONa4 literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/27-hostsmgr.png b/src/web/src/modules/home/components/softwareIcon/imgs/27-hostsmgr.png new file mode 100644 index 0000000000000000000000000000000000000000..349d5b17e0e182d6a05c9e8352a0d5a055ab27a6 GIT binary patch literal 750 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0)t6JK~y+Tm6Xd* zT0s=X{ga3Zal^t@7hSmNs%cW(b!VCgiwXo2V=yMQYA9)F2ysD71p1mBO#IZi(BLMoNwcsw2yi^bc8Hz^bfSXp@muXpkfMu_5T#A44eJNpQByM0j9>2wf@ zL{Ki5sf!`DW2Lf9m?biqIZRLA!^FhnL6h_Ib0iW8uq!Z=Xf%p=JdVvx2ZCFeTS8x9X&(q_*jg273Qj*i~lgrQQY(9g)o2rL#0 zO%Doha_iv#A~nkU2lN?Sa2KS8_;DSA@Bv=IPd~V?c;gWe3J3^Cx3TJU!}oa;{&hdz ze-aT+#38Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0@O)FK~y+Tm6S_N z6Hyd~XQosO3m_y$MSSdJL)4%NiMr6ljmD^nF)=3UhUh|fMibPy(h%b#Y)tS0Fh}F?c#W3E8%O0;>5hfL155qYVK# zD=m05Gy&J#Bk&?H1)=z|VqMYcjQ~4r1JDtQLU(w9?w} z9l)k0861%XxFY|AXE^6w<Q7&cM-5AGFNOLk_}&u{Z^sb^iDha2btD$s}}!qYzFk z(@qM$`{+pd9bU+^y5Y{?C?lg|`lV`sc<8bJk7y9t{NCu=6qT^jdpyQn;hO6tksRD{{W|H;7 za+3Z|BP18Q!5aw%%!iCph^Iodt+gN6hMp28rMmU73fPJdM=+#=xMR(Dh=y4?I!i3xi}D z9f>q!{dW3)(7pfiTm_It?n1GD0&IA6B&^$L@L&f-H=56+c}fy)R(_2WXxur@=ha$`3*IY8QeBrjcfn_002ov JPDHLkV1mqObJ_p^ literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/28-personalDNSfilter.svg b/src/web/src/modules/home/components/softwareIcon/imgs/28-personalDNSfilter.svg new file mode 100644 index 000000000..90fd8f734 --- /dev/null +++ b/src/web/src/modules/home/components/softwareIcon/imgs/28-personalDNSfilter.svg @@ -0,0 +1,20 @@ + + + +Layer 1 + + + + + + + + + + + + \ No newline at end of file diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/29-Unbound.png b/src/web/src/modules/home/components/softwareIcon/imgs/29-Unbound.png new file mode 100644 index 0000000000000000000000000000000000000000..e6100dd8aeb3483288be1f3e931ed579eef96102 GIT binary patch literal 565 zcmV-50?Pe~P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0m?~4K~y+TV?YK9 zN3N^OAH2R<;n20$T8Hn-fyA^<-j`4~bp5&Fq3b)94`0;=D?|qJ`|k_LAG|g}{?N7G z@`tYf2VsrFw_HJT%15tT!Nh?0H_)KTTE`v(_w9LGmDVG69wU<<=bj&mf}X`(H}h2Su~CPThYU-MSx&N>S^8 z^mh;+Su;qzh=$jH24PY2XV^72{@2xO2GiIy3k#dQW{{I}GLn_`KS_#a8Cn0c5)$?% z;J~P_uV>QGNR3xh%X^AXvzmI|b9MF9B%lr^utsE{r`OG`qgUMm@+Y!pkpFe{synQ# zN_nA5aRYPnb_G3y=9NIrzw`~7*BTi$gF_w_FfafBn1nOOUpWR>00000NkvXXu0mjf DC4~J` literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/30-BIND.png b/src/web/src/modules/home/components/softwareIcon/imgs/30-BIND.png new file mode 100644 index 0000000000000000000000000000000000000000..74723afaf1d359782a9c73db41ef2918958493fb GIT binary patch literal 520 zcmV+j0{8uiP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0i8)iK~y+T)l)l5 z!%!Igv^Xg^2%>I^;A9s;@F)0K9J=Wsn#aAF9G!~bPjD3%ClNOhQE;lzN0PQ_+DQjN zsJOTZeZ_NcQe%BU)8gQP!@VK-&OP6EZsUKv51?qp5S4g$$Sl6Xpp(YCeM#|#6AU^Ht*x-{H!r(o2S1;q8yGjq5; zZ_s)Q1vPsSZI4E#A(KW(aLAksUr_uhy!42{-otjt_On>O?%QNe6~ZFWSK1a`GUo&r zvjvx4PgGH>I|Zyu{yh{?@8qXxD>Ks*4Rgw${pb0Mbo=4of#@9pdgq0aG(GhI0000< KMNUMnLSTZL9Ne`4 literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/31-AdGuard-Home.png b/src/web/src/modules/home/components/softwareIcon/imgs/31-AdGuard-Home.png new file mode 100644 index 0000000000000000000000000000000000000000..e217b6879cfc0f52fb498073717e3b35fa925daa GIT binary patch literal 878 zcmV-!1CjiRP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0|QA!K~y+TeUn*l z+E5UM`P+S|RH;uO*-iD>! zZX+BHBbiJ>5CkZSfJWt&aev$&+|C> zaSEH=2D{6FKi8M=gnbBcVbHs5HVc_mlh5a&v6f3^9eS;fDz(<`pw;W)aWa7=z=iPb z*LR#ce&W*Y#7!`OSmF*DL4+vD$SHZqs)l@_1g%s?Nndj#PQN*g z_Z*UZ3Vc?8%qFR*3TsVct(8onEuX<)fbnDui^uPI0XiCuB9&qS8$M!A1TP5?l`JGp zhE^`1%7ke2?M@rLK4UZ*^b`q^1!&!RORwlCREj9q zbyQnSu-jyP^f9cMd zcdf?^MSh@DNRaptCvrD|CozIgLS#y+ioU0oo-Zx%7gDMvYC9e|I{*Lx07*qoM6N<$ Eg2&N_MF0Q* literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/32-AdNauseam.png b/src/web/src/modules/home/components/softwareIcon/imgs/32-AdNauseam.png new file mode 100644 index 0000000000000000000000000000000000000000..773f3c556bcda75b5576d8af06e9211ae2b203fb GIT binary patch literal 713 zcmV;)0yh1LP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0$xc(K~y+TwNy!H z6hRa%y(r>A!3D&lh~Pm4K?J3lu4)|@6f_=OE&&zB1(zf!XdH8h2u3Ad^q}H)3OZd~ zlZ-?U5pxqf3L*%4P!EAjEfWP1+E+b2LyuF3QS`&7KkvPM_3O{?A^$aE63^nk?kWem zD}`Dj^r{OuRefT|=XojQj!IrHhVXgBbR1FLpTaE>`DUr*Iny6Flj~BrHO2$81fq9| zQ3qy;A=S0e*PBwR9>roj8y&rD8g*!9lQT8N+0?R>CImotR*+fGjD$v zG|Zmnrq`g}73He_gcr|snMG9ntmJ2w6R}yZY9kYY?vI%2$zr&{8>gA&0&|RTY7RI_ zrY_^ekv7hgE7~xdRNo_ln$u2_smFNU&0_eGz6qwiEY?h_M=>vX+(n|Zk35)JkLULW zCaAiCVV}?H8VOy9YpU%o(x&|q#;96}E>D$NZQF~1h6An$1=xk@Q8YrH)1b>iUEBW_x60<00R%3t<|2hM+w{FDrZcgQeh?)U( zcn1S63Z{B7>j7zwGwa_Z|C>BBHW@`gL6>3lLxBff|f_brAm+MSBSNS6CJB>K5_~u?2u~(+sCV6rvtRJq~;b zMg`P;&|X3}L+HGlGjp=et3l|Wft$qA>Z1V8r28|B7muLZ{dT8HY}!M80^I!&*8%?k v^Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0{BTpK~y+Tg_Lhd z6JZ?3C-kCszUfUb2evmtiBl_ci1YsxTuYE;V3MST7QN_&P|1jJArVwdBCH@PsThp3 zG|+hylgN4|)3R;(XPa(wyZyP{ZI!$IdbZu1)oy;_1J50NKm6|Qc}|cmeSLj<6bi*q zLqh}8*w`osfShb_HU2a;HFZ{3S3_lGC5(JooTO=bnGcGhOe9I>bJfggZEYP@tJNTt zN@3MzLrgdVVICMJ3~sl#ovUWf@bIu%r_+H_sf1vNMl=%ve&RxRcHuz(71!APMp)KL zfeJWL2$%Sv=rA~U5$0H5m(wg!1}squ6uE{dIs!qAhYY}kp1_jGHo?#?Lb+Tnesi}0 zqH*EWQ3zn6AD7~MHCv(Q!o|dTCys3Iu(r1L$?WVbFzW^gEIkD>5JV&uhBywF7hY*~ ziS;%?1{_WvVRLhHURPJwRxB37+Y9hl41*^?BM&a|5@5jQ7$U#7Xqh`;bp~7km9pMf8o zCLQr0je1|0;Je)m4<0{*j?VLdu+)Y{an?LEn0E@PxwHG&=_*ZpBS($hoF*O72^A98 zw?ogR%kW$~3M=jqtZveOVYYF?*oT^u=yc^T)*!*B;#guMv%XK9DjD$rjg+?$EMrj` znj?ArEhXF{Dx|ET9Lti&jGa0R>`Xnxs3lGZP}Cnn71ut4)fM7pTNooGSh!<4eF;Vk z(HR*)EV+G(R3UWW+#Hyl6j*RM6ALTu(+Qz}Tq2B2l$m}{mO@mIr_&b$J6QNn{1`ISV`@iy0XB4ude`@%$AjKn>ZRE{-7<{&)M&docw{9MxCmcrH|FcPlSD(DLxki5ei{bMY9zxa$k#5&!Sdkq&j)3@9~SL=P+;*w z^={sEn@j@<2LYCjMIASD*mmFjC%a&ymge-+68*iA_ZZmw; z>=Po(-fD|*eW=>ItnhY@Xy4-(^4Au0g)M|3Mfv{+-tj2TZ?H~SdyU^{HZU$2JYD@< J);T3K0RW$*#Bcxr literal 0 HcmV?d00001 diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/imgs.d.ts b/src/web/src/modules/home/components/softwareIcon/imgs/imgs.d.ts new file mode 100644 index 000000000..1090848f7 --- /dev/null +++ b/src/web/src/modules/home/components/softwareIcon/imgs/imgs.d.ts @@ -0,0 +1,9 @@ +declare module "*.svg" { + const content: any; + export default content; +} + +declare module "*.png" { + const content: any; + export default content; +} \ No newline at end of file diff --git a/src/web/src/modules/home/components/softwareIcon/imgs/index.ts b/src/web/src/modules/home/components/softwareIcon/imgs/index.ts new file mode 100644 index 000000000..00cb09611 --- /dev/null +++ b/src/web/src/modules/home/components/softwareIcon/imgs/index.ts @@ -0,0 +1,69 @@ +import img1 from "./01-uBlock-Origin.svg"; +import img2 from "./02-Adblock-Plus.svg"; +import img3 from "./03-AdGuard.svg"; +import img4 from "./04-DNS66.png"; +import img5 from "./05-Nano-Adblocker.png"; +import img6 from "./06-AdBlock.png"; +import img7 from "./07-AdAway.png"; +import img8 from "./08-Personal-Blocklist.png"; +import img10 from "./10-Redirector.png"; +import img11 from "./11-Hosts-File-Editor.png"; +import img12 from "./12-Gas-Mask.png"; +import img13 from "./13-MinerBlock.svg"; +import img14 from "./14-Pi-hole.svg"; +import img15 from "./15-uBlock.svg"; +import img16 from "./16-Internet-Explorer-TPL.svg"; +import img17 from "./17-Google-Hit-Hider-by-Domain.png"; +import img18 from "./18-FireHOL.png"; +import img19 from "./19-Samsung-Knox.png"; +import img20 from "./20-Little-Snitch.png"; +import img21 from "./21-Privoxy.png"; +import img22 from "./22-Diversion.png"; +import img23 from "./23-dnsmasq.png"; +import img24 from "./24-Slimjet.png"; +import img25 from "./25-uMatrix.png"; +import img26 from "./26-Blokada.png"; +import img27 from "./27-hostsmgr.png"; +import img28 from "./28-personalDNSfilter.svg"; +import img29 from "./29-Unbound.png"; +import img30 from "./30-BIND.png"; +import img31 from "./31-AdGuard-Home.png"; +import img32 from "./32-AdNauseam.png"; +import img33 from "./33-Legacy-Unix-Derivatives.png"; +import img34 from "./34-Windows-command-line.png"; + +export { + img1, + img2, + img3, + img4, + img5, + img6, + img7, + img8, + img10, + img11, + img12, + img13, + img14, + img15, + img16, + img17, + img18, + img19, + img20, + img21, + img22, + img23, + img24, + img25, + img26, + img27, + img28, + img29, + img30, + img31, + img32, + img33, + img34 + }; diff --git a/src/web/src/modules/home/components/softwareIcon/index.ts b/src/web/src/modules/home/components/softwareIcon/index.ts new file mode 100644 index 000000000..2dca6d6c1 --- /dev/null +++ b/src/web/src/modules/home/components/softwareIcon/index.ts @@ -0,0 +1,5 @@ +import { SoftwareIcon } from "./SoftwareIcon"; + +export { + SoftwareIcon + }; \ No newline at end of file diff --git a/src/web/src/modules/home/index.ts b/src/web/src/modules/home/index.ts new file mode 100644 index 000000000..f53b5d5c0 --- /dev/null +++ b/src/web/src/modules/home/index.ts @@ -0,0 +1,5 @@ +import { HomeContainer } from "./HomeContainer"; + +export { + HomeContainer as Home + }; \ No newline at end of file diff --git a/src/web/src/modules/home/interfaces/IColumnVisibility.ts b/src/web/src/modules/home/interfaces/IColumnVisibility.ts new file mode 100644 index 000000000..3f11fd9a6 --- /dev/null +++ b/src/web/src/modules/home/interfaces/IColumnVisibility.ts @@ -0,0 +1,4 @@ +export interface IColumnVisibility { + column: string; + visible: boolean; +}; \ No newline at end of file diff --git a/src/web/src/modules/home/interfaces/ILanguage.ts b/src/web/src/modules/home/interfaces/ILanguage.ts new file mode 100644 index 000000000..6f90f94d2 --- /dev/null +++ b/src/web/src/modules/home/interfaces/ILanguage.ts @@ -0,0 +1,6 @@ +export interface ILanguage { + id: number; + filterListIds: number[]; + iso6391: string; + name: string; +}; \ No newline at end of file diff --git a/src/web/src/modules/home/interfaces/ILicense.ts b/src/web/src/modules/home/interfaces/ILicense.ts new file mode 100644 index 000000000..52b42da81 --- /dev/null +++ b/src/web/src/modules/home/interfaces/ILicense.ts @@ -0,0 +1,6 @@ +export interface ILicense { + id: number; + descriptionUrl: string; + filterListIds: number[]; + name: string; +}; \ No newline at end of file diff --git a/src/web/src/modules/home/interfaces/IList.ts b/src/web/src/modules/home/interfaces/IList.ts new file mode 100644 index 000000000..1de1a8607 --- /dev/null +++ b/src/web/src/modules/home/interfaces/IList.ts @@ -0,0 +1,24 @@ +export interface IList { + id: number; + chatUrl: string; + description: string; + descriptionSourceUrl: string; + donateUrl: string; + emailAddress: string; + forumUrl: string; + homeUrl: string; + issuesUrl: string; + languageIds: number[]; + licenseId: number; + maintainerIds: number[]; + name: string; + policyUrl: string; + publishedDate: string; + //ruleCount: number; + submissionUrl: string; + syntaxId: number; + tagIds: number[]; + //updatedDate: string; + viewUrl: string; + viewUrlMirrors: string[]; +}; \ No newline at end of file diff --git a/src/web/src/modules/home/interfaces/IMaintainer.ts b/src/web/src/modules/home/interfaces/IMaintainer.ts new file mode 100644 index 000000000..421ce83c9 --- /dev/null +++ b/src/web/src/modules/home/interfaces/IMaintainer.ts @@ -0,0 +1,8 @@ +export interface IMaintainer { + id: number; + emailAddress: string; + filterListIds: number[]; + homeUrl: string; + name: string; + twitterHandle: string; +}; \ No newline at end of file diff --git a/src/web/src/modules/home/interfaces/ISoftware.ts b/src/web/src/modules/home/interfaces/ISoftware.ts new file mode 100644 index 000000000..840a05fb0 --- /dev/null +++ b/src/web/src/modules/home/interfaces/ISoftware.ts @@ -0,0 +1,7 @@ +export interface ISoftware { + id: number; + homeUrl: string; + isAbpSubscribable: boolean; + name: string; + syntaxIds: number[]; +}; \ No newline at end of file diff --git a/src/web/src/modules/home/interfaces/ISyntax.ts b/src/web/src/modules/home/interfaces/ISyntax.ts new file mode 100644 index 000000000..2dd8fc9ee --- /dev/null +++ b/src/web/src/modules/home/interfaces/ISyntax.ts @@ -0,0 +1,7 @@ +export interface ISyntax { + id: number; + definitionUrl: string; + filterListIds: number[]; + name: string; + softwareIds: number[]; +}; \ No newline at end of file diff --git a/src/web/src/modules/home/interfaces/ITag.ts b/src/web/src/modules/home/interfaces/ITag.ts new file mode 100644 index 000000000..62e526469 --- /dev/null +++ b/src/web/src/modules/home/interfaces/ITag.ts @@ -0,0 +1,6 @@ +export interface ITag { + id: number; + description: string; + filterListIds: number[]; + name: string; +}; \ No newline at end of file diff --git a/src/web/src/modules/home/interfaces/index.ts b/src/web/src/modules/home/interfaces/index.ts new file mode 100644 index 000000000..6a72c288c --- /dev/null +++ b/src/web/src/modules/home/interfaces/index.ts @@ -0,0 +1,19 @@ +import { IColumnVisibility } from "./IColumnVisibility"; +import { ILanguage } from "./ILanguage"; +import { ILicense } from "./ILicense"; +import { IList } from "./IList"; +import { IMaintainer } from "./IMaintainer"; +import { ISoftware } from "./ISoftware"; +import { ISyntax } from "./ISyntax"; +import { ITag } from "./ITag"; + +export { + IColumnVisibility, + ILanguage, + ILicense, + IList, + IMaintainer, + ISoftware, + ISyntax, + ITag + }; \ No newline at end of file diff --git a/src/web/src/modules/index.ts b/src/web/src/modules/index.ts new file mode 100644 index 000000000..d4c28103a --- /dev/null +++ b/src/web/src/modules/index.ts @@ -0,0 +1,5 @@ +import { Home } from "./home"; + +export { + Home + }; \ No newline at end of file diff --git a/src/web/src/utils/GetContrast.ts b/src/web/src/utils/GetContrast.ts new file mode 100644 index 000000000..0dc5f4e55 --- /dev/null +++ b/src/web/src/utils/GetContrast.ts @@ -0,0 +1,8 @@ +//https://stackoverflow.com/a/11868398/2343739 +export const getContrast = (hexcolor: string) => { + const r = parseInt(hexcolor.substr(0, 2), 16); + const g = parseInt(hexcolor.substr(2, 2), 16); + const b = parseInt(hexcolor.substr(4, 2), 16); + const yiq = ((r * 299) + (g * 587) + (b * 114)) / 1000; + return (yiq >= 128) ? "black" : "white"; +}; \ No newline at end of file diff --git a/src/web/src/utils/index.ts b/src/web/src/utils/index.ts new file mode 100644 index 000000000..ecd02f727 --- /dev/null +++ b/src/web/src/utils/index.ts @@ -0,0 +1,5 @@ +import { getContrast } from "./GetContrast"; + +export { + getContrast + }; \ No newline at end of file diff --git a/src/web/src/utils/loader.css b/src/web/src/utils/loader.css new file mode 100644 index 000000000..396eb8671 --- /dev/null +++ b/src/web/src/utils/loader.css @@ -0,0 +1,68 @@ +/*https://projects.lukehaas.me/css-loaders/#load1*/ + +.loader, +.loader:before, +.loader:after { + -ms-animation: load1 1s infinite ease-in-out; + -webkit-animation: load1 1s infinite ease-in-out; + animation: load1 1s infinite ease-in-out; + background: #000000; + height: 4em; + width: 1em; +} + +.loader { + -ms-transform: translateZ(0); + -webkit-animation-delay: -0.16s; + -webkit-transform: translateZ(0); + animation-delay: -0.16s; + color: #000000; + font-size: 11px; + margin: 88px auto; + position: relative; + text-indent: -9999em; + transform: translateZ(0); +} + +.loader:before, +.loader:after { + content: ''; + position: absolute; + top: 0; +} + +.loader:before { + -webkit-animation-delay: -0.32s; + animation-delay: -0.32s; + left: -1.5em; +} + +.loader:after { left: 1.5em; } + +@-webkit-keyframes load1 { + 0%, + 80%, + 100% { + box-shadow: 0 0; + height: 4em; + } + + 40% { + box-shadow: 0 -2em; + height: 5em; + } +} + +@keyframes load1 { + 0%, + 80%, + 100% { + box-shadow: 0 0; + height: 4em; + } + + 40% { + box-shadow: 0 -2em; + height: 5em; + } +} \ No newline at end of file