add link buttons to drawer, ditch dropdown button for subscribe

This commit is contained in:
Collin M. Barrett 2019-08-25 20:54:04 -05:00
parent 7546c7e655
commit 60711b53e4
7 changed files with 144 additions and 116 deletions

View file

@ -0,0 +1,23 @@
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) =>
<Button
href={props.url}
title={props.title}
type={props.type || "default"}
block
style={{ borderLeftColor: "rgb(217, 217, 217)" }} //HACK: override buggy style in antd
icon={props.icon}
target="_blank" rel="noopener noreferrer" >
{props.text}
</Button >;

View file

@ -11,6 +11,7 @@ interface Props {
export const ListDetailsButton = (props: RouteComponentProps & Props) =>
<Button
type="primary"
icon="info-circle"
onClick={() => props.history.push(`/lists/${props.list.id}`)}>
Details
</Button>;

View file

@ -1,4 +1,5 @@
import { Drawer } from 'antd';
import { Divider, Drawer } from 'antd';
import ButtonGroup from 'antd/lib/button/button-group';
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
@ -7,7 +8,8 @@ import { List } from '../interfaces/List';
import { Tag } from '../interfaces/Tag';
import { Description } from './Description';
import { LanguageCloud } from './languageCloud';
import { SubscribeButton } from './subscribeButton';
import { LinkButton } from './LinkButton';
import { SubscribeButton } from './SubscribeButton';
import { TagCloud } from './tagCloud';
interface Props {
@ -46,7 +48,55 @@ export class ListDetailsDrawer extends React.Component<RouteComponentProps & Pro
{this.props.list.tagIds
? <TagCloud tags={this.props.tags.filter((t: Tag) => this.props.list.tagIds.includes(t.id))} showLabel={true} />
: null}
<SubscribeButton {...this.props.list} />
<Divider />
<ButtonGroup style={{ display: "inherit" }}>
{this.props.list.viewUrl && <SubscribeButton {...this.props.list} />}
{this.props.list.viewUrl &&
<LinkButton url={this.props.list.viewUrl}
text="View"
title={`View ${this.props.list.name} in its raw format`}
icon="search" />}
{this.props.list.homeUrl &&
<LinkButton url={this.props.list.homeUrl}
text="Home"
title={`View ${this.props.list.name}'s homepage.`}
icon="home" />}
{this.props.list.policyUrl &&
<LinkButton url={this.props.list.policyUrl}
text="Policy"
title={`View the types of rules that ${this.props.list.name} includes.`}
icon="file-exclamation" />}
{this.props.list.emailAddress &&
<LinkButton url={`mailto:${this.props.list.emailAddress}`}
text="Email"
title={`Email ${this.props.list.name}.`}
icon="mail" />}
{this.props.list.issuesUrl &&
<LinkButton url={this.props.list.issuesUrl}
text="GitHub Issues"
title={`View the GitHub Issues for ${this.props.list.name}.`}
icon="github" />}
{this.props.list.submissionUrl &&
<LinkButton url={this.props.list.submissionUrl}
text="Submit a Rule"
title={`Submit a new rule to be included in ${this.props.list.name}.`}
icon="form" />}
{this.props.list.forumUrl &&
<LinkButton url={this.props.list.forumUrl}
text="Forum"
title={`View the forum for ${this.props.list.name}.`}
icon="team" />}
{this.props.list.chatUrl &&
<LinkButton url={this.props.list.chatUrl}
text="Chat"
title={`Enter the chat room for ${this.props.list.name}.`}
icon="message" />}
{this.props.list.donateUrl &&
<LinkButton url={this.props.list.donateUrl}
text="Donate"
title={`Donate to the maintainer of ${this.props.list.name}.`}
icon="dollar" />}
</ButtonGroup>
</Drawer>
}

View file

@ -0,0 +1,67 @@
import { Button } from 'antd';
import { ButtonProps, ButtonType } from 'antd/lib/button';
import React from 'react';
interface Props {
name: string;
viewUrl: string;
viewUrlMirrors: string[];
};
export const SubscribeButton = (props: Props): JSX.Element => {
const buttonProps = buildButtonProps(props.name, props.viewUrl);
return <span>
<Button disabled={buttonProps[1]}
block
icon="import"
{...buttonProps[0]}>
Subscribe
</Button>
{props.viewUrlMirrors && props.viewUrlMirrors.length &&
props.viewUrlMirrors.map((viewUrlMirror: string, i: number) => {
const buttonProps = buildButtonProps(props.name, viewUrlMirror);
return <Button key={i}
disabled={buttonProps[1]}
block
icon="import"
{...buttonProps[0]}>
{`Mirror ${i + 1} Subscribe`}
</Button>
})}
</span>
};
const buildButtonProps = (name: string, viewUrl: string): [ButtonProps, boolean] => {
let type: ButtonType = "primary";
let disabled: boolean = false;
const hrefLocation = `${encodeURIComponent(viewUrl)}`;
const hrefTitle = `${encodeURIComponent(name)}`;
let href = `abp:subscribe?location=${hrefLocation}&amp;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 [{ type, href, title }, disabled]
}

View file

@ -1,14 +0,0 @@
.sub_li {
/* reduce vertical white space around dropdown items */
height: 24px !important;
}
.sub_a {
/* fix font color on dropdown buttons */
color: #fff !important;
}
.single {
/* make non-dropdown button equivalent width to dropdown */
width: 106.81px;
}

View file

@ -1,96 +0,0 @@
import { Button, Dropdown, Menu } from 'antd';
import { ButtonProps, ButtonType } from 'antd/lib/button';
import React from 'react';
import styles from './SubscribeButton.module.css';
//TODO: import DropdownButtonType from antd rather than redefining if they export the type
//import { DropdownButtonType } from "antd/lib/dropdown";
declare type DropdownButtonType = 'primary' | 'ghost' | 'dashed';
interface Props {
name: string;
viewUrl: string;
viewUrlMirrors: string[];
};
export const SubscribeButton = (props: Props): JSX.Element => {
const buttonProps = buildButtonProps(props.name, props.viewUrl);
return (props.viewUrlMirrors && props.viewUrlMirrors.length)
? <ButtonDropdown {...props} />
: <div>
<Button disabled={buttonProps[1]}
className={styles.single} size="small"
{...buttonProps[0]}>
Subscribe
</Button>
</div>
};
const ButtonDropdown = (props: Props): JSX.Element => {
const buttonProps = buildButtonProps(props.name, props.viewUrl);
return <Dropdown.Button
disabled={buttonProps[1]}
size="small"
placement="bottomRight"
type={buttonProps[0].type as DropdownButtonType}
href={buttonProps[0].href}
title={buttonProps[0].title}
overlay={<DropdownOverlay viewUrlMirrors={props.viewUrlMirrors} name={props.name} />}>
Subscribe
</Dropdown.Button>;
};
interface DropdownOverlayProps {
name: string;
viewUrlMirrors: string[];
};
const DropdownOverlay = (props: DropdownOverlayProps): JSX.Element =>
<Menu>
{props.viewUrlMirrors.map((viewUrlMirror: string, i: number) => {
const buttonProps = buildButtonProps(props.name, viewUrlMirror);
return <Menu.Item className={styles.sub_li} key={i}>
<Button disabled={buttonProps[1]}
className={styles.sub_a} size="small"
{...buttonProps[0]}>
{`Mirror ${i + 1}`}
</Button>
</Menu.Item>
})}
</Menu>;
const buildButtonProps = (name: string, viewUrl: string): [ButtonProps, boolean] => {
let type: ButtonType = "primary";
let disabled: boolean = false;
const hrefLocation = `${encodeURIComponent(viewUrl)}`;
const hrefTitle = `${encodeURIComponent(name)}`;
let href = `abp:subscribe?location=${hrefLocation}&amp;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 [{ type, href, title }, disabled]
}

View file

@ -1,3 +0,0 @@
import { SubscribeButton } from './SubscribeButton';
export { SubscribeButton }