From 34bdb6d9a87eb991c17b57612e6de89c0c5d9174 Mon Sep 17 00:00:00 2001 From: chris48s Date: Sun, 19 Mar 2023 15:31:40 +0000 Subject: [PATCH 01/34] delete loads of really important stuff that we definitely need --- frontend/components/badge-examples.tsx | 108 ----- frontend/components/category-headings.tsx | 84 ---- frontend/components/common.tsx | 125 ----- .../components/customizer/builder-common.tsx | 46 -- .../customizer/copied-content-indicator.tsx | 73 --- frontend/components/customizer/customizer.tsx | 156 ------ .../components/customizer/path-builder.tsx | 258 ---------- .../customizer/query-string-builder.tsx | 348 -------------- .../customizer/request-markup-button.tsx | 134 ------ frontend/components/development/logo-page.tsx | 77 --- .../components/development/style-page.tsx | 168 ------- frontend/components/donate.tsx | 16 - frontend/components/dynamic-badge-maker.tsx | 103 ---- frontend/components/footer.tsx | 83 ---- frontend/components/header.tsx | 26 - frontend/components/main.tsx | 185 -------- frontend/components/markup-modal/index.tsx | 35 -- .../markup-modal/markup-modal-content.tsx | 44 -- frontend/components/meta.tsx | 25 - frontend/components/search.tsx | 36 -- frontend/components/snippet.tsx | 61 --- frontend/components/static-badge-maker.tsx | 77 --- frontend/components/usage.tsx | 447 ------------------ frontend/constants.ts | 36 -- frontend/gatsby-browser.js | 18 - frontend/gatsby-config.js | 33 -- frontend/gatsby-node.js | 45 -- frontend/lib/generate-image-markup.spec.ts | 72 --- frontend/lib/generate-image-markup.ts | 99 ---- frontend/lib/pattern-helpers.spec.ts | 28 -- frontend/lib/pattern-helpers.ts | 34 -- frontend/lib/redirect-legacy-routes.ts | 15 - .../lib/service-definitions/index.spec.ts | 16 - frontend/lib/service-definitions/index.ts | 67 --- .../service-definition-set-helper.spec.ts | 31 -- .../service-definition-set-helper.ts | 54 --- frontend/lib/supported-features.ts | 5 - frontend/package.json | 32 -- frontend/pages/community.tsx | 118 ----- frontend/pages/endpoint.tsx | 255 ---------- frontend/pages/index.tsx | 2 - frontend/types/assets.d.ts | 5 - .../mapbox__react-click-to-select/index.d.ts | 11 - scripts/export-service-definitions-cli.js | 11 - scripts/export-supported-features-cli.js | 22 - 45 files changed, 3724 deletions(-) delete mode 100644 frontend/components/badge-examples.tsx delete mode 100644 frontend/components/category-headings.tsx delete mode 100644 frontend/components/common.tsx delete mode 100644 frontend/components/customizer/builder-common.tsx delete mode 100644 frontend/components/customizer/copied-content-indicator.tsx delete mode 100644 frontend/components/customizer/customizer.tsx delete mode 100644 frontend/components/customizer/path-builder.tsx delete mode 100644 frontend/components/customizer/query-string-builder.tsx delete mode 100644 frontend/components/customizer/request-markup-button.tsx delete mode 100644 frontend/components/development/logo-page.tsx delete mode 100644 frontend/components/development/style-page.tsx delete mode 100644 frontend/components/donate.tsx delete mode 100644 frontend/components/dynamic-badge-maker.tsx delete mode 100644 frontend/components/footer.tsx delete mode 100644 frontend/components/header.tsx delete mode 100644 frontend/components/main.tsx delete mode 100644 frontend/components/markup-modal/index.tsx delete mode 100644 frontend/components/markup-modal/markup-modal-content.tsx delete mode 100644 frontend/components/meta.tsx delete mode 100644 frontend/components/search.tsx delete mode 100644 frontend/components/snippet.tsx delete mode 100644 frontend/components/static-badge-maker.tsx delete mode 100644 frontend/components/usage.tsx delete mode 100644 frontend/constants.ts delete mode 100644 frontend/gatsby-browser.js delete mode 100644 frontend/gatsby-config.js delete mode 100644 frontend/gatsby-node.js delete mode 100644 frontend/lib/generate-image-markup.spec.ts delete mode 100644 frontend/lib/generate-image-markup.ts delete mode 100644 frontend/lib/pattern-helpers.spec.ts delete mode 100644 frontend/lib/pattern-helpers.ts delete mode 100644 frontend/lib/redirect-legacy-routes.ts delete mode 100644 frontend/lib/service-definitions/index.spec.ts delete mode 100644 frontend/lib/service-definitions/index.ts delete mode 100644 frontend/lib/service-definitions/service-definition-set-helper.spec.ts delete mode 100644 frontend/lib/service-definitions/service-definition-set-helper.ts delete mode 100644 frontend/lib/supported-features.ts delete mode 100644 frontend/package.json delete mode 100644 frontend/pages/community.tsx delete mode 100644 frontend/pages/endpoint.tsx delete mode 100644 frontend/pages/index.tsx delete mode 100644 frontend/types/assets.d.ts delete mode 100644 frontend/types/mapbox__react-click-to-select/index.d.ts delete mode 100644 scripts/export-service-definitions-cli.js delete mode 100644 scripts/export-supported-features-cli.js diff --git a/frontend/components/badge-examples.tsx b/frontend/components/badge-examples.tsx deleted file mode 100644 index 7d17b81827e2c..0000000000000 --- a/frontend/components/badge-examples.tsx +++ /dev/null @@ -1,108 +0,0 @@ -import React from 'react' -import styled from 'styled-components' -import { - badgeUrlFromPath, - staticBadgeUrl, -} from '../../core/badge-urls/make-badge-url' -import { removeRegexpFromPattern } from '../lib/pattern-helpers' -import { - Example as ExampleData, - RenderableExample, -} from '../lib/service-definitions' -import { Badge } from './common' -import { StyledCode } from './snippet' - -const ExampleTable = styled.table` - min-width: 50%; - margin: auto; - - th, - td { - text-align: left; - } -` - -const ClickableTh = styled.th` - cursor: pointer; -` - -const ClickableCode = styled(StyledCode)` - cursor: pointer; -` - -function Example({ - baseUrl, - onClick, - exampleData, -}: { - baseUrl?: string - onClick: (example: RenderableExample) => void - exampleData: RenderableExample -}): JSX.Element { - const handleClick = React.useCallback( - function (): void { - onClick(exampleData) - }, - [exampleData, onClick] - ) - - const { - example: { pattern, queryParams }, - preview: { label, message, color, style, namedLogo }, - } = exampleData as ExampleData - const previewUrl = staticBadgeUrl({ - baseUrl, - label: label || '', - message, - color, - style, - namedLogo, - }) - const exampleUrl = badgeUrlFromPath({ - path: removeRegexpFromPattern(pattern), - queryParams, - }) - - const { title } = exampleData - return ( - - {title}: - - - - - {exampleUrl} - - - ) -} - -export function BadgeExamples({ - examples, - baseUrl, - onClick, -}: { - examples: RenderableExample[] - baseUrl?: string - onClick: (exampleData: RenderableExample) => void -}): JSX.Element { - return ( - - - {examples.map(exampleData => ( - - ))} - - - ) -} diff --git a/frontend/components/category-headings.tsx b/frontend/components/category-headings.tsx deleted file mode 100644 index 2f1d03c9a512a..0000000000000 --- a/frontend/components/category-headings.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import React from 'react' -import styled from 'styled-components' -import { Link } from 'gatsby' -import { H3 } from './common' - -export interface Category { - id: string - name: string -} - -export function CategoryHeading({ - category: { id, name }, -}: { - category: Category -}): JSX.Element { - return ( - -

{name}

- - ) -} - -export function CategoryHeadings({ - categories, -}: { - categories: Category[] -}): JSX.Element { - return ( -
- {categories.map(category => ( - - ))} -
- ) -} - -const StyledNav = styled.nav` - ul { - display: flex; - - min-width: 50%; - max-width: 500px; - - margin: 0 auto 20px; - padding-inline-start: 0; - - flex-wrap: wrap; - justify-content: center; - - list-style-type: none; - } - - @media screen and (max-width: 768px) { - ul { - display: none; - } - } - - li { - margin: 4px 10px; - } - - .active { - font-weight: 900; - } -` - -export function CategoryNav({ - categories, -}: { - categories: Category[] -}): JSX.Element { - return ( - -
    - {categories.map(({ id, name }) => ( -
  • - {name} -
  • - ))} -
-
- ) -} diff --git a/frontend/components/common.tsx b/frontend/components/common.tsx deleted file mode 100644 index e878e6792be5c..0000000000000 --- a/frontend/components/common.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import React from 'react' -import styled, { css, createGlobalStyle } from 'styled-components' - -export const noAutocorrect = Object.freeze({ - autoComplete: 'off', - autoCorrect: 'off', - autoCapitalize: 'off', - spellcheck: 'false', -}) - -export const nonBreakingSpace = '\u00a0' - -export const GlobalStyle = createGlobalStyle` - * { - box-sizing: border-box; - } -` - -export const BaseFont = styled.div` - font-family: Lekton, sans-serif; - color: #534; -` - -export const H2 = styled.h2` - font-style: italic; - - margin-top: 12mm; - font-variant: small-caps; - - ::before { - content: '☙ '; - } - - ::after { - content: ' ❧'; - } -` - -export const H3 = styled.h3` - font-style: italic; -` - -interface BadgeWrapperProps { - height: string - display: string - clickable: boolean -} - -const BadgeWrapper = styled.span` - padding: 2px; - height: ${({ height }) => height}; - vertical-align: middle; - display: ${({ display }) => display}; - - ${({ clickable }) => - clickable && - css` - cursor: pointer; - `}; -` - -interface BadgeProps extends React.HTMLAttributes { - src: string - alt?: string - display?: 'inline' | 'block' | 'inline-block' - height?: string - clickable?: boolean - object?: boolean -} - -export function Badge({ - src, - alt = '', - display = 'inline', - height = '20px', - clickable = false, - object = false, - ...rest -}: BadgeProps): JSX.Element { - return ( - - {src ? ( - object ? ( - alt - ) : ( - {alt} - ) - ) : ( - nonBreakingSpace - )} - - ) -} - -export const StyledInput = styled.input` - height: 15px; - border: solid #b9a; - border-width: 0 0 1px 0; - padding: 0; - - text-align: center; - - color: #534; - - :focus { - outline: 0; - } -` - -export const InlineInput = styled(StyledInput)` - width: 70px; - margin-left: 5px; - margin-right: 5px; -` - -export const BlockInput = styled(StyledInput)` - width: 40%; - background-color: transparent; -` - -export const VerticalSpace = styled.hr` - border: 0; - display: block; - height: 3mm; -` diff --git a/frontend/components/customizer/builder-common.tsx b/frontend/components/customizer/builder-common.tsx deleted file mode 100644 index 939184028728f..0000000000000 --- a/frontend/components/customizer/builder-common.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import React from 'react' -import styled from 'styled-components' - -const BuilderOuterContainer = styled.div` - margin-top: 10px; - margin-bottom: 10px; -` - -// The inner container is inline-block so that its width matches its columns. -const BuilderInnerContainer = styled.div` - display: inline-block; - - padding: 1px 14px 10px; - - border-radius: 4px; - background: #eef; -` - -export function BuilderContainer({ - children, -}: { - children: JSX.Element[] | JSX.Element -}): JSX.Element { - return ( - - {children} - - ) -} - -const labelFont = ` - font-family: system-ui; - font-size: 11px; -` - -export const BuilderLabel = styled.label` - ${labelFont} - - text-transform: lowercase; -` - -export const BuilderCaption = styled.span` - ${labelFont} - - color: #999; -` diff --git a/frontend/components/customizer/copied-content-indicator.tsx b/frontend/components/customizer/copied-content-indicator.tsx deleted file mode 100644 index a45a0dfb9b147..0000000000000 --- a/frontend/components/customizer/copied-content-indicator.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import React, { useState, useImperativeHandle, forwardRef } from 'react' -import posed from 'react-pose' -import styled from 'styled-components' - -const ContentAnchor = styled.span` - position: relative; - display: inline-block; -` - -// 100vw allows providing styled content which is wider than its container. -const ContentContainer = styled.span` - width: 100vw; - - position: absolute; - left: 50%; - transform: translateX(-50%); - - will-change: opacity, top; - - pointer-events: none; -` - -const PosedContentContainer = posed(ContentContainer)({ - hidden: { opacity: 0, transition: { duration: 100 } }, - effectStart: { top: '-10px', opacity: 1.0, transition: { duration: 0 } }, - effectEnd: { top: '-75px', opacity: 0.5 }, -}) - -export interface CopiedContentIndicatorHandle { - trigger: () => void -} - -// When `trigger()` is called, render copied content that floats up, then -// disappears. -function _CopiedContentIndicator( - { - copiedContent, - children, - }: { - copiedContent: JSX.Element | string - children: JSX.Element | JSX.Element[] - }, - ref: React.Ref -): JSX.Element { - const [pose, setPose] = useState('hidden') - - useImperativeHandle(ref, () => ({ - trigger() { - setPose('effectStart') - }, - })) - - const handlePoseComplete = React.useCallback( - function (): void { - if (pose === 'effectStart') { - setPose('effectEnd') - } else { - setPose('hidden') - } - }, - [pose, setPose] - ) - - return ( - - - {copiedContent} - - {children} - - ) -} -export const CopiedContentIndicator = forwardRef(_CopiedContentIndicator) diff --git a/frontend/components/customizer/customizer.tsx b/frontend/components/customizer/customizer.tsx deleted file mode 100644 index 503efc6741978..0000000000000 --- a/frontend/components/customizer/customizer.tsx +++ /dev/null @@ -1,156 +0,0 @@ -import React, { useRef, useState } from 'react' -import clipboardCopy from 'clipboard-copy' -import { staticBadgeUrl } from '../../../core/badge-urls/make-badge-url' -import { generateMarkup, MarkupFormat } from '../../lib/generate-image-markup' -import { Badge } from '../common' -import PathBuilder from './path-builder' -import QueryStringBuilder from './query-string-builder' -import RequestMarkupButtom from './request-markup-button' -import { - CopiedContentIndicator, - CopiedContentIndicatorHandle, -} from './copied-content-indicator' - -export default function Customizer({ - baseUrl, - title, - pattern, - exampleNamedParams, - exampleQueryParams, - initialStyle, -}: { - baseUrl: string - title: string - pattern: string - exampleNamedParams: { [k: string]: string } - exampleQueryParams: { [k: string]: string } - initialStyle?: string -}): JSX.Element { - // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/35572 - // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/28884#issuecomment-471341041 - const indicatorRef = - useRef() as React.MutableRefObject - const [path, setPath] = useState('') - const [queryString, setQueryString] = useState() - const [pathIsComplete, setPathIsComplete] = useState() - const [markup, setMarkup] = useState() - const [message, setMessage] = useState() - - const generateBuiltBadgeUrl = React.useCallback( - function (): string { - const suffix = queryString ? `?${queryString}` : '' - return `${baseUrl}${path}${suffix}` - }, - [baseUrl, path, queryString] - ) - - function renderLivePreview(): JSX.Element { - // There are some usability issues here. It would be better if the message - // changed from a validation error to a loading message once the - // parameters were filled in, and also switched back to loading when the - // parameters changed. - let src - if (pathIsComplete) { - src = generateBuiltBadgeUrl() - } else { - src = staticBadgeUrl({ - baseUrl, - label: 'preview', - message: 'some parameters missing', - }) - } - return ( -

- -

- ) - } - - const copyMarkup = React.useCallback( - async function (markupFormat: MarkupFormat): Promise { - const builtBadgeUrl = generateBuiltBadgeUrl() - const markup = generateMarkup({ - badgeUrl: builtBadgeUrl, - title, - markupFormat, - }) - - try { - await clipboardCopy(markup) - } catch (e) { - setMessage('Copy failed') - setMarkup(markup) - return - } - - setMarkup(markup) - if (indicatorRef.current) { - indicatorRef.current.trigger() - } - }, - [generateBuiltBadgeUrl, title, setMessage, setMarkup] - ) - - function renderMarkupAndLivePreview(): JSX.Element { - return ( -
- {renderLivePreview()} - - - - {message && ( -
-

{message}

-

Markup: {markup}

-
- )} -
- ) - } - - const handlePathChange = React.useCallback( - function ({ - path, - isComplete, - }: { - path: string - isComplete: boolean - }): void { - setPath(path) - setPathIsComplete(isComplete) - }, - [setPath, setPathIsComplete] - ) - - const handleQueryStringChange = React.useCallback( - function ({ - queryString, - isComplete, - }: { - queryString: string - isComplete: boolean - }): void { - setQueryString(queryString) - }, - [setQueryString] - ) - - return ( -
- - -
{renderMarkupAndLivePreview()}
- - ) -} diff --git a/frontend/components/customizer/path-builder.tsx b/frontend/components/customizer/path-builder.tsx deleted file mode 100644 index 5e4d10f653f9e..0000000000000 --- a/frontend/components/customizer/path-builder.tsx +++ /dev/null @@ -1,258 +0,0 @@ -import React, { useState, useEffect, ChangeEvent } from 'react' -import styled, { css } from 'styled-components' -import { Token, Key, parse } from 'path-to-regexp' -import humanizeString from 'humanize-string' -import { patternToOptions } from '../../lib/pattern-helpers' -import { noAutocorrect, StyledInput } from '../common' -import { - BuilderContainer, - BuilderLabel, - BuilderCaption, -} from './builder-common' - -interface PathBuilderColumnProps { - pathContainsOnlyLiterals: boolean - withHorizPadding?: boolean -} - -const PathBuilderColumn = styled.span` - height: ${({ pathContainsOnlyLiterals }) => - pathContainsOnlyLiterals ? '18px' : '78px'}; - - float: left; - display: flex; - flex-direction: column; - - margin: 0; - - ${({ withHorizPadding }) => - withHorizPadding && - css` - padding: 0 8px; - `}; -` - -interface PathLiteralProps { - isFirstToken: boolean - pathContainsOnlyLiterals: boolean -} - -const PathLiteral = styled.div` - margin-top: ${({ pathContainsOnlyLiterals }) => - pathContainsOnlyLiterals ? '0px' : '39px'}; - ${({ isFirstToken }) => - isFirstToken && - css` - margin-left: 3px; - `}; -` - -const NamedParamLabelContainer = styled.span` - display: flex; - flex-direction: column; - height: 37px; - width: 100%; - justify-content: center; -` - -const inputStyling = ` - width: 100%; - text-align: center; -` - -// 2px to align with input boxes alongside. -const NamedParamInput = styled(StyledInput)` - ${inputStyling} - margin-top: 2px; - margin-bottom: 10px; -` - -const NamedParamSelect = styled.select` - ${inputStyling} - margin-bottom: 9px; - font-size: 10px; -` - -const NamedParamCaption = styled(BuilderCaption)` - width: 100%; - text-align: center; -` - -export function constructPath({ - tokens, - namedParams, -}: { - tokens: Token[] - namedParams: { [k: string]: string } -}): { path: string; isComplete: boolean } { - let isComplete = true - let path = tokens - .map(token => { - if (typeof token === 'string') { - return token.trim() - } else { - const { prefix, name, modifier } = token - const value = namedParams[name] - if (value) { - return `${prefix}${value.trim()}` - } else if (modifier === '?' || modifier === '*') { - return '' - } else { - isComplete = false - return `${prefix}:${name}` - } - } - }) - .join('') - path = encodeURI(path) - return { path, isComplete } -} - -export default function PathBuilder({ - pattern, - exampleParams, - onChange, -}: { - pattern: string - exampleParams: { [k: string]: string } - onChange: ({ - path, - isComplete, - }: { - path: string - isComplete: boolean - }) => void -}): JSX.Element { - const [tokens] = useState(() => parse(pattern)) - const [namedParams, setNamedParams] = useState(() => - // `pathToRegexp.parse()` returns a mixed array of strings for literals - // and objects for parameters. Filter out the literals and work with the - // objects. - tokens - .filter(t => typeof t !== 'string') - .map(t => t as Key) - .reduce((accum, { name }) => { - accum[name] = '' - return accum - }, {} as { [k: string]: string }) - ) - - useEffect(() => { - // Ensure the default style is applied right away. - if (onChange) { - const { path, isComplete } = constructPath({ tokens, namedParams }) - onChange({ path, isComplete }) - } - }, [tokens, namedParams, onChange]) - - const handleTokenChange = React.useCallback( - function ({ - target: { name, value }, - }: ChangeEvent): void { - setNamedParams({ - ...namedParams, - [name]: value, - }) - }, - [setNamedParams, namedParams] - ) - - function renderLiteral( - literal: string, - tokenIndex: number, - pathContainsOnlyLiterals: boolean - ): JSX.Element { - return ( - - - {literal} - - - ) - } - - function renderNamedParamInput(token: Key): JSX.Element { - const { pattern } = token - const name = `${token.name}` - const options = patternToOptions(pattern) - - const value = namedParams[name] - - if (options) { - return ( - - - {options.map(option => ( - - ))} - - ) - } else { - return ( - - ) - } - } - - function renderNamedParam( - token: Key, - tokenIndex: number, - namedParamIndex: number - ): JSX.Element { - const { prefix, modifier } = token - const optional = modifier === '?' || modifier === '*' - const name = `${token.name}` - - const exampleValue = exampleParams[name] || '(not set)' - - return ( - - {renderLiteral(prefix, tokenIndex, false)} - - - {humanizeString(name)} - {optional ? (optional) : null} - - {renderNamedParamInput(token)} - - {namedParamIndex === 0 ? `e.g. ${exampleValue}` : exampleValue} - - - - ) - } - - let namedParamIndex = 0 - const pathContainsOnlyLiterals = tokens.every( - token => typeof token === 'string' - ) - return ( - - {tokens.map((token, tokenIndex) => - typeof token === 'string' - ? renderLiteral(token, tokenIndex, pathContainsOnlyLiterals) - : renderNamedParam(token, tokenIndex, namedParamIndex++) - )} - - ) -} diff --git a/frontend/components/customizer/query-string-builder.tsx b/frontend/components/customizer/query-string-builder.tsx deleted file mode 100644 index bb369d0c6b843..0000000000000 --- a/frontend/components/customizer/query-string-builder.tsx +++ /dev/null @@ -1,348 +0,0 @@ -import React, { - useState, - useEffect, - ChangeEvent, - ChangeEventHandler, -} from 'react' -import styled from 'styled-components' -import humanizeString from 'humanize-string' -import qs from 'query-string' -import { advertisedStyles } from '../../lib/supported-features' -import { noAutocorrect, StyledInput } from '../common' -import { - BuilderContainer, - BuilderLabel, - BuilderCaption, -} from './builder-common' - -const QueryParamLabel = styled(BuilderLabel)` - margin: 5px; -` - -const QueryParamInput = styled(StyledInput)` - margin: 5px 10px; -` - -const QueryParamCaption = styled(BuilderCaption)` - margin: 5px; -` - -type BadgeOptionName = 'style' | 'label' | 'color' | 'logo' | 'logoColor' - -interface BadgeOptionInfo { - name: BadgeOptionName - label?: string - shieldsDefaultValue?: string -} - -const supportedBadgeOptions = [ - { name: 'style', shieldsDefaultValue: 'flat' }, - { name: 'label', label: 'override label' }, - { name: 'color', label: 'override color' }, - { name: 'logo', label: 'named logo' }, - { name: 'logoColor', label: 'override logo color' }, -] as BadgeOptionInfo[] - -function getBadgeOption(name: BadgeOptionName): BadgeOptionInfo { - const result = supportedBadgeOptions.find(opt => opt.name === name) - if (!result) { - throw Error(`Unknown badge option: ${name}`) - } - return result -} - -function getQueryString({ - queryParams, - badgeOptions, -}: { - queryParams: Record - badgeOptions: Record -}): { - queryString: string - isComplete: boolean -} { - // Use `string | null`, because `query-string` renders e.g. - // `{ compact_message: null }` as `?compact_message`. This is - // what we want for boolean params that are true (see below). - const outQuery = {} as Record - let isComplete = true - - Object.entries(queryParams).forEach(([name, value]) => { - // As above, there are two types of supported params: strings and - // booleans. - if (typeof value === 'string') { - if (value) { - outQuery[name] = value.trim() - } else { - // Skip empty params. - isComplete = false - } - } else { - // Generate empty query params for boolean parameters by translating - // `{ compact_message: true }` to `?compact_message`. When values are - // false, skip the param. - if (value) { - outQuery[name] = null - } - } - }) - - Object.entries(badgeOptions).forEach(([name, value]) => { - const { shieldsDefaultValue } = getBadgeOption(name as BadgeOptionName) - if (value && value !== shieldsDefaultValue) { - outQuery[name] = value - } - }) - - const queryString = qs.stringify(outQuery) - - return { queryString, isComplete } -} - -function ServiceQueryParam({ - name, - value, - exampleValue, - isStringParam, - stringParamCount, - handleServiceQueryParamChange, -}: { - name: string - value: string | boolean - exampleValue: string - isStringParam: boolean - stringParamCount?: number - handleServiceQueryParamChange: ChangeEventHandler -}): JSX.Element { - return ( - - - - {humanizeString(name).toLowerCase()} - - - - {isStringParam && ( - - {stringParamCount === 0 ? `e.g. ${exampleValue}` : exampleValue} - - )} - - - {isStringParam ? ( - - ) : ( - - )} - - - ) -} - -function BadgeOptionInput({ - name, - value, - handleBadgeOptionChange, -}: { - name: BadgeOptionName - value: string - handleBadgeOptionChange: ChangeEventHandler< - HTMLSelectElement | HTMLInputElement - > -}): JSX.Element { - if (name === 'style') { - return ( - - ) - } else { - return ( - - ) - } -} - -function BadgeOption({ - name, - value, - handleBadgeOptionChange, -}: { - name: BadgeOptionName - value: string - handleBadgeOptionChange: ChangeEventHandler -}): JSX.Element { - const { - label = humanizeString(name), - shieldsDefaultValue: hasShieldsDefaultValue, - } = getBadgeOption(name) - return ( - - - {label} - - - {!hasShieldsDefaultValue && ( - optional - )} - - - - - - ) -} - -// The UI for building the query string, which includes two kinds of settings: -// 1. Custom query params defined by the service, stored in -// `this.state.queryParams` -// 2. The standard badge options which apply to all badges, stored in -// `this.state.badgeOptions` -export default function QueryStringBuilder({ - exampleParams, - initialStyle = 'flat', - onChange, -}: { - exampleParams: { [k: string]: string } - initialStyle?: string - onChange: ({ - queryString, - isComplete, - }: { - queryString: string - isComplete: boolean - }) => void -}): JSX.Element { - const [queryParams, setQueryParams] = useState(() => - // For each of the custom query params defined in `exampleParams`, - // create empty values in `queryParams`. - Object.entries(exampleParams) - .filter( - // If the example defines a value for one of the standard supported - // options, do not duplicate the corresponding parameter. - ([name]) => !supportedBadgeOptions.some(option => name === option.name) - ) - .reduce((accum, [name, value]) => { - // Custom query params are either string or boolean. Inspect the example - // value to infer which one, and set empty values accordingly. - // Throughout the component, these two types are supported in the same - // manner: by inspecting this value type. - const isStringParam = typeof value === 'string' - accum[name] = isStringParam ? '' : true - return accum - }, {} as { [k: string]: string | boolean }) - ) - // For each of the standard badge options, create empty values in - // `badgeOptions`. When `initialStyle` has been provided, use it. - const [badgeOptions, setBadgeOptions] = useState(() => - supportedBadgeOptions.reduce((accum, { name }) => { - if (name === 'style') { - accum[name] = initialStyle - } else { - accum[name] = '' - } - return accum - }, {} as Record) - ) - - const handleServiceQueryParamChange = React.useCallback( - function ({ - target: { name, type: targetType, checked, value }, - }: ChangeEvent): void { - const outValue = targetType === 'checkbox' ? checked : value - setQueryParams({ ...queryParams, [name]: outValue }) - }, - [setQueryParams, queryParams] - ) - - const handleBadgeOptionChange = React.useCallback( - function ({ - target: { name, value }, - }: ChangeEvent): void { - setBadgeOptions({ ...badgeOptions, [name]: value }) - }, - [setBadgeOptions, badgeOptions] - ) - - useEffect(() => { - if (onChange) { - const { queryString, isComplete } = getQueryString({ - queryParams, - badgeOptions, - }) - onChange({ queryString, isComplete }) - } - }, [onChange, queryParams, badgeOptions]) - - const hasQueryParams = Boolean(Object.keys(queryParams).length) - let stringParamCount = 0 - return ( - <> - {hasQueryParams && ( - - - - {Object.entries(queryParams).map(([name, value]) => { - const isStringParam = typeof value === 'string' - return ( - - ) - })} - -
-
- )} - - - - {Object.entries(badgeOptions).map(([name, value]) => ( - - ))} - -
-
- - ) -} diff --git a/frontend/components/customizer/request-markup-button.tsx b/frontend/components/customizer/request-markup-button.tsx deleted file mode 100644 index 8d1f93ffd5eea..0000000000000 --- a/frontend/components/customizer/request-markup-button.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import React, { useRef } from 'react' -import styled from 'styled-components' -import Select, { components } from 'react-select' -import { MarkupFormat } from '../../lib/generate-image-markup' - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -function ClickableControl(props: any): JSX.Element { - return ( - - ) -} - -interface Option { - value: MarkupFormat - label: string -} - -const MarkupFormatSelect = styled(Select)` - width: 200px; - - margin-left: auto; - margin-right: auto; - - font-family: 'Lato', sans-serif; - font-size: 12px; - - .markup-format__control { - background-image: linear-gradient(-180deg, #00aeff 0%, #0076ff 100%); - border: 1px solid rgba(238, 239, 241, 0.8); - border-width: 0; - box-shadow: unset; - cursor: copy; - } - - .markup-format__control--is-disabled { - background: rgba(0, 118, 255, 0.3); - cursor: none; - } - - .markup-format__placeholder { - color: #eeeff1; - } - - .markup-format__indicator { - color: rgba(238, 239, 241, 0.81); - cursor: pointer; - } - - .markup-format__indicator:hover { - color: #eeeff1; - } - - .markup-format__control--is-focused .markup-format__indicator, - .markup-format__control--is-focused .markup-format__indicator:hover { - color: #ffffff; - } - - .markup-format__option { - text-align: left; - cursor: copy; - } -` - -const markupOptions: Option[] = [ - { value: 'markdown', label: 'Copy Markdown' }, - { value: 'rst', label: 'Copy reStructuredText' }, - { value: 'asciidoc', label: 'Copy AsciiDoc' }, - { value: 'html', label: 'Copy HTML' }, -] - -export default function GetMarkupButton({ - onMarkupRequested, - isDisabled, -}: { - onMarkupRequested: (markupFormat: MarkupFormat) => Promise - isDisabled: boolean -}): JSX.Element { - // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/35572 - // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/28884#issuecomment-471341041 - const selectRef = useRef>() as React.MutableRefObject< - Select