diff --git a/src/FilterLists.Web/.gitignore b/src/FilterLists.Web/.gitignore index 4d29575de..9f6f0d08b 100644 --- a/src/FilterLists.Web/.gitignore +++ b/src/FilterLists.Web/.gitignore @@ -1,5 +1,3 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - # dependencies /node_modules /.pnp @@ -20,4 +18,4 @@ npm-debug.log* yarn-debug.log* -yarn-error.log* +yarn-error.log* \ No newline at end of file diff --git a/src/FilterLists.Web/config-overrides.js b/src/FilterLists.Web/config-overrides.js new file mode 100644 index 000000000..7373d107d --- /dev/null +++ b/src/FilterLists.Web/config-overrides.js @@ -0,0 +1,9 @@ +const { override, fixBabelImports } = require('customize-cra'); + +module.exports = override( + fixBabelImports('import', { + libraryName: 'antd', + libraryDirectory: 'es', + style: 'css', + }), +); \ No newline at end of file diff --git a/src/FilterLists.Web/package-lock.json b/src/FilterLists.Web/package-lock.json index c553cc344..5c095e1a9 100644 Binary files a/src/FilterLists.Web/package-lock.json and b/src/FilterLists.Web/package-lock.json differ diff --git a/src/FilterLists.Web/package.json b/src/FilterLists.Web/package.json index bb2a23593..c183e0cf3 100644 --- a/src/FilterLists.Web/package.json +++ b/src/FilterLists.Web/package.json @@ -1,30 +1,28 @@ { - "name": "web", + "name": "filterlists.web", "version": "0.1.0", "private": true, "dependencies": { - "@types/jest": "24.0.18", - "@types/node": "12.7.3", - "@types/react": "16.9.2", - "@types/react-dom": "16.9.0", + "@types/jest": "^24.0.18", + "@types/node": "^12.7.3", + "@types/react": "^16.9.2", + "@types/react-dom": "^16.9.0", "@types/react-router-dom": "^4.3.5", - "@types/react-table": "^6.8.5", - "bootstrap": "^4.3.1", - "es6-promise": "^4.2.8", - "moment": "^2.24.0", + "antd": "^3.22.2", + "babel-plugin-import": "^1.12.1", + "customize-cra": "^0.5.0", "react": "^16.9.0", - "react-bootstrap": "^1.0.0-beta.12", + "react-app-rewired": "^2.1.3", "react-dom": "^16.9.0", "react-router-dom": "^5.0.1", - "react-scripts": "3.1.1", - "react-table": "^6.10.0", - "typescript": "3.6.2" + "react-scripts": "^3.1.1", + "slugify": "^1.3.4", + "typescript": "^3.6.2" }, "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", - "eject": "react-scripts eject" + "start": "react-app-rewired start", + "build": "react-app-rewired build", + "test": "react-app-rewired test" }, "proxy": "https://filterlists.com", "eslintConfig": { @@ -41,6 +39,5 @@ "last 1 firefox version", "last 1 safari version" ] - }, - "devDependencies": {} -} + } +} \ No newline at end of file diff --git a/src/FilterLists.Web/public/index.html b/src/FilterLists.Web/public/index.html index 4fedac461..ec85e765d 100644 --- a/src/FilterLists.Web/public/index.html +++ b/src/FilterLists.Web/public/index.html @@ -1,27 +1,42 @@ + + + + + + + + FilterLists | Subscriptions for uBlock Origin, Adblock Plus, AdGuard, ... + + + + + - - - - - - - FilterLists | Subscriptions for uBlock Origin, Adblock Plus, AdGuard, ... - - - - - - - -
-

FilterLists is built with ReactJS and therefore requires first-party JavaScript to be enabled. We do not use any - third-party JavaScript, and your privacy is very important to us. If you prefer not to enable JavaScript or your - browser does not support it, the data is also available on our GitHub repo.

-
- - - \ No newline at end of file + + +
+

+ FilterLists is built with ReactJS and therefore requires first-party + JavaScript to be enabled. We do not use any third-party JavaScript, and + your privacy is very important to us. If you prefer not to enable + JavaScript or your browser does not support it, the data is also + available on + our GitHub repo. +

+
+ + diff --git a/src/FilterLists.Web/src/App.css b/src/FilterLists.Web/src/App.css deleted file mode 100644 index 021a9f2fc..000000000 --- a/src/FilterLists.Web/src/App.css +++ /dev/null @@ -1,14 +0,0 @@ -/* use consistent and smaller font size globally */ -body, -h2, -h3, -h4, -h5, -blockquote { - font-size: 16px; -} - -/* leave a bit of horizontal padding around the app for cleanliness */ -.container { - max-width: 90vw; -} diff --git a/src/FilterLists.Web/src/App.test.tsx b/src/FilterLists.Web/src/App.test.tsx index a754b201b..7911e5b41 100644 --- a/src/FilterLists.Web/src/App.test.tsx +++ b/src/FilterLists.Web/src/App.test.tsx @@ -1,9 +1,10 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import App from './App'; + +import { App } from './App'; it('renders without crashing', () => { const div = document.createElement('div'); ReactDOM.render(, div); ReactDOM.unmountComponentAtNode(div); -}); +}); \ No newline at end of file diff --git a/src/FilterLists.Web/src/App.tsx b/src/FilterLists.Web/src/App.tsx index 8ef9be137..e2ac34738 100644 --- a/src/FilterLists.Web/src/App.tsx +++ b/src/FilterLists.Web/src/App.tsx @@ -1,14 +1,90 @@ +import { Icon, Layout, Menu } from 'antd'; import React from 'react'; -import './App.css'; -import { Layout } from "./Layout"; -import { Router } from "./Router"; +import { BrowserRouter as Router, Route, RouteComponentProps, Switch } from 'react-router-dom'; -const App: React.FC = () => { - return ( +import { ListsTable } from './components'; + +const { Header, Content, Footer } = Layout; + +export const App: React.FC = () => + - +
+ + +
+ +
+ + + + +
+
+
+ | | | | | +
- ); -} +
; -export default App; +const Logo = () => + FilterLists logo; + +const NotFound = (props: RouteComponentProps) => +

+ 404 Not Found: {props.location.pathname} +

; + +const CopyrightAuthor = () => + <> + ©{new Date().getFullYear()}  + + Collin M. Barrett + + ; + +const Twitter = () => + + Twitter + ; + +const Community = () => + + Community + ; + +const GitHub = () => + + GitHub + ; + +const Api = () => + + API + ; + +const Donate = () => + + Donate + ; \ No newline at end of file diff --git a/src/FilterLists.Web/src/Layout.tsx b/src/FilterLists.Web/src/Layout.tsx deleted file mode 100644 index e98fe8ded..000000000 --- a/src/FilterLists.Web/src/Layout.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import * as React from "react"; - -interface Props { - children?: React.ReactNode; -}; - -export const Layout = (props: Props) => -
-
-
-
- {props.children} -
-
-
-
; - -const Header = () => -
-

- - FilterLists - -

-
; - -const Footer = () => - ; - -const HubLink = () => - - Hub - ; - -const GitHubLink = () => - - GitHub - ; - -const ApiLink = () => - - API - ; - -const DonateLink = () => - - Donate - ; - -const OwnerLink = () => - - Collin M. Barrett - ; \ No newline at end of file diff --git a/src/FilterLists.Web/src/Router.tsx b/src/FilterLists.Web/src/Router.tsx deleted file mode 100644 index 6036178a7..000000000 --- a/src/FilterLists.Web/src/Router.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import * as React from "react"; -import { BrowserRouter, Redirect, Route, Switch } from "react-router-dom"; -import { Home } from "./modules"; - -const Routes = - - - - - - ; - -export const Router = () => \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/Description.tsx b/src/FilterLists.Web/src/components/Description.tsx new file mode 100644 index 000000000..eb7a906da --- /dev/null +++ b/src/FilterLists.Web/src/components/Description.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +interface Props { + description: string; + descriptionSourceUrl: string; +}; + +export const Description = (props: Props) => + props.description + ?
{props.description}
+ :

{props.description}

; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/LicenseTag.tsx b/src/FilterLists.Web/src/components/LicenseTag.tsx new file mode 100644 index 000000000..d6349d4a5 --- /dev/null +++ b/src/FilterLists.Web/src/components/LicenseTag.tsx @@ -0,0 +1,31 @@ +import { Tag } from 'antd'; +import * as React from 'react'; + +interface Props { + name: string; + descriptionUrl: string; +}; + +export const LicenseTag = (props: Props) => + props.name + ? <> +

License:

+ + + + + : null; + +const TagContents = (props: Props) => + props.descriptionUrl + ? + {props.name} + + : <> + {props.name} + ; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/LinkButton.tsx b/src/FilterLists.Web/src/components/LinkButton.tsx new file mode 100644 index 000000000..27e8f6841 --- /dev/null +++ b/src/FilterLists.Web/src/components/LinkButton.tsx @@ -0,0 +1,26 @@ +import { Button } from 'antd'; +import { ButtonType } from 'antd/lib/button'; +import React from 'react'; + +interface Props { + url: string; + text: string; + title?: string; + type?: ButtonType; + icon?: string; +}; + +export const LinkButton = (props: Props) => + props.url && props.text + ? + : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/ListInfoButton.tsx b/src/FilterLists.Web/src/components/ListInfoButton.tsx new file mode 100644 index 000000000..041a79b06 --- /dev/null +++ b/src/FilterLists.Web/src/components/ListInfoButton.tsx @@ -0,0 +1,22 @@ +import { Button, Icon } from 'antd'; +import React from 'react'; +import { RouteComponentProps } from 'react-router-dom'; +import slugify from 'slugify'; + +interface Props { + listName: string; +}; + +export const ListInfoButton = (props: RouteComponentProps & Props) => { + const listPath = `/lists/${slugify(props.listName)}`; + return ( + + ); +}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/ListInfoDrawer.tsx b/src/FilterLists.Web/src/components/ListInfoDrawer.tsx new file mode 100644 index 000000000..8c5e4303e --- /dev/null +++ b/src/FilterLists.Web/src/components/ListInfoDrawer.tsx @@ -0,0 +1,122 @@ +import { Divider, Drawer } from 'antd'; +import ButtonGroup from 'antd/lib/button/button-group'; +import React, { useEffect, useState } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; + +import { Language } from '../interfaces/Language'; +import { License } from '../interfaces/License'; +import { List } from '../interfaces/List'; +import { Software } from '../interfaces/Software'; +import { Syntax } from '../interfaces/Syntax'; +import { Tag } from '../interfaces/Tag'; +import { Description } from './Description'; +import { LanguageCloud } from './languageCloud'; +import { LicenseTag } from './LicenseTag'; +import { LinkButton } from './LinkButton'; +import { PublishedDate } from './PublishedDate'; +import { SoftwareCloud } from './softwareCloud'; +import { SubscribeButtons } from './SubscribeButtons'; +import { SyntaxTag } from './SyntaxTag'; +import { TagCloud } from './tagCloud'; + +interface Props { + list: List; + languages: Language[]; + license: License | undefined; + software: Software[]; + syntax: Syntax | undefined; + tags: Tag[]; +}; + +export const ListInfoDrawer = (props: RouteComponentProps & Props) => { + const [originalTitle] = useState(document.title); + useEffect(() => { + const updateTitle = () => document.title = props.list.name + " | " + originalTitle; + updateTitle(); + return () => { document.title = originalTitle; }; + }, [props.list, originalTitle]); + return ( + props.history.push("/")}> + + + + {props.license && + } + {props.syntax && + } + + + + + + + + + + + + + + + + + ); +}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/PublishedDate.tsx b/src/FilterLists.Web/src/components/PublishedDate.tsx new file mode 100644 index 000000000..f7fb53aa7 --- /dev/null +++ b/src/FilterLists.Web/src/components/PublishedDate.tsx @@ -0,0 +1,13 @@ +import React from 'react'; + +interface Props { + publishedDate: string; +}; + +export const PublishedDate = (props: Props) => + props.publishedDate + ? <> +

First Published Date:

+ {new Date(props.publishedDate).toDateString()} + + : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/SubscribeButtons.tsx b/src/FilterLists.Web/src/components/SubscribeButtons.tsx new file mode 100644 index 000000000..f1893b281 --- /dev/null +++ b/src/FilterLists.Web/src/components/SubscribeButtons.tsx @@ -0,0 +1,95 @@ +import { Button } from 'antd'; +import { ButtonType } from 'antd/lib/button'; +import React from 'react'; + +interface Props { + name: string; + viewUrl: string; + viewUrlMirrors: string[]; +}; + +export const SubscribeButtons = (props: Props) => + props.viewUrl + ? <> + + + + : null; + +interface MirrorButtonsProps { + name: string; + viewUrlMirrors: string[]; +}; + +const MirrorButtons = (props: MirrorButtonsProps) => + <> + {props.viewUrlMirrors && props.viewUrlMirrors.length + ? props.viewUrlMirrors.map((viewUrlMirror: string, i: number) => + ) + : null} + ; + +interface SubscribeButtonProps { + name: string; + viewUrl: string; + text: string; +}; + +const SubscribeButton = (props: SubscribeButtonProps) => { + const buttonProps = buildButtonProps(props.name, props.viewUrl); + return ( + + ); +}; + +const buildButtonProps = (name: string, viewUrl: string) => { + let type: ButtonType = "primary"; + let disabled: boolean = false; + + const hrefLocation = `${encodeURIComponent(viewUrl)}`; + const hrefTitle = `${encodeURIComponent(name)}`; + let href = `abp:subscribe?location=${hrefLocation}&title=${hrefTitle}`; + + let prefixes: string[] = []; + let message = `Subscribe to ${name} with a browser extension supporting the "abp:" protocol (e.g. uBlock Origin, Adblock Plus).`; + + // HTTP protocols + if (viewUrl.includes(".onion/")) { + type = "dashed"; + prefixes.push("TOR"); + }; + if (viewUrl.includes("http://")) { + type = "danger"; + prefixes.push("INSECURE"); + }; + + // Software protocols + if (viewUrl.includes(".tpl")) { + disabled = true; // IE not supported by FilterLists + }; + if (viewUrl.includes(".lsrules") || viewUrl.includes("?hostformat=littlesnitch")) { + href = `x-littlesnitch:subscribe-rules?url=${hrefLocation}`; + message = `Subscribe to ${name} with Little Snitch's rule group subscription feature.`; + }; + + const title = `${prefixes.length ? prefixes.join(" | ") + " | " : ""}${message}`; + + return { disabled, type, href, title }; +}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/SyntaxTag.tsx b/src/FilterLists.Web/src/components/SyntaxTag.tsx new file mode 100644 index 000000000..be50e6412 --- /dev/null +++ b/src/FilterLists.Web/src/components/SyntaxTag.tsx @@ -0,0 +1,31 @@ +import { Tag } from 'antd'; +import * as React from 'react'; + +interface Props { + name: string; + definitionUrl: string; +}; + +export const SyntaxTag = (props: Props) => + props.name + ? <> +

Syntax:

+ + + + + : null; + +const TagContents = (props: Props) => + props.definitionUrl + ? + {props.name} + + : <> + {props.name} + ; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/index.ts b/src/FilterLists.Web/src/components/index.ts new file mode 100644 index 000000000..2392fcc0e --- /dev/null +++ b/src/FilterLists.Web/src/components/index.ts @@ -0,0 +1,3 @@ +import { ListsTable } from './listsTable'; + +export { ListsTable }; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/languageCloud/LanguageCloud.module.css b/src/FilterLists.Web/src/components/languageCloud/LanguageCloud.module.css new file mode 100644 index 000000000..3bee840b6 --- /dev/null +++ b/src/FilterLists.Web/src/components/languageCloud/LanguageCloud.module.css @@ -0,0 +1,4 @@ +/* allow for 2nd row's tags' bottom border to not be chopped in AllListsTable */ +.grow { + max-height: none !important; +} diff --git a/src/FilterLists.Web/src/components/languageCloud/LanguageCloud.tsx b/src/FilterLists.Web/src/components/languageCloud/LanguageCloud.tsx new file mode 100644 index 000000000..4c64ca1e2 --- /dev/null +++ b/src/FilterLists.Web/src/components/languageCloud/LanguageCloud.tsx @@ -0,0 +1,19 @@ +import { Tag } from 'antd'; +import React from 'react'; + +import { Language } from '../../interfaces/Language'; +import styles from './LanguageCloud.module.css'; + +interface Props { + languages: Language[]; + showLabel?: boolean; +}; + +export const LanguageCloud = (props: Props) => + props.languages && props.languages.length + ?
+ {props.showLabel &&

{`Language${props.languages.length > 1 ? "s" : ""}:`}

} + {props.languages.map((l: Language, i: number) => + {l.iso6391})} +
+ : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/languageCloud/index.ts b/src/FilterLists.Web/src/components/languageCloud/index.ts new file mode 100644 index 000000000..3f61a4e3d --- /dev/null +++ b/src/FilterLists.Web/src/components/languageCloud/index.ts @@ -0,0 +1,3 @@ +import { LanguageCloud } from './LanguageCloud'; + +export { LanguageCloud }; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/listsTable/ListDrawer.tsx b/src/FilterLists.Web/src/components/listsTable/ListDrawer.tsx new file mode 100644 index 000000000..3cb1ae641 --- /dev/null +++ b/src/FilterLists.Web/src/components/listsTable/ListDrawer.tsx @@ -0,0 +1,36 @@ +import React from 'react'; +import { Redirect, Route, RouteComponentProps, StaticContext } from 'react-router'; + +import { Language } from '../../interfaces/Language'; +import { License } from '../../interfaces/License'; +import { List } from '../../interfaces/List'; +import { Software } from '../../interfaces/Software'; +import { Syntax } from '../../interfaces/Syntax'; +import { Tag } from '../../interfaces/Tag'; +import { ListInfoDrawer } from '../ListInfoDrawer'; + +interface Props { + lists: List[]; + languages: Language[]; + licenses: License[]; + software: Software[]; + syntaxes: Syntax[]; + tags: Tag[]; +}; + +export const ListDrawer = (props: Props) => { + const renderDrawer = (rp: RouteComponentProps) => { + const list = props.lists.find(l => l.slug === rp.match.params.listSlug); + return list + ? list.languageIds.includes(l.id))} + license={list.licenseId ? props.licenses.find((l: License) => list.licenseId === l.id) : props.licenses.find((l: License) => l.id === 5)} + software={list.syntaxId ? props.software.filter((s: Software) => s.syntaxIds.includes(list.syntaxId)) : []} + syntax={list.syntaxId ? props.syntaxes.find(s => s.id === list.syntaxId) : undefined} + tags={list.tagIds && props.tags.filter((t: Tag) => list.tagIds.includes(t.id))} + {...rp} /> + : (props.lists && props.lists.length && ) || null; + }; + return ; +}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/listsTable/ListsTable.module.css b/src/FilterLists.Web/src/components/listsTable/ListsTable.module.css new file mode 100644 index 000000000..11d17859b --- /dev/null +++ b/src/FilterLists.Web/src/components/listsTable/ListsTable.module.css @@ -0,0 +1,21 @@ +.nogrow > * { + /* limit table cells from wrapping more than 2 lines */ + /* https://stackoverflow.com/a/13924997/2343739 */ + /* https://stackoverflow.com/a/22042054/2343739 */ + overflow: hidden; + text-overflow: ellipsis; + display: -webkit-box !important; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; /* number of lines to show */ + line-height: 1.5; /* fallback */ + max-height: 3em; /* fallback */ + + /* fixed row height */ + min-height: 3em; +} + +.nogrow { + /* eliminate top and bottom padding in cells to fit more rows per page */ + padding-top: 0px !important; + padding-bottom: 0px !important; +} diff --git a/src/FilterLists.Web/src/components/listsTable/ListsTable.tsx b/src/FilterLists.Web/src/components/listsTable/ListsTable.tsx new file mode 100644 index 000000000..1e84e9f51 --- /dev/null +++ b/src/FilterLists.Web/src/components/listsTable/ListsTable.tsx @@ -0,0 +1,145 @@ +import { Table, Tag } from 'antd'; +import React from 'react'; +import { RouteComponentProps } from 'react-router'; + +import { useSearchColumnFilter, useTablePageSizer } from '../../hooks'; +import { Language } from '../../interfaces/Language'; +import { License } from '../../interfaces/License'; +import { List } from '../../interfaces/List'; +import { Software } from '../../interfaces/Software'; +import { Tag as TagInterface } from '../../interfaces/Tag'; +import { nameof } from '../../utils'; +import { Description } from '../Description'; +import { LanguageCloud } from '../languageCloud'; +import { ListInfoButton } from '../ListInfoButton'; +import { SoftwareCloud, SoftwareIcon } from '../softwareCloud'; +import { TagCloud } from '../tagCloud'; +import { arraySorter } from './arraySorter'; +import styles from './ListsTable.module.css'; + +interface Props { + lists: List[]; + languages: Language[]; + licenses: License[]; + software: Software[]; + tags: TagInterface[]; +}; + +export const ListsTable = (props: RouteComponentProps & Props) => { + const { lists, languages, licenses, software, tags, ...routeComponentProps } = props; + const tablePageSize = useTablePageSizer(); + const searchNameColumn = useSearchColumnFilter(nameof("name")); + const searchDescriptionColumn = useSearchColumnFilter(nameof("description")); + return ( + + dataSource={lists} + rowKey={record => record.id.toString()} + loading={lists.length ? false : true} + size="small" + pagination={{ + size: "small", + simple: true, + style: { float: "left" }, + pageSize: tablePageSize.pageSize + }} + scroll={{ x: tablePageSize.isNarrowWindow ? undefined : 1200 }}> + + title="Info" + dataIndex={nameof("id")} + className={styles.nogrow} + fixed="left" + render={(_id: number, list: List) => + } /> + + title="Name" + dataIndex={nameof("name")} + sorter={(a, b) => a.name.localeCompare(b.name)} + defaultSortOrder={"ascend"} + width={tablePageSize.isNarrowWindow ? undefined : 200} + className={styles.nogrow} + fixed="left" + filterDropdown={searchNameColumn.filterDropdown} + filterIcon={searchNameColumn.filterIcon} + onFilter={searchNameColumn.onFilter} + render={(name: string) => +
{name}
} /> + {tablePageSize.isNarrowWindow + ? null + : + title="Description" + dataIndex={nameof("description")} + className={styles.nogrow} + filterDropdown={searchDescriptionColumn.filterDropdown} + filterIcon={searchDescriptionColumn.filterIcon} + onFilter={searchDescriptionColumn.onFilter} + render={(description: string, list: List) => + } />} + {tablePageSize.isNarrowWindow + ? null + : + title="Software" + dataIndex={nameof("syntaxId")} + sorter={(a, b) => { + const getSoftwareIds = (l: List) => software.filter((s: Software) => s.syntaxIds.includes(l.syntaxId)).map(s => s.id); + return arraySorter(getSoftwareIds(a), getSoftwareIds(b), software); + }} + width={143} + className={styles.nogrow} + filters={software.map(s => ({ + text: <> +   + {s.name} + , + value: s.name + }))} + onFilter={(value, record) => software.filter((s: Software) => s.name === value).flatMap(s => s.syntaxIds).includes(record.syntaxId)} + render={(syntaxId: number) => + syntaxId + ? s.syntaxIds.includes(syntaxId))} /> + : null} />} + {tablePageSize.isNarrowWindow + ? null + : + title="Languages" + dataIndex={nameof("languageIds")} + sorter={(a, b) => arraySorter(a.languageIds, b.languageIds, languages)} + width={125} + className={styles.nogrow} + filters={languages.map(l => ({ + text: <> + {l.iso6391}  + {l.name} + , + value: l.id.toString() + }))} + onFilter={(value, record) => record.languageIds + ? record.languageIds.includes(+value) + : false} + render={(languageIds: number[]) => + languageIds + ? languageIds.includes(l.id))} /> + : null} />} + {tablePageSize.isNarrowWindow + ? null + : + title="Tags" + dataIndex={nameof("tagIds")} + sorter={(a, b) => arraySorter(a.tagIds, b.tagIds, tags)} + width={275} + className={styles.nogrow} + filters={tags.map(t => ({ + text: {t.name}, + value: t.id.toString() + }))} + onFilter={(value, record) => record.tagIds + ? record.tagIds.includes(+value) + : false} + render={(tagIds: number[]) => + tagIds + ? tagIds.includes(t.id))} /> + : null} />} + + ); +}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/listsTable/ListsTableHoc.tsx b/src/FilterLists.Web/src/components/listsTable/ListsTableHoc.tsx new file mode 100644 index 000000000..1c0c39481 --- /dev/null +++ b/src/FilterLists.Web/src/components/listsTable/ListsTableHoc.tsx @@ -0,0 +1,33 @@ +import React from 'react'; +import { RouteComponentProps } from 'react-router-dom'; + +import { useLanguages, useLicenses, useLists, useSoftware, useSyntaxes, useTags } from '../../hooks'; +import { ListDrawer } from './ListDrawer'; +import { ListsTable } from './ListsTable'; + +export const ListsTableHoc = (props: RouteComponentProps) => { + const lists = useLists(); + const languages = useLanguages(); + const licenses = useLicenses(); + const software = useSoftware(); + const syntaxes = useSyntaxes(); + const tags = useTags(); + return ( + <> + + + + ); +}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/listsTable/arraySorter.ts b/src/FilterLists.Web/src/components/listsTable/arraySorter.ts new file mode 100644 index 000000000..e438c34b9 --- /dev/null +++ b/src/FilterLists.Web/src/components/listsTable/arraySorter.ts @@ -0,0 +1,18 @@ +interface ArraySortableEntity { + id: number; + name: string; +}; + +export const arraySorter = (a: number[], b: number[], entities: ArraySortableEntity[]) => + a && a.length + ? b && b.length + ? a.length === b.length + ? entities.filter((e: ArraySortableEntity) => a.includes(e.id)).map((e: ArraySortableEntity) => e.name).join().toLowerCase() + > entities.filter((e: ArraySortableEntity) => b.includes(e.id)).map((e: ArraySortableEntity) => e.name).join().toLowerCase() + ? 1 + : -1 + : a.length > b.length + ? -1 + : 1 + : -1 + : 1; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/listsTable/index.ts b/src/FilterLists.Web/src/components/listsTable/index.ts new file mode 100644 index 000000000..e69706c2e --- /dev/null +++ b/src/FilterLists.Web/src/components/listsTable/index.ts @@ -0,0 +1,3 @@ +import { ListsTableHoc } from './ListsTableHoc'; + +export { ListsTableHoc as ListsTable }; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/softwareCloud/SoftwareCloud.module.css b/src/FilterLists.Web/src/components/softwareCloud/SoftwareCloud.module.css new file mode 100644 index 000000000..5daff62ad --- /dev/null +++ b/src/FilterLists.Web/src/components/softwareCloud/SoftwareCloud.module.css @@ -0,0 +1,4 @@ +/* allow for 2nd row's bottom border to not be chopped in AllListsTable */ +.grow { + max-height: none !important; +} diff --git a/src/FilterLists.Web/src/components/softwareCloud/SoftwareCloud.tsx b/src/FilterLists.Web/src/components/softwareCloud/SoftwareCloud.tsx new file mode 100644 index 000000000..50090622d --- /dev/null +++ b/src/FilterLists.Web/src/components/softwareCloud/SoftwareCloud.tsx @@ -0,0 +1,26 @@ +import React from 'react'; + +import { Software } from '../../interfaces/Software'; +import styles from './SoftwareCloud.module.css'; +import { SoftwareIcon } from './SoftwareIcon'; + +interface Props { + software: Software[]; + showLabel?: boolean; +}; + +export const SoftwareCloud = (props: Props) => + props.software && props.software.length + ?
+ {props.showLabel &&

{`Software:`}

} + {props.software.map((s: Software, i: number) => + s.homeUrl + ? + + + : )} +
+ : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/SoftwareIcon.tsx b/src/FilterLists.Web/src/components/softwareCloud/SoftwareIcon.tsx similarity index 60% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/SoftwareIcon.tsx rename to src/FilterLists.Web/src/components/softwareCloud/SoftwareIcon.tsx index 9a043bcff..d8a397863 100644 --- a/src/FilterLists.Web/src/modules/home/components/softwareIcon/SoftwareIcon.tsx +++ b/src/FilterLists.Web/src/components/softwareCloud/SoftwareIcon.tsx @@ -1,5 +1,43 @@ -import * as React from "react"; -import { img1, img10, img11, img12, img13, img14, img15, img16, img17, img18, img19, img2, img20, img21, img22, img23, img24, img25, img26, img27, img28, img29, img3, img30, img31, img32, img33, img34, img35, img36, img37, img4, img5, img6, img7, img8 } from "./imgs"; +import * as React from 'react'; + +import { + img01, + img02, + img03, + img04, + img05, + img06, + img07, + img08, + 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, + img35, + img36, + img37 +} from './imgs'; interface Props { id: number; @@ -7,26 +45,27 @@ interface Props { export const SoftwareIcon = (props: Props) => icons[props.id] - ? {icons[props.id].imageTitle} + title={`View ${icons[props.id].imageTitle}'s homepage.`} /> : null; -interface IIcon { +interface Icon { 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" }, +const icons: { [id: number]: Icon; } = { + 1: { image: img01, imageTitle: "uBlock Origin" }, + 2: { image: img02, imageTitle: "Adblock Plus" }, + 3: { image: img03, imageTitle: "AdGuard" }, + 4: { image: img04, imageTitle: "DNS66" }, + 5: { image: img05, imageTitle: "Nano Adblocker" }, + 6: { image: img06, imageTitle: "AdBlock" }, + 7: { image: img07, imageTitle: "AdAway" }, + 8: { image: img08, imageTitle: "Personal Blocklist" }, 10: { image: img10, imageTitle: "Redirector" }, 11: { image: img11, imageTitle: "Hosts File Editor" }, 12: { image: img12, imageTitle: "Gas Mask" }, @@ -54,5 +93,5 @@ const icons: { [id: number]: IIcon; } = { 34: { image: img34, imageTitle: "Windows command line" }, 35: { image: img35, imageTitle: "Shadowsocks" }, 36: { image: img36, imageTitle: "ShadowsocksR" }, - 37: { image: img37, imageTitle: "Shadowrocket" }, -}; + 37: { image: img37, imageTitle: "Shadowrocket" } +}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/01-uBlock-Origin.svg b/src/FilterLists.Web/src/components/softwareCloud/imgs/01-uBlock-Origin.svg similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/01-uBlock-Origin.svg rename to src/FilterLists.Web/src/components/softwareCloud/imgs/01-uBlock-Origin.svg diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/02-Adblock-Plus.svg b/src/FilterLists.Web/src/components/softwareCloud/imgs/02-Adblock-Plus.svg similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/02-Adblock-Plus.svg rename to src/FilterLists.Web/src/components/softwareCloud/imgs/02-Adblock-Plus.svg diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/03-AdGuard.svg b/src/FilterLists.Web/src/components/softwareCloud/imgs/03-AdGuard.svg similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/03-AdGuard.svg rename to src/FilterLists.Web/src/components/softwareCloud/imgs/03-AdGuard.svg diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/04-DNS66.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/04-DNS66.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/04-DNS66.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/04-DNS66.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/05-Nano-Adblocker.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/05-Nano-Adblocker.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/05-Nano-Adblocker.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/05-Nano-Adblocker.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/06-AdBlock.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/06-AdBlock.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/06-AdBlock.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/06-AdBlock.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/07-AdAway.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/07-AdAway.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/07-AdAway.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/07-AdAway.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/08-Personal-Blocklist.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/08-Personal-Blocklist.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/08-Personal-Blocklist.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/08-Personal-Blocklist.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/10-Redirector.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/10-Redirector.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/10-Redirector.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/10-Redirector.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/11-Hosts-File-Editor.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/11-Hosts-File-Editor.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/11-Hosts-File-Editor.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/11-Hosts-File-Editor.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/12-Gas-Mask.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/12-Gas-Mask.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/12-Gas-Mask.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/12-Gas-Mask.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/13-MinerBlock.svg b/src/FilterLists.Web/src/components/softwareCloud/imgs/13-MinerBlock.svg similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/13-MinerBlock.svg rename to src/FilterLists.Web/src/components/softwareCloud/imgs/13-MinerBlock.svg diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/14-Pi-hole.svg b/src/FilterLists.Web/src/components/softwareCloud/imgs/14-Pi-hole.svg similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/14-Pi-hole.svg rename to src/FilterLists.Web/src/components/softwareCloud/imgs/14-Pi-hole.svg diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/15-uBlock.svg b/src/FilterLists.Web/src/components/softwareCloud/imgs/15-uBlock.svg similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/15-uBlock.svg rename to src/FilterLists.Web/src/components/softwareCloud/imgs/15-uBlock.svg diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/16-Internet-Explorer-TPL.svg b/src/FilterLists.Web/src/components/softwareCloud/imgs/16-Internet-Explorer-TPL.svg similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/16-Internet-Explorer-TPL.svg rename to src/FilterLists.Web/src/components/softwareCloud/imgs/16-Internet-Explorer-TPL.svg diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/17-Google-Hit-Hider-by-Domain.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/17-Google-Hit-Hider-by-Domain.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/17-Google-Hit-Hider-by-Domain.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/17-Google-Hit-Hider-by-Domain.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/18-FireHOL.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/18-FireHOL.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/18-FireHOL.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/18-FireHOL.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/19-Samsung-Knox.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/19-Samsung-Knox.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/19-Samsung-Knox.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/19-Samsung-Knox.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/20-Little-Snitch.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/20-Little-Snitch.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/20-Little-Snitch.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/20-Little-Snitch.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/21-Privoxy.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/21-Privoxy.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/21-Privoxy.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/21-Privoxy.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/22-Diversion.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/22-Diversion.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/22-Diversion.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/22-Diversion.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/23-dnsmasq.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/23-dnsmasq.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/23-dnsmasq.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/23-dnsmasq.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/24-Slimjet.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/24-Slimjet.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/24-Slimjet.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/24-Slimjet.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/25-uMatrix.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/25-uMatrix.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/25-uMatrix.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/25-uMatrix.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/26-Blokada.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/26-Blokada.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/26-Blokada.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/26-Blokada.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/27-hostsmgr.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/27-hostsmgr.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/27-hostsmgr.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/27-hostsmgr.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/28-personalDNSfilter.svg b/src/FilterLists.Web/src/components/softwareCloud/imgs/28-personalDNSfilter.svg similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/28-personalDNSfilter.svg rename to src/FilterLists.Web/src/components/softwareCloud/imgs/28-personalDNSfilter.svg diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/29-Unbound.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/29-Unbound.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/29-Unbound.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/29-Unbound.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/30-BIND.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/30-BIND.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/30-BIND.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/30-BIND.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/31-AdGuard-Home.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/31-AdGuard-Home.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/31-AdGuard-Home.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/31-AdGuard-Home.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/32-AdNauseam.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/32-AdNauseam.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/32-AdNauseam.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/32-AdNauseam.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/33-Legacy-Unix-Derivatives.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/33-Legacy-Unix-Derivatives.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/33-Legacy-Unix-Derivatives.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/33-Legacy-Unix-Derivatives.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/34-Windows-command-line.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/34-Windows-command-line.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/34-Windows-command-line.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/34-Windows-command-line.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/35-Shadowsocks.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/35-Shadowsocks.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/35-Shadowsocks.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/35-Shadowsocks.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/36-ShadowsocksR.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/36-ShadowsocksR.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/36-ShadowsocksR.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/36-ShadowsocksR.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/37-Shadowrocket.png b/src/FilterLists.Web/src/components/softwareCloud/imgs/37-Shadowrocket.png similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/37-Shadowrocket.png rename to src/FilterLists.Web/src/components/softwareCloud/imgs/37-Shadowrocket.png diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/imgs.d.ts b/src/FilterLists.Web/src/components/softwareCloud/imgs/imgs.d.ts similarity index 100% rename from src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/imgs.d.ts rename to src/FilterLists.Web/src/components/softwareCloud/imgs/imgs.d.ts diff --git a/src/FilterLists.Web/src/components/softwareCloud/imgs/index.ts b/src/FilterLists.Web/src/components/softwareCloud/imgs/index.ts new file mode 100644 index 000000000..6d65459c3 --- /dev/null +++ b/src/FilterLists.Web/src/components/softwareCloud/imgs/index.ts @@ -0,0 +1,75 @@ +import img01 from './01-uBlock-Origin.svg'; +import img02 from './02-Adblock-Plus.svg'; +import img03 from './03-AdGuard.svg'; +import img04 from './04-DNS66.png'; +import img05 from './05-Nano-Adblocker.png'; +import img06 from './06-AdBlock.png'; +import img07 from './07-AdAway.png'; +import img08 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'; +import img35 from './35-Shadowsocks.png'; +import img36 from './36-ShadowsocksR.png'; +import img37 from './37-Shadowrocket.png'; + +export { + img01, + img02, + img03, + img04, + img05, + img06, + img07, + img08, + 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, + img35, + img36, + img37 +}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/softwareCloud/index.ts b/src/FilterLists.Web/src/components/softwareCloud/index.ts new file mode 100644 index 000000000..212ee46c3 --- /dev/null +++ b/src/FilterLists.Web/src/components/softwareCloud/index.ts @@ -0,0 +1,4 @@ +import { SoftwareCloud } from './SoftwareCloud'; +import { SoftwareIcon } from './SoftwareIcon'; + +export { SoftwareCloud, SoftwareIcon }; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/tagCloud/TagCloud.module.css b/src/FilterLists.Web/src/components/tagCloud/TagCloud.module.css new file mode 100644 index 000000000..3bee840b6 --- /dev/null +++ b/src/FilterLists.Web/src/components/tagCloud/TagCloud.module.css @@ -0,0 +1,4 @@ +/* allow for 2nd row's tags' bottom border to not be chopped in AllListsTable */ +.grow { + max-height: none !important; +} diff --git a/src/FilterLists.Web/src/components/tagCloud/TagCloud.tsx b/src/FilterLists.Web/src/components/tagCloud/TagCloud.tsx new file mode 100644 index 000000000..45b0d4073 --- /dev/null +++ b/src/FilterLists.Web/src/components/tagCloud/TagCloud.tsx @@ -0,0 +1,19 @@ +import { Tag } from 'antd'; +import React from 'react'; + +import { Tag as TagInterface } from '../../interfaces/Tag'; +import styles from './TagCloud.module.css'; + +interface Props { + tags: TagInterface[]; + showLabel?: boolean; +}; + +export const TagCloud = (props: Props) => + props.tags && props.tags.length + ?
+ {props.showLabel &&

{`Tag${props.tags.length > 1 ? "s" : ""}:`}

} + {props.tags.map((t: TagInterface, i: number) => + {t.name})} +
+ : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/components/tagCloud/index.ts b/src/FilterLists.Web/src/components/tagCloud/index.ts new file mode 100644 index 000000000..eeb9fca3f --- /dev/null +++ b/src/FilterLists.Web/src/components/tagCloud/index.ts @@ -0,0 +1,3 @@ +import { TagCloud } from './TagCloud'; + +export { TagCloud }; \ No newline at end of file diff --git a/src/FilterLists.Web/src/hooks/index.ts b/src/FilterLists.Web/src/hooks/index.ts new file mode 100644 index 000000000..1c59895ce --- /dev/null +++ b/src/FilterLists.Web/src/hooks/index.ts @@ -0,0 +1,19 @@ +import { useLanguages } from './useLanguages'; +import { useLicenses } from './useLicenses'; +import { useLists } from './useLists'; +import { useSearchColumnFilter } from './useSearchColumnFilter'; +import { useSoftware } from './useSoftware'; +import { useSyntaxes } from './useSyntaxes'; +import { useTablePageSizer } from './useTablePageSizer'; +import { useTags } from './useTags'; + +export { + useLanguages, + useLicenses, + useLists, + useSearchColumnFilter, + useSoftware, + useSyntaxes, + useTablePageSizer, + useTags +}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/hooks/useApiData.tsx b/src/FilterLists.Web/src/hooks/useApiData.tsx new file mode 100644 index 000000000..4813771bc --- /dev/null +++ b/src/FilterLists.Web/src/hooks/useApiData.tsx @@ -0,0 +1,10 @@ +import { useEffect, useState } from 'react'; + +export const useApiData = (url: string) => { + const [data, setData] = useState(); + useEffect(() => { + const fetchData = async () => (await fetch(url)).json().then(r => setData(r)); + fetchData(); + }, [url]); + return data; +}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/hooks/useLanguages.tsx b/src/FilterLists.Web/src/hooks/useLanguages.tsx new file mode 100644 index 000000000..ed67cd574 --- /dev/null +++ b/src/FilterLists.Web/src/hooks/useLanguages.tsx @@ -0,0 +1,5 @@ +import { Language } from '../interfaces/Language'; +import { useApiData } from './useApiData'; + +export const useLanguages = () => (useApiData("/api/v1/languages") || []) + .sort((a: Language, b: Language) => a.name.localeCompare(b.name)); \ No newline at end of file diff --git a/src/FilterLists.Web/src/hooks/useLicenses.tsx b/src/FilterLists.Web/src/hooks/useLicenses.tsx new file mode 100644 index 000000000..0704ae603 --- /dev/null +++ b/src/FilterLists.Web/src/hooks/useLicenses.tsx @@ -0,0 +1,5 @@ +import { License } from '../interfaces/License'; +import { useApiData } from './useApiData'; + +export const useLicenses = () => (useApiData("/api/v1/licenses") || []) + .sort((a: License, b: License) => a.name.localeCompare(b.name)); \ No newline at end of file diff --git a/src/FilterLists.Web/src/hooks/useLists.tsx b/src/FilterLists.Web/src/hooks/useLists.tsx new file mode 100644 index 000000000..f01f960ef --- /dev/null +++ b/src/FilterLists.Web/src/hooks/useLists.tsx @@ -0,0 +1,11 @@ +import slugify from 'slugify'; + +import { List } from '../interfaces/List'; +import { useApiData } from './useApiData'; + +export const useLists = () => { + const lists = useApiData("/api/v1/lists"); + lists && lists.forEach(l => l.slug = slugify(l.name)); + return (lists || []) + .sort((a: List, b: List) => a.name.localeCompare(b.name)); +}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/hooks/useSearchColumnFilter.tsx b/src/FilterLists.Web/src/hooks/useSearchColumnFilter.tsx new file mode 100644 index 000000000..e0a3c8480 --- /dev/null +++ b/src/FilterLists.Web/src/hooks/useSearchColumnFilter.tsx @@ -0,0 +1,57 @@ +import { Button, Icon, Input } from 'antd'; +import { FilterDropdownProps } from 'antd/lib/table'; +import React, { useEffect, useState } from 'react'; + +interface FilterPropsState { + filterDropdown?: React.ReactNode | ((props: FilterDropdownProps) => React.ReactNode); + filterIcon?: React.ReactNode | ((filtered: boolean) => React.ReactNode); + onFilter?: (value: any, record: T) => boolean; +} + +export const useSearchColumnFilter = (dataIndex: string) => { + const [filterProps, setFilterProps] = useState>({ + filterDropdown: undefined, + filterIcon: undefined, + onFilter: undefined + }); + useEffect(() => { + const handleSearch = (confirm?: () => void) => { + confirm && confirm(); + }; + const handleReset = (clearFilters?: (selectedKeys: string[]) => void) => { + clearFilters && clearFilters([]); + }; + setFilterProps({ + filterDropdown: ({ setSelectedKeys, selectedKeys, confirm, clearFilters }) => ( +
+ setSelectedKeys && setSelectedKeys(e.target.value ? [e.target.value] : [])} + onPressEnter={() => handleSearch(confirm)} + style={{ width: 188, marginBottom: 8, display: 'block' }} /> + + +
+ ), + filterIcon: filtered => , + onFilter: (value, record) => { + const searchValue = (record as any)[dataIndex]; + return searchValue && searchValue.toString().toLowerCase().includes(value.toString().toLowerCase()) + } + }) + }, [dataIndex]); + return filterProps; +}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/hooks/useSoftware.tsx b/src/FilterLists.Web/src/hooks/useSoftware.tsx new file mode 100644 index 000000000..2e21c1e0c --- /dev/null +++ b/src/FilterLists.Web/src/hooks/useSoftware.tsx @@ -0,0 +1,5 @@ +import { Software } from '../interfaces/Software'; +import { useApiData } from './useApiData'; + +export const useSoftware = () => (useApiData("/api/v1/software") || []) + .sort((a: Software, b: Software) => a.name.localeCompare(b.name)); \ No newline at end of file diff --git a/src/FilterLists.Web/src/hooks/useSyntaxes.tsx b/src/FilterLists.Web/src/hooks/useSyntaxes.tsx new file mode 100644 index 000000000..8a61eb92b --- /dev/null +++ b/src/FilterLists.Web/src/hooks/useSyntaxes.tsx @@ -0,0 +1,5 @@ +import { Syntax } from '../interfaces/Syntax'; +import { useApiData } from './useApiData'; + +export const useSyntaxes = () => (useApiData("/api/v1/syntaxes") || []) + .sort((a: Syntax, b: Syntax) => a.name.localeCompare(b.name)); \ No newline at end of file diff --git a/src/FilterLists.Web/src/hooks/useTablePageSizer.tsx b/src/FilterLists.Web/src/hooks/useTablePageSizer.tsx new file mode 100644 index 000000000..979cf8258 --- /dev/null +++ b/src/FilterLists.Web/src/hooks/useTablePageSizer.tsx @@ -0,0 +1,21 @@ +import { useEffect, useState } from 'react'; + +interface TablePageSize { + pageSize: number; + isNarrowWindow: boolean; +}; + +export const useTablePageSizer = () => { + const [state, setState] = useState(calculateSize()); + useEffect(() => { + const updatePageSize = () => setState(calculateSize()); + window.addEventListener('resize', updatePageSize); + return () => window.removeEventListener('resize', updatePageSize); + }, []); + return state; +}; + +const calculateSize = () => ({ + pageSize: Math.floor((window.innerHeight - 211.5) / 56), + isNarrowWindow: window.innerWidth < 576 ? true : false +}); \ No newline at end of file diff --git a/src/FilterLists.Web/src/hooks/useTags.tsx b/src/FilterLists.Web/src/hooks/useTags.tsx new file mode 100644 index 000000000..6495c363a --- /dev/null +++ b/src/FilterLists.Web/src/hooks/useTags.tsx @@ -0,0 +1,5 @@ +import { Tag } from '../interfaces/Tag'; +import { useApiData } from './useApiData'; + +export const useTags = () => (useApiData("/api/v1/tags") || []) + .sort((a: Tag, b: Tag) => a.name.localeCompare(b.name)); \ No newline at end of file diff --git a/src/FilterLists.Web/src/index.tsx b/src/FilterLists.Web/src/index.tsx index 90ba2def7..8fec59ed5 100644 --- a/src/FilterLists.Web/src/index.tsx +++ b/src/FilterLists.Web/src/index.tsx @@ -1,7 +1,8 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import '../node_modules/bootstrap/dist/css/bootstrap.min.css'; -import App from './App'; import './index.css'; +import React from 'react'; +import ReactDOM from 'react-dom'; + +import { App } from './App'; + ReactDOM.render(, document.getElementById('root')); \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/interfaces/Language.ts b/src/FilterLists.Web/src/interfaces/Language.ts similarity index 73% rename from src/FilterLists.Web/src/modules/home/interfaces/Language.ts rename to src/FilterLists.Web/src/interfaces/Language.ts index 4726a4c01..c453f42a6 100644 --- a/src/FilterLists.Web/src/modules/home/interfaces/Language.ts +++ b/src/FilterLists.Web/src/interfaces/Language.ts @@ -1,4 +1,4 @@ -export interface Language { +export interface Language { id: number; filterListIds: number[]; iso6391: string; diff --git a/src/FilterLists.Web/src/modules/home/interfaces/ILicense.ts b/src/FilterLists.Web/src/interfaces/License.ts similarity index 75% rename from src/FilterLists.Web/src/modules/home/interfaces/ILicense.ts rename to src/FilterLists.Web/src/interfaces/License.ts index 52b42da81..ba223d799 100644 --- a/src/FilterLists.Web/src/modules/home/interfaces/ILicense.ts +++ b/src/FilterLists.Web/src/interfaces/License.ts @@ -1,4 +1,4 @@ -export interface ILicense { +export interface License { id: number; descriptionUrl: string; filterListIds: number[]; diff --git a/src/FilterLists.Web/src/modules/home/interfaces/IList.ts b/src/FilterLists.Web/src/interfaces/List.ts similarity index 85% rename from src/FilterLists.Web/src/modules/home/interfaces/IList.ts rename to src/FilterLists.Web/src/interfaces/List.ts index ff8c6cf81..f63bf709a 100644 --- a/src/FilterLists.Web/src/modules/home/interfaces/IList.ts +++ b/src/FilterLists.Web/src/interfaces/List.ts @@ -1,4 +1,4 @@ -export interface IList { +export interface List { id: number; chatUrl: string; description: string; @@ -19,4 +19,7 @@ tagIds: number[]; viewUrl: string; viewUrlMirrors: string[]; + + // auto-generated by useLists hook + slug: string; }; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/interfaces/ISoftware.ts b/src/FilterLists.Web/src/interfaces/Software.ts similarity index 78% rename from src/FilterLists.Web/src/modules/home/interfaces/ISoftware.ts rename to src/FilterLists.Web/src/interfaces/Software.ts index 840a05fb0..d65d4fdcc 100644 --- a/src/FilterLists.Web/src/modules/home/interfaces/ISoftware.ts +++ b/src/FilterLists.Web/src/interfaces/Software.ts @@ -1,4 +1,4 @@ -export interface ISoftware { +export interface Software { id: number; homeUrl: string; isAbpSubscribable: boolean; diff --git a/src/FilterLists.Web/src/modules/home/interfaces/ISyntax.ts b/src/FilterLists.Web/src/interfaces/Syntax.ts similarity index 79% rename from src/FilterLists.Web/src/modules/home/interfaces/ISyntax.ts rename to src/FilterLists.Web/src/interfaces/Syntax.ts index 2dd8fc9ee..c2eea02d4 100644 --- a/src/FilterLists.Web/src/modules/home/interfaces/ISyntax.ts +++ b/src/FilterLists.Web/src/interfaces/Syntax.ts @@ -1,4 +1,4 @@ -export interface ISyntax { +export interface Syntax { id: number; definitionUrl: string; filterListIds: number[]; diff --git a/src/FilterLists.Web/src/interfaces/Tag.ts b/src/FilterLists.Web/src/interfaces/Tag.ts new file mode 100644 index 000000000..755e683f7 --- /dev/null +++ b/src/FilterLists.Web/src/interfaces/Tag.ts @@ -0,0 +1,6 @@ +export interface Tag { + id: number; + description: string; + filterListIds: number[]; + name: string; +}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/Home.tsx b/src/FilterLists.Web/src/modules/home/Home.tsx deleted file mode 100644 index 34350686b..000000000 --- a/src/FilterLists.Web/src/modules/home/Home.tsx +++ /dev/null @@ -1,111 +0,0 @@ -import * as React from "react"; -import { ListsTable, Oneliner } from "./components"; -import { IColumnVisibility } from "./interfaces/IColumnVisibility"; -import { ILicense } from "./interfaces/ILicense"; -import { IList } from "./interfaces/IList"; -import { IMaintainer } from "./interfaces/IMaintainer"; -import { ISoftware } from "./interfaces/ISoftware"; -import { ISyntax } from "./interfaces/ISyntax"; -import { ITag } from "./interfaces/ITag"; -import { Language } from "./interfaces/Language"; - -const columnVisibilityDefaults: IColumnVisibility[] = [ - { column: "Software", visible: true }, - { column: "Languages", visible: true }, - { column: "Tags", visible: true }, - { column: "License", visible: false }, - { column: "Maintainers", visible: false }, - { column: "Subscribe", visible: false } -]; - -interface Props { - languages: Language[]; - licenses: ILicense[]; - lists: IList[]; - maintainers: IMaintainer[]; - software: ISoftware[]; - syntaxes: ISyntax[]; - tags: ITag[]; -}; - -interface IState { - columnVisibility: IColumnVisibility[]; - pageSize: number; -}; - -export class Home extends React.Component { - constructor(props: Props) { - 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 - 340) / 55), 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/FilterLists.Web/src/modules/home/HomeContainer.tsx b/src/FilterLists.Web/src/modules/home/HomeContainer.tsx deleted file mode 100644 index 0c0ea906a..000000000 --- a/src/FilterLists.Web/src/modules/home/HomeContainer.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import * as React from "react"; -import { Home } from "./Home"; -import { ILicense } from "./interfaces/ILicense"; -import { IList } from "./interfaces/IList"; -import { IMaintainer } from "./interfaces/IMaintainer"; -import { ISoftware } from "./interfaces/ISoftware"; -import { ISyntax } from "./interfaces/ISyntax"; -import { ITag } from "./interfaces/ITag"; -import { Language } from "./interfaces/Language"; - -interface IState { - languages: Language[]; - 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.fetchLists(); - this.fetchLanguages(); - this.fetchLicenses(); - this.fetchMaintainers(); - this.fetchSoftware(); - this.fetchSyntaxes(); - this.fetchTags(); - }; - - fetchLanguages() { - fetch("/api/v1/languages") - .then(response => response.json()) - .then(json => { this.setState({ languages: json }); }) - }; - - fetchLicenses() { - fetch("/api/v1/licenses") - .then(response => response.json()) - .then(json => { this.setState({ licenses: json }); }) - }; - - fetchLists() { - fetch("/api/v1/lists") - .then(response => response.json()) - .then(json => { this.setState({ lists: json }); }) - }; - - fetchMaintainers() { - fetch("/api/v1/maintainers") - .then(response => response.json()) - .then(json => { this.setState({ maintainers: json }); }) - }; - - fetchSoftware() { - fetch("/api/v1/software") - .then(response => response.json()) - .then(json => { this.setState({ software: json }); }) - }; - - fetchSyntaxes() { - fetch("/api/v1/syntaxes") - .then(response => response.json()) - .then(json => { this.setState({ syntaxes: json }); }) - }; - - fetchTags() { - fetch("/api/v1/tags") - .then(response => response.json()) - .then(json => { this.setState({ tags: json }); }) - }; - - render() { - return ; - }; -}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/IListDetails.ts b/src/FilterLists.Web/src/modules/home/components/IListDetails.ts deleted file mode 100644 index d5ed31f82..000000000 --- a/src/FilterLists.Web/src/modules/home/components/IListDetails.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { ILicense } from "../interfaces/ILicense"; -import { IMaintainer } from "../interfaces/IMaintainer"; -import { ISyntax } from "../interfaces/ISyntax"; -import { ITag } from "../interfaces/ITag"; -import { Language } from "../interfaces/Language"; - -export interface IListDetails { - id: number; - chatUrl: string; - description: string; - descriptionSourceUrl: string; - donateUrl: string; - emailAddress: string; - forumUrl: string; - homeUrl: string; - issuesUrl: string; - languages: Language[]; - license: ILicense; - maintainers: IMaintainer[]; - name: string; - policyUrl: string; - publishedDate: string; - submissionUrl: string; - syntax: ISyntax; - tags: ITag[]; - viewUrl: string; - viewUrlMirrors: string[]; -}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/Oneliner.tsx b/src/FilterLists.Web/src/modules/home/components/Oneliner.tsx deleted file mode 100644 index b9754c39f..000000000 --- a/src/FilterLists.Web/src/modules/home/components/Oneliner.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from "react"; - -interface Props { - listCount: number; -}; - -export const Oneliner = (props: Props) => - props.listCount > 0 - ?

- The independent, comprehensive directory of {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/FilterLists.Web/src/modules/home/components/TagGroup.tsx b/src/FilterLists.Web/src/modules/home/components/TagGroup.tsx deleted file mode 100644 index a6439ab80..000000000 --- a/src/FilterLists.Web/src/modules/home/components/TagGroup.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import * as React from "react"; -import { getContrast } from "../../../utils"; -import { ITag } from "../interfaces/ITag"; - -interface Props { - tags: ITag[]; -}; - -export const TagGroup = (props: Props) => - 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/FilterLists.Web/src/modules/home/components/detailsExpander/DetailsExpander.tsx b/src/FilterLists.Web/src/modules/home/components/detailsExpander/DetailsExpander.tsx deleted file mode 100644 index 54c7002be..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/DetailsExpander.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import * as React from "react"; -import { IColumnVisibility } from "../../interfaces/IColumnVisibility"; -import { ISoftware } from "../../interfaces/ISoftware"; -import { IListDetails } from "../IListDetails"; -import { InfoCard } from "./infoCard"; -import { LinkButtonGroup } from "./LinkButtonGroup"; -import { MaintainersInfoCard } from "./maintainersInfoCard"; - -interface Props { - columnVisibility: IColumnVisibility[]; - list: IListDetails; - software: ISoftware[]; -}; - -export const DetailsExpander = (props: Props) => -
-
-
-
- - -
-
- -
-
-
-
; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/detailsExpander/LinkButtonGroup.tsx b/src/FilterLists.Web/src/modules/home/components/detailsExpander/LinkButtonGroup.tsx deleted file mode 100644 index 5049b2026..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/LinkButtonGroup.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import * as React from "react"; -import { ChatButton, DonateButton, EmailButton, ForumButton, HomeButton, IssuesButton, PolicyButton, SubmitButton, SubscribeButton, ViewButton } from "../linkButtons"; -import "./linkButtonGroup.css"; - -interface Props { - 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: Props) => -
- - - - - - - - - - -
; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/detailsExpander/index.ts b/src/FilterLists.Web/src/modules/home/components/detailsExpander/index.ts deleted file mode 100644 index 741dbb60b..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { DetailsExpander } from "./DetailsExpander"; - -export { DetailsExpander }; diff --git a/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/Description.tsx b/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/Description.tsx deleted file mode 100644 index 93a782295..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/Description.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import * as React from "react"; -import "./description.css"; - -interface Props { - description: string; - url: string; -}; - -export const Description = (props: Props) => - props.description - ?

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

- : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/InfoCard.tsx b/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/InfoCard.tsx deleted file mode 100644 index fd52dac1f..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/InfoCard.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import * as React from "react"; -import { IColumnVisibility } from "../../../interfaces/IColumnVisibility"; -import { ILicense } from "../../../interfaces/ILicense"; -import { ISoftware } from "../../../interfaces/ISoftware"; -import { ISyntax } from "../../../interfaces/ISyntax"; -import { ITag } from "../../../interfaces/ITag"; -import { Language } from "../../../interfaces/Language"; -import { SoftwareIcon } from "../../softwareIcon"; -import { TagGroup } from "../../TagGroup"; -import { Description } from "./Description"; -import { Languages } from "./Languages"; -import { License } from "./License"; -import { PublishedDate } from "./PublishedDate"; -import { Syntax } from "./Syntax"; - -interface Props { - columnVisibility: IColumnVisibility[]; - description: string; - descriptionSourceUrl: string; - languages: Language[]; - license: ILicense; - name: string; - publishedDate: string; - software: ISoftware[]; - syntax: ISyntax; - tags: ITag[]; -}; - -export const InfoCard = (props: Props) => -
- {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 === "License")[0].visible - ? null - : } -
-
; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/Languages.tsx b/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/Languages.tsx deleted file mode 100644 index cb3989273..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/Languages.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import * as React from "react"; -import { Language } from "../../../interfaces/Language"; - -interface Props { - languages: Language[]; -}; - -export const Languages = (props: Props) => - props.languages && props.languages.length > 0 - ? props.languages.length > 1 - ?
  • -

    Languages:

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

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

    -
  • - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/License.tsx b/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/License.tsx deleted file mode 100644 index 0c2c51776..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/License.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import * as React from "react"; -import { ILicense } from "../../../interfaces/ILicense"; - -interface Props { - license: ILicense; -}; - -export const License = (props: Props) => - 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/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/PublishedDate.tsx b/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/PublishedDate.tsx deleted file mode 100644 index 67325b70a..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/PublishedDate.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import moment from 'moment'; -import * as React from "react"; - -interface Props { - date: string; -}; - -export const PublishedDate = (props: Props) => - props.date - ?
  • -

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

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

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

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

    Syntax: {props.syntax.name}

    -
  • - :
  • -

    Syntax: {props.syntax.name}

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

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

    -
  • - : null; diff --git a/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/description.css b/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/description.css deleted file mode 100644 index 2a1267485..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/description.css +++ /dev/null @@ -1 +0,0 @@ -.fl-description { margin: 0 0 .5rem; } \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/index.ts b/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/index.ts deleted file mode 100644 index 260aed18f..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/infoCard/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { InfoCard } from "./InfoCard"; - -export { InfoCard }; diff --git a/src/FilterLists.Web/src/modules/home/components/detailsExpander/linkButtonGroup.css b/src/FilterLists.Web/src/modules/home/components/detailsExpander/linkButtonGroup.css deleted file mode 100644 index a590b0139..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/linkButtonGroup.css +++ /dev/null @@ -1,3 +0,0 @@ -.btn-group-vertical { - display: inline; -} diff --git a/src/FilterLists.Web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerInfoCard.tsx b/src/FilterLists.Web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerInfoCard.tsx deleted file mode 100644 index d773bc9b5..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerInfoCard.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import * as React from "react"; -import { IMaintainer } from "../../../interfaces/IMaintainer"; -import { MaintainerLinkButtonGroup } from "./MaintainerLinkButtonGroup"; - -interface Props { - maintainer: IMaintainer; -}; - -export const MaintainerInfoCard = (props: Props) => - props.maintainer.name - ?
    -
    -

    Maintained by {props.maintainer.name}

    -
    -
    - -
    -
    -
    -
    - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerLinkButtonGroup.tsx b/src/FilterLists.Web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerLinkButtonGroup.tsx deleted file mode 100644 index e8afa1c2c..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainerLinkButtonGroup.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import * as React from "react"; -import { EmailButton, HomeButton, TwitterButton } from "../../linkButtons"; - -interface Props { - emailAddress: string; - homeUrl: string; - name: string; - twitterHandle: string; -}; - -export const MaintainerLinkButtonGroup = (props: Props) => -
    - - - -
    ; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainersInfoCard.tsx b/src/FilterLists.Web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainersInfoCard.tsx deleted file mode 100644 index dc31c5772..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/maintainersInfoCard/MaintainersInfoCard.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from "react"; -import { IMaintainer } from "../../../interfaces/IMaintainer"; -import { MaintainerInfoCard } from "./MaintainerInfoCard"; - -interface Props { - maintainers: IMaintainer[]; -}; - -export const MaintainersInfoCard = (props: Props) => - props.maintainers && props.maintainers.length > 0 - ?
    - {props.maintainers.map((m: IMaintainer, i: number) => )} -
    - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/detailsExpander/maintainersInfoCard/index.ts b/src/FilterLists.Web/src/modules/home/components/detailsExpander/maintainersInfoCard/index.ts deleted file mode 100644 index 162aa5359..000000000 --- a/src/FilterLists.Web/src/modules/home/components/detailsExpander/maintainersInfoCard/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { MaintainersInfoCard } from "./MaintainersInfoCard"; - -export { MaintainersInfoCard }; diff --git a/src/FilterLists.Web/src/modules/home/components/index.ts b/src/FilterLists.Web/src/modules/home/components/index.ts deleted file mode 100644 index feee39ff4..000000000 --- a/src/FilterLists.Web/src/modules/home/components/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { DetailsExpander } from "./detailsExpander"; -import { ListsTable } from "./listsTable"; -import { Oneliner } from "./Oneliner"; - -export { DetailsExpander, ListsTable, Oneliner }; diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/ChatButton.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/ChatButton.tsx deleted file mode 100644 index 573a4a1b3..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/ChatButton.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from "react"; -import { LinkButton } from "./LinkButton"; - -interface Props { - name: string; - url: string; -}; - -export const ChatButton = (props: Props) => - props.url - ? - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/DonateButton.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/DonateButton.tsx deleted file mode 100644 index 8ac2711a1..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/DonateButton.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from "react"; -import { LinkButton } from "./LinkButton"; - -interface Props { - name: string; - url: string; -}; - -export const DonateButton = (props: Props) => - props.url - ? - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/EmailButton.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/EmailButton.tsx deleted file mode 100644 index 0b7e6f8bc..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/EmailButton.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from "react"; -import { LinkButton } from "./LinkButton"; - -interface Props { - name: string; - emailAddress: string; -}; - -export const EmailButton = (props: Props) => - props.emailAddress - ? - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/ForumButton.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/ForumButton.tsx deleted file mode 100644 index 756bcef71..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/ForumButton.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from "react"; -import { LinkButton } from "./LinkButton"; - -interface Props { - name: string; - url: string; -}; - -export const ForumButton = (props: Props) => - props.url - ? - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/HomeButton.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/HomeButton.tsx deleted file mode 100644 index d9add0cb2..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/HomeButton.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from "react"; -import { LinkButton } from "./LinkButton"; - -interface Props { - name: string; - url: string; -}; - -export const HomeButton = (props: Props) => - props.url - ? - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/IssuesButton.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/IssuesButton.tsx deleted file mode 100644 index 8b00c10ee..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/IssuesButton.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from "react"; -import { LinkButton } from "./LinkButton"; - -interface Props { - name: string; - url: string; -}; - -export const IssuesButton = (props: Props) => - props.url - ? - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/LinkButton.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/LinkButton.tsx deleted file mode 100644 index a8a003a71..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/LinkButton.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import * as React from "react"; -import { Button, ButtonProps } from "react-bootstrap"; - -interface Props { - href: string; - variant?: ButtonProps["variant"], - title?: string; - text: string; -}; - -export const LinkButton = (props: Props) => - props.href - ? - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/PolicyButton.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/PolicyButton.tsx deleted file mode 100644 index 0107e7200..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/PolicyButton.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from "react"; -import { LinkButton } from "./LinkButton"; - -interface Props { - name: string; - url: string; -}; - -export const PolicyButton = (props: Props) => - props.url - ? - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/SubmitButton.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/SubmitButton.tsx deleted file mode 100644 index 2de8de818..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/SubmitButton.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from "react"; -import { LinkButton } from "./LinkButton"; - -interface Props { - name: string; - url: string; -}; - -export const SubmitButton = (props: Props) => - props.url - ? - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/SubscribeButton/SubscribeButton.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/SubscribeButton/SubscribeButton.tsx deleted file mode 100644 index 67e19c951..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/SubscribeButton/SubscribeButton.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import * as React from "react"; -import { ButtonProps } from "react-bootstrap"; -import { LinkButton } from "../LinkButton"; - -interface Props { - name: string; - url: string; - text?: string; -}; - -export const SubscribeButton = (props: Props) => { - let buttonVariant: ButtonProps["variant"]; - let titlePrefix: string; - - if (props.url.indexOf(".onion/") > 0) { - buttonVariant = "success"; - titlePrefix = "Tor address - "; - } else if (props.url.indexOf("http://") === 0) { - buttonVariant = "danger"; - titlePrefix = "Not Secure - "; - } else { - buttonVariant = 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; -}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/SubscribeButton/SubscribeButtonGroup.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/SubscribeButton/SubscribeButtonGroup.tsx deleted file mode 100644 index 5e876d6c3..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/SubscribeButton/SubscribeButtonGroup.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import * as React from "react"; -import { SubscribeButton } from "./SubscribeButton"; -import { SubscribeButtonGroupDropdown } from "./SubscribeButtonGroupDropdown"; - -interface Props { - name: string; - url: string; - urlMirrors?: string[]; -}; - -export const SubscribeButtonGroup = (props: Props) => - props.url - ? (props.urlMirrors && props.urlMirrors.length > 0) - ? - : - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/SubscribeButton/SubscribeButtonGroupDropdown.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/SubscribeButton/SubscribeButtonGroupDropdown.tsx deleted file mode 100644 index 922c9a5e2..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/SubscribeButton/SubscribeButtonGroupDropdown.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import * as React from "react"; -import { Dropdown, DropdownButton } from "react-bootstrap"; -import { SubscribeButton } from "./SubscribeButton"; - -interface Props { - name: string; - url: string; - urlMirrors: string[]; -}; - -export const SubscribeButtonGroupDropdown = (props: Props) => { - 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) => - - - )} - ; -}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/SubscribeButton/index.ts b/src/FilterLists.Web/src/modules/home/components/linkButtons/SubscribeButton/index.ts deleted file mode 100644 index 870bea9c7..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/SubscribeButton/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { SubscribeButtonGroup } from "./SubscribeButtonGroup"; - -export { SubscribeButtonGroup as SubscribeButton }; diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/TwitterButton.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/TwitterButton.tsx deleted file mode 100644 index e632dc519..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/TwitterButton.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import * as React from "react"; -import { LinkButton } from "./LinkButton"; - -interface Props { - name: string; - twitterHandle: string; -}; - -export const TwitterButton = (props: Props) => - props.twitterHandle - ? - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/ViewButton/ViewButton.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/ViewButton/ViewButton.tsx deleted file mode 100644 index 221238fdd..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/ViewButton/ViewButton.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import * as React from "react"; -import { LinkButton } from "../LinkButton"; - -interface Props { - name: string; - url: string; - text?: string; -}; - -export const ViewButton = (props: Props) => { - - 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/FilterLists.Web/src/modules/home/components/linkButtons/ViewButton/ViewButtonGroup.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/ViewButton/ViewButtonGroup.tsx deleted file mode 100644 index adc0cb388..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/ViewButton/ViewButtonGroup.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import * as React from "react"; -import { ViewButton } from "./ViewButton"; -import { ViewButtonGroupDropdown } from "./ViewButtonGroupDropdown"; - -interface Props { - name: string; - url: string; - urlMirrors?: string[]; -}; - -export const ViewButtonGroup = (props: Props) => - props.url - ? (props.urlMirrors && props.urlMirrors.length > 0) - ? - : - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/ViewButton/ViewButtonGroupDropdown.tsx b/src/FilterLists.Web/src/modules/home/components/linkButtons/ViewButton/ViewButtonGroupDropdown.tsx deleted file mode 100644 index a72a6cece..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/ViewButton/ViewButtonGroupDropdown.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import * as React from "react"; -import { Dropdown, DropdownButton } from "react-bootstrap"; -import { ViewButton } from "./ViewButton"; - -interface Props { - name: string; - url: string; - urlMirrors: string[]; -}; - -export const ViewButtonGroupDropdown = (props: Props) => { - 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) => - - - )} - ; -}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/ViewButton/index.ts b/src/FilterLists.Web/src/modules/home/components/linkButtons/ViewButton/index.ts deleted file mode 100644 index 6a15392f2..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/ViewButton/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { ViewButtonGroup } from "./ViewButtonGroup"; - -export { ViewButtonGroup as ViewButton }; diff --git a/src/FilterLists.Web/src/modules/home/components/linkButtons/index.ts b/src/FilterLists.Web/src/modules/home/components/linkButtons/index.ts deleted file mode 100644 index 15e7c38f1..000000000 --- a/src/FilterLists.Web/src/modules/home/components/linkButtons/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -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 { SubscribeButton } from "./SubscribeButton"; -import { TwitterButton } from "./TwitterButton"; -import { ViewButton } from "./ViewButton"; - -export { ChatButton, DonateButton, EmailButton, ForumButton, HomeButton, IssuesButton, PolicyButton, SubmitButton, SubscribeButton, TwitterButton, ViewButton }; diff --git a/src/FilterLists.Web/src/modules/home/components/listsTable/ListsTable.tsx b/src/FilterLists.Web/src/modules/home/components/listsTable/ListsTable.tsx deleted file mode 100644 index 3816e7c1f..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/ListsTable.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import * as React from "react"; -import ReactTable from "react-table"; -import "react-table/react-table.css"; -import "../../../../utils/loader.css"; -import { DetailsExpander } from "../../components"; -import { IColumnVisibility } from "../../interfaces/IColumnVisibility"; -import { ILicense } from "../../interfaces/ILicense"; -import { IList } from "../../interfaces/IList"; -import { IMaintainer } from "../../interfaces/IMaintainer"; -import { ISoftware } from "../../interfaces/ISoftware"; -import { ISyntax } from "../../interfaces/ISyntax"; -import { ITag } from "../../interfaces/ITag"; -import { Language } from "../../interfaces/Language"; -import { IListDetails } from "../IListDetails"; -import { DetailsButton, Languages, License, Maintainers, Name, Software, SubscribeButton, Tags } from "./columns"; -import "./listsTable.css"; - -interface Props { - languages: Language[]; - licenses: ILicense[]; - lists: IList[]; - maintainers: IMaintainer[]; - software: ISoftware[]; - syntaxes: ISyntax[]; - tags: ITag[]; - columnVisibility: IColumnVisibility[]; - pageSize: number; -}; - -export const ListsTable = (props: Props) => - 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: Language[]; - 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: Language) => 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, - 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, - viewUrl: props.list.viewUrl, - viewUrlMirrors: props.list.viewUrlMirrors - } as IListDetails); \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/listsTable/columns/DetailsButton.tsx b/src/FilterLists.Web/src/modules/home/components/listsTable/columns/DetailsButton.tsx deleted file mode 100644 index e72c23aff..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/columns/DetailsButton.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import * as React from "react"; -import { Button } from "react-bootstrap"; -import { Column, RowRenderProps } from "react-table"; - -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/FilterLists.Web/src/modules/home/components/listsTable/columns/Languages.tsx b/src/FilterLists.Web/src/modules/home/components/listsTable/columns/Languages.tsx deleted file mode 100644 index 6d8a1e782..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/columns/Languages.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import * as React from "react"; -import { Column, Filter } from "react-table"; -import { IColumnVisibility } from "../../../interfaces/IColumnVisibility"; -import { Language } from "../../../interfaces/Language"; - -export const Languages = (columnVisibility: IColumnVisibility[], languages: Language[]) => { - 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) => filterLanguages({ 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 filterLanguages = (props: any, languages: Language[]) => - ; - -const sortMethod = (a: number[], b: number[], languages: Language[]) => { - if (a && a.length > 0) { - if (b && b.length > 0) { - const aLanguageNames = - languages.filter((l: Language) => a.indexOf(l.id) > -1).map((l: Language) => l.name).join(); - const bLanguageNames = - languages.filter((l: Language) => b.indexOf(l.id) > -1).map((l: Language) => l.name).join(); - return aLanguageNames.toLowerCase() > bLanguageNames.toLowerCase() ? 1 : -1; - } else { - return -1; - } - } else { - return 1; - } -}; - -const Cell = (languageIds: number[], languages: Language[]) => - languageIds - ?
    - {languageIds.map((id: number, i: number) => { - const language = languages.filter((l: Language) => l.id === id)[0]; - return - {language.iso6391} - ; - })} -
    - : null; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/listsTable/columns/License.tsx b/src/FilterLists.Web/src/modules/home/components/listsTable/columns/License.tsx deleted file mode 100644 index 84a221b35..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/columns/License.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import * as React from "react"; -import { Column, Filter } from "react-table"; -import { IColumnVisibility } from "../../../interfaces/IColumnVisibility"; -import { ILicense } from "../../../interfaces/ILicense"; - -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) => filterLicenses({ 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 filterLicenses = (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/FilterLists.Web/src/modules/home/components/listsTable/columns/Maintainers.tsx b/src/FilterLists.Web/src/modules/home/components/listsTable/columns/Maintainers.tsx deleted file mode 100644 index 029e05318..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/columns/Maintainers.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import * as React from "react"; -import { Column, Filter } from "react-table"; -import { IColumnVisibility } from "../../../interfaces/IColumnVisibility"; -import { IMaintainer } from "../../../interfaces/IMaintainer"; - -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) => filterMaintainers({ 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 filterMaintainers = (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/FilterLists.Web/src/modules/home/components/listsTable/columns/Name.tsx b/src/FilterLists.Web/src/modules/home/components/listsTable/columns/Name.tsx deleted file mode 100644 index ab74d9497..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/columns/Name.tsx +++ /dev/null @@ -1,22 +0,0 @@ -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/FilterLists.Web/src/modules/home/components/listsTable/columns/RuleCount.tsx b/src/FilterLists.Web/src/modules/home/components/listsTable/columns/RuleCount.tsx deleted file mode 100644 index 90ee34b70..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/columns/RuleCount.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import * as React from "react"; -import { Column } from "react-table"; -import { IColumnVisibility } from "../../../interfaces/IColumnVisibility"; - -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/FilterLists.Web/src/modules/home/components/listsTable/columns/Software.tsx b/src/FilterLists.Web/src/modules/home/components/listsTable/columns/Software.tsx deleted file mode 100644 index 8644ea981..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/columns/Software.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import * as React from "react"; -import { Column, Filter } from "react-table"; -import { IColumnVisibility } from "../../../interfaces/IColumnVisibility"; -import { ISoftware } from "../../../interfaces/ISoftware"; -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) => filterSoftware({ 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 filterSoftware = (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/FilterLists.Web/src/modules/home/components/listsTable/columns/SubscribeButton.tsx b/src/FilterLists.Web/src/modules/home/components/listsTable/columns/SubscribeButton.tsx deleted file mode 100644 index 42e89260b..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/columns/SubscribeButton.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import * as React from "react"; -import { Column, Filter } from "react-table"; -import { IColumnVisibility } from "../../../interfaces/IColumnVisibility"; -import { SubscribeButton as SubscribeButtonBase } 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/FilterLists.Web/src/modules/home/components/listsTable/columns/Syntax.tsx b/src/FilterLists.Web/src/modules/home/components/listsTable/columns/Syntax.tsx deleted file mode 100644 index 773e52cea..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/columns/Syntax.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import * as React from "react"; -import { Column, Filter } from "react-table"; -import { IColumnVisibility } from "../../../interfaces/IColumnVisibility"; -import { ISyntax } from "../../../interfaces/ISyntax"; - -//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) => filterSyntaxes({ 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 filterSyntaxes = (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/FilterLists.Web/src/modules/home/components/listsTable/columns/Tags.tsx b/src/FilterLists.Web/src/modules/home/components/listsTable/columns/Tags.tsx deleted file mode 100644 index 76957a4e5..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/columns/Tags.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import * as React from "react"; -import { Column, Filter } from "react-table"; -import { IColumnVisibility } from "../../../interfaces/IColumnVisibility"; -import { ITag } from "../../../interfaces/ITag"; -import { TagGroup } from "../../TagGroup"; - -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) => filterTags({ 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 filterTags = (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/FilterLists.Web/src/modules/home/components/listsTable/columns/UpdatedDate.tsx b/src/FilterLists.Web/src/modules/home/components/listsTable/columns/UpdatedDate.tsx deleted file mode 100644 index 23acf2b89..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/columns/UpdatedDate.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import moment from 'moment'; -import * as React from "react"; -import { Column } from "react-table"; -import { IColumnVisibility } from "../../../interfaces/IColumnVisibility"; - -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/FilterLists.Web/src/modules/home/components/listsTable/columns/index.ts b/src/FilterLists.Web/src/modules/home/components/listsTable/columns/index.ts deleted file mode 100644 index e82dc8aa9..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/columns/index.ts +++ /dev/null @@ -1,13 +0,0 @@ -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 }; diff --git a/src/FilterLists.Web/src/modules/home/components/listsTable/index.ts b/src/FilterLists.Web/src/modules/home/components/listsTable/index.ts deleted file mode 100644 index 6a848e986..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { ListsTable } from "./ListsTable"; - -export { ListsTable, }; diff --git a/src/FilterLists.Web/src/modules/home/components/listsTable/listsTable.css b/src/FilterLists.Web/src/modules/home/components/listsTable/listsTable.css deleted file mode 100644 index 9315f2922..000000000 --- a/src/FilterLists.Web/src/modules/home/components/listsTable/listsTable.css +++ /dev/null @@ -1,16 +0,0 @@ -/* vertically center-align cell contents */ -.rt-tr { - -ms-align-items: center; - -o-align-items: center; - -webkit-align-items: center; - align-items: center; -} - -/* set minimum usable width of table */ -div.rt-tbody, div.rt-thead.-filters, div.rt-thead.-header { min-width: 320px !important; } - -/* prevent cell contents from getting trimmed */ -.fl-wrap-cell { - line-height: 1; - white-space: normal; -} \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/03-AdGuard.png b/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/03-AdGuard.png deleted file mode 100644 index 61471018c..000000000 Binary files a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/03-AdGuard.png and /dev/null differ diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/14-Pi-hole.png b/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/14-Pi-hole.png deleted file mode 100644 index 99c6753a2..000000000 Binary files a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/14-Pi-hole.png and /dev/null differ diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/16-Internet-Explorer-TPL.png b/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/16-Internet-Explorer-TPL.png deleted file mode 100644 index 2b8189c8d..000000000 Binary files a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/16-Internet-Explorer-TPL.png and /dev/null differ diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/28-personalDNSfilter.png b/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/28-personalDNSfilter.png deleted file mode 100644 index 8275b2b17..000000000 Binary files a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/28-personalDNSfilter.png and /dev/null differ diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/index.ts b/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/index.ts deleted file mode 100644 index ff77ce9ff..000000000 --- a/src/FilterLists.Web/src/modules/home/components/softwareIcon/imgs/index.ts +++ /dev/null @@ -1,39 +0,0 @@ -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"; -import img35 from "./35-Shadowsocks.png"; -import img36 from "./36-ShadowsocksR.png"; -import img37 from "./37-Shadowrocket.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, img35, img36, img37 }; - diff --git a/src/FilterLists.Web/src/modules/home/components/softwareIcon/index.ts b/src/FilterLists.Web/src/modules/home/components/softwareIcon/index.ts deleted file mode 100644 index b3f6cc39f..000000000 --- a/src/FilterLists.Web/src/modules/home/components/softwareIcon/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { SoftwareIcon } from "./SoftwareIcon"; - -export { SoftwareIcon }; diff --git a/src/FilterLists.Web/src/modules/home/index.ts b/src/FilterLists.Web/src/modules/home/index.ts deleted file mode 100644 index bace2e88e..000000000 --- a/src/FilterLists.Web/src/modules/home/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { HomeContainer } from "./HomeContainer"; - -export { HomeContainer as Home }; diff --git a/src/FilterLists.Web/src/modules/home/interfaces/IColumnVisibility.ts b/src/FilterLists.Web/src/modules/home/interfaces/IColumnVisibility.ts deleted file mode 100644 index 3f11fd9a6..000000000 --- a/src/FilterLists.Web/src/modules/home/interfaces/IColumnVisibility.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface IColumnVisibility { - column: string; - visible: boolean; -}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/home/interfaces/IMaintainer.ts b/src/FilterLists.Web/src/modules/home/interfaces/IMaintainer.ts deleted file mode 100644 index 421ce83c9..000000000 --- a/src/FilterLists.Web/src/modules/home/interfaces/IMaintainer.ts +++ /dev/null @@ -1,8 +0,0 @@ -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/FilterLists.Web/src/modules/home/interfaces/ITag.ts b/src/FilterLists.Web/src/modules/home/interfaces/ITag.ts deleted file mode 100644 index 62e526469..000000000 --- a/src/FilterLists.Web/src/modules/home/interfaces/ITag.ts +++ /dev/null @@ -1,6 +0,0 @@ -export interface ITag { - id: number; - description: string; - filterListIds: number[]; - name: string; -}; \ No newline at end of file diff --git a/src/FilterLists.Web/src/modules/index.ts b/src/FilterLists.Web/src/modules/index.ts deleted file mode 100644 index 26437089f..000000000 --- a/src/FilterLists.Web/src/modules/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Home } from "./home"; - -export { Home }; diff --git a/src/FilterLists.Web/src/react-app-env.d.ts b/src/FilterLists.Web/src/react-app-env.d.ts index 6431bc5fc..6889c6b37 100644 --- a/src/FilterLists.Web/src/react-app-env.d.ts +++ b/src/FilterLists.Web/src/react-app-env.d.ts @@ -1 +1 @@ -/// +/// \ No newline at end of file diff --git a/src/FilterLists.Web/src/utils/GetContrast.ts b/src/FilterLists.Web/src/utils/GetContrast.ts deleted file mode 100644 index 0dc5f4e55..000000000 --- a/src/FilterLists.Web/src/utils/GetContrast.ts +++ /dev/null @@ -1,8 +0,0 @@ -//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/FilterLists.Web/src/utils/index.ts b/src/FilterLists.Web/src/utils/index.ts index 4646f2030..d22b49973 100644 --- a/src/FilterLists.Web/src/utils/index.ts +++ b/src/FilterLists.Web/src/utils/index.ts @@ -1,3 +1,3 @@ -import { getContrast } from "./GetContrast"; +import { nameof } from './nameof'; -export { getContrast }; +export { nameof }; \ No newline at end of file diff --git a/src/FilterLists.Web/src/utils/loader.css b/src/FilterLists.Web/src/utils/loader.css deleted file mode 100644 index bdf0e7446..000000000 --- a/src/FilterLists.Web/src/utils/loader.css +++ /dev/null @@ -1,70 +0,0 @@ -/*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; - } -} diff --git a/src/FilterLists.Web/src/utils/nameof.ts b/src/FilterLists.Web/src/utils/nameof.ts new file mode 100644 index 000000000..5a09f50fa --- /dev/null +++ b/src/FilterLists.Web/src/utils/nameof.ts @@ -0,0 +1,2 @@ +//https://stackoverflow.com/a/50470026/2343739 +export const nameof = (name: Extract) => name; \ No newline at end of file diff --git a/src/FilterLists.Web/tsconfig.json b/src/FilterLists.Web/tsconfig.json index 0980b23fa..213390d38 100644 --- a/src/FilterLists.Web/tsconfig.json +++ b/src/FilterLists.Web/tsconfig.json @@ -17,9 +17,10 @@ "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, - "jsx": "preserve" + "jsx": "preserve", + "noImplicitAny": true }, "include": [ "src" ] -} +} \ No newline at end of file