Skip to content

Commit

Permalink
feat: refactor snippets (#3409)
Browse files Browse the repository at this point in the history
* feat: refactor snippets

* fix: fix tab selection

* fix: differenciate between TS and JS snippets

* fix: replace also the enabledTradeTypes

* fix: add missing commit i forgot to upload

* fix: fix issue with value of tabs

* fix: remove type for JS example

* fix: rename html example
  • Loading branch information
anxolin authored Nov 18, 2023
1 parent af1add9 commit 1b703ea
Show file tree
Hide file tree
Showing 9 changed files with 150 additions and 52 deletions.
7 changes: 7 additions & 0 deletions apps/widget-configurator/src/app/embedDialog/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ export const COMMENTS_BY_PARAM_NAME: Record<string, string> = {
interfaceFeeBips: 'Fill the form above if you are interested',
}

export const COMMENTS_BY_PARAM_NAME_TYPESCRIPT: Record<string, string> = {
tradeType: 'TradeType.SWAP, TradeType.LIMIT or TradeType.ADVANCED',
enabledTradeTypes: 'TradeType.SWAP, TradeType.LIMIT and/or TradeType.ADVANCED',
}

export const VALUES_BY_PARAM_NAME: Record<string, string> = {
provider: 'window.ethereum',
}
Expand All @@ -27,3 +32,5 @@ export const SANITIZE_PARAMS = {
}

export const REMOVE_PARAMS: (keyof CowSwapWidgetParams)[] = ['env']

export const IMPORT_STATEMENT = `import { CowSwapWidget, CowSwapWidgetParams, TradeType }`
92 changes: 70 additions & 22 deletions apps/widget-configurator/src/app/embedDialog/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React, { SyntheticEvent, useEffect, useMemo, useRef, useState } from 'react'
import React, { SyntheticEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react'

import HTMLIcon from '@cowprotocol/assets/cow-swap/html.svg'
import JSIcon from '@cowprotocol/assets/cow-swap/js.svg'
import ReactIcon from '@cowprotocol/assets/cow-swap/react.svg'
import TSIcon from '@cowprotocol/assets/cow-swap/ts.svg'
import { CowSwapWidgetProps } from '@cowprotocol/widget-react'

import { Tab } from '@mui/material'
import MuiAlert, { AlertProps } from '@mui/material/Alert'
import Box from '@mui/material/Box'
import Button from '@mui/material/Button'
Expand All @@ -13,27 +15,66 @@ import DialogActions from '@mui/material/DialogActions'
import DialogContent from '@mui/material/DialogContent'
import DialogTitle from '@mui/material/DialogTitle'
import Snackbar from '@mui/material/Snackbar'
import Tab from '@mui/material/Tab'
import Tabs from '@mui/material/Tabs'
import SVG from 'react-inlinesvg'
import SyntaxHighlighter from 'react-syntax-highlighter'
// eslint-disable-next-line no-restricted-imports
import { nightOwl } from 'react-syntax-highlighter/dist/esm/styles/hljs'

import { reactExample } from './utils/reactExample'
import { vanilaNpmExample } from './utils/vanilaNpmExample'
import { vanillaNoDepsExample } from './utils/vanillaNoDepsExample'
import { vanillaNoDepsExample } from './utils/htmlExample'
import { jsExample } from './utils/jsExample'
import { reactTsExample } from './utils/reactTsExample'
import { tsExample } from './utils/tsExample'

import { copyEmbedCodeGA, viewEmbedCodeGA } from '../analytics'

interface TabInfo {
id: number
label: string
language: string
snippetFromParams(params: CowSwapWidgetProps['params']): string
icon: string
}

const TABS: TabInfo[] = [
{
id: 0,
label: 'React Typescript',
language: 'typescript',
snippetFromParams: reactTsExample,
icon: ReactIcon,
},
{
id: 1,
label: 'Typescript',
language: 'typescript',
snippetFromParams: tsExample,
icon: TSIcon,
},
{
id: 2,
label: 'Javascript',
language: 'javascript',
snippetFromParams: jsExample,
icon: JSIcon,
},
{
id: 3,
label: 'Pure HTML',
language: 'html',
snippetFromParams: vanillaNoDepsExample,
icon: HTMLIcon,
},
]

const Alert = React.forwardRef<HTMLDivElement, AlertProps>(function Alert(props, ref) {
return <MuiAlert elevation={6} ref={ref} variant="filled" {...props} />
})

function a11yProps(index: number) {
function a11yProps(id: number) {
return {
id: `simple-tab-${index}`,
'aria-controls': `simple-tabpanel-${index}`,
id: `simple-tab-${id}`,
'aria-controls': `simple-tabpanel-${id}`,
}
}

Expand All @@ -45,7 +86,8 @@ export interface EmbedDialogProps {

export function EmbedDialog({ params, open, handleClose }: EmbedDialogProps) {
const [scroll, setScroll] = useState<DialogProps['scroll']>('paper')
const [currentTab, setCurrentTab] = useState(0)
const [tabInfo, setCurrentTabInfo] = useState<TabInfo>(TABS[0])
const { id, language, snippetFromParams } = tabInfo
const descriptionElementRef = useRef<HTMLElement>(null)

const [snackbarOpen, setSnackbarOpen] = useState(false)
Expand Down Expand Up @@ -74,12 +116,10 @@ export function EmbedDialog({ params, open, handleClose }: EmbedDialogProps) {
}, [open])

const code = useMemo(() => {
if (currentTab === 0) return vanilaNpmExample(params)
if (currentTab === 1) return reactExample(params)
if (currentTab === 2) return vanillaNoDepsExample(params)
return snippetFromParams(params)
}, [snippetFromParams, params])

return ''
}, [currentTab, params])
const onChangeTab = useCallback((_event: SyntheticEvent, newValue: TabInfo) => setCurrentTabInfo(newValue), [])

return (
<div>
Expand All @@ -97,9 +137,9 @@ export function EmbedDialog({ params, open, handleClose }: EmbedDialogProps) {
<DialogContent dividers={scroll === 'paper'}>
<Box sx={{ borderBottom: 1, borderColor: 'divider' }}>
<Tabs
value={currentTab}
onChange={(event: SyntheticEvent, newValue: number) => setCurrentTab(newValue)}
aria-label="configuration tabs"
value={tabInfo}
onChange={onChangeTab}
aria-label="languages"
sx={{
'& .MuiTab-iconWrapper': {
height: '16px',
Expand All @@ -111,17 +151,25 @@ export function EmbedDialog({ params, open, handleClose }: EmbedDialogProps) {
},
}}
>
<Tab label="Vanilla (NPM)" icon={<SVG src={JSIcon} />} iconPosition="start" {...a11yProps(0)} />
<Tab label="React" icon={<SVG src={ReactIcon} />} iconPosition="start" {...a11yProps(1)} />
<Tab label="Pure HTML" icon={<SVG src={HTMLIcon} />} iconPosition="start" {...a11yProps(2)} />
{TABS.map((info) => {
return (
<Tab
key={info.id}
label={info.label}
icon={<SVG src={info.icon} />}
value={info}
{...a11yProps(info.id)}
/>
)
})}
</Tabs>
</Box>

<div role="tabpanel" id={`simple-tabpanel-${currentTab}`} aria-labelledby={`simple-tab-${currentTab}`}>
<div role="tabpanel" id={`simple-tabpanel-${id}`} aria-labelledby={`simple-tab-${id}`}>
<SyntaxHighlighter
showLineNumbers={true}
children={code}
language={currentTab === 2 ? 'html' : 'typescript'}
language={language}
style={nightOwl}
customStyle={{ fontSize: '0.8em' }}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,49 @@ import { CowSwapWidgetParams } from '@cowprotocol/widget-lib'

import { sanitizeParameters } from './sanitizeParameters'

import { COMMENTS_BY_PARAM_NAME, REMOVE_PARAMS, VALUES_BY_PARAM_NAME } from '../const'
import {
COMMENTS_BY_PARAM_NAME,
COMMENTS_BY_PARAM_NAME_TYPESCRIPT,
REMOVE_PARAMS,
VALUES_BY_PARAM_NAME,
} from '../const'

export function formatParameters(params: CowSwapWidgetParams, padLeft = 0): string {
export function formatParameters(params: CowSwapWidgetParams, padLeft = 0, isTypescript: boolean): string {
const paramsSanitized = sanitizeParameters(params)
REMOVE_PARAMS.forEach((propName) => {
delete paramsSanitized[propName]
})

// Stringify params
const formattedParams = JSON.stringify(paramsSanitized, null, 4)

// Add comments
const resultWithComments = Object.keys(COMMENTS_BY_PARAM_NAME).reduce((acc, propName) => {
return acc.replace(new RegExp(`"${propName}".*$`, 'gm'), `$& // ${COMMENTS_BY_PARAM_NAME[propName]}`)
const commentsByParamName = isTypescript
? { ...COMMENTS_BY_PARAM_NAME, ...COMMENTS_BY_PARAM_NAME_TYPESCRIPT }
: COMMENTS_BY_PARAM_NAME

const resultWithComments = Object.keys(commentsByParamName).reduce((acc, propName) => {
return acc.replace(new RegExp(`"${propName}".*$`, 'gm'), `$& // ${commentsByParamName[propName]}`)
}, formattedParams)

// Add values
const resultWithValues = Object.keys(VALUES_BY_PARAM_NAME).reduce((acc, propName) => {
return acc.replace(new RegExp(`("${propName}".* )(".*")(.*)$`, 'gm'), `$1${VALUES_BY_PARAM_NAME[propName]}$3`)
const tradeTypeValue = isTypescript ? 'TradeType.' + params.tradeType?.toUpperCase() : `"${params.tradeType}"`
const valuesByParamName: Record<string, string> = tradeTypeValue
? { ...VALUES_BY_PARAM_NAME, tradeType: tradeTypeValue }
: VALUES_BY_PARAM_NAME

let resultWithValues = Object.keys(valuesByParamName).reduce((acc, propName) => {
return acc.replace(new RegExp(`("${propName}".* )(".*")(.*)$`, 'gm'), `$1${valuesByParamName[propName]}$3`)
}, resultWithComments)

// Fix the enabledTradeTypes
if (isTypescript) {
resultWithValues = resultWithValues.replace(
new RegExp(/^(\s*)"(\w*)"(,?)$/gm),
(_match, space, tradeType, comma) => space + 'TradeType.' + tradeType.toUpperCase() + comma
)
}

if (padLeft === 0) {
return resultWithValues
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function vanillaNoDepsExample(params: CowSwapWidgetParams): string {
<div id="app"></div>
<script>
// ${COMMENTS_BEFORE_PARAMS}
const params = ${formatParameters(params, 4)}
const params = ${formatParameters(params, 4, false)}
cowSwapWidget.cowSwapWidget(document.getElementById("app"), params)
</script>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { formatParameters } from './formatParameters'

import { COMMENTS_BEFORE_PARAMS } from '../const'

export function vanilaNpmExample(params: CowSwapWidgetParams): string {
export function jsExample(params: CowSwapWidgetParams): string {
return `
import { CowSwapWidgetParams, cowSwapWidget } from '@cowprotocol/widget-lib'
import { cowSwapWidget } from '@cowprotocol/widget-lib'
const container = document.getElementById('<YOUR_CONTAINER>')
// ${COMMENTS_BEFORE_PARAMS}
const params: CowSwapWidgetParams = ${formatParameters(params)}
const params = ${formatParameters(params, 0, false)}
const updateWidget = cowSwapWidget(container, params)
`
Expand Down
20 changes: 0 additions & 20 deletions apps/widget-configurator/src/app/embedDialog/utils/reactExample.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { CowSwapWidgetParams } from '@cowprotocol/widget-lib'

import { formatParameters } from './formatParameters'

import { COMMENTS_BEFORE_PARAMS, IMPORT_STATEMENT } from '../const'

export function reactTsExample(params: CowSwapWidgetParams): string {
return `
${IMPORT_STATEMENT} from '@cowprotocol/widget-react'
// ${COMMENTS_BEFORE_PARAMS}
const params: CowSwapWidgetParams = ${formatParameters(params, 0, true)}
function App() {
return (
<CowSwapWidget params={params} />
)
}
`
}
18 changes: 18 additions & 0 deletions apps/widget-configurator/src/app/embedDialog/utils/tsExample.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { CowSwapWidgetParams } from '@cowprotocol/widget-lib'

import { formatParameters } from './formatParameters'

import { COMMENTS_BEFORE_PARAMS, IMPORT_STATEMENT as TS_IMPORT_STATEMENT } from '../const'

export function tsExample(params: CowSwapWidgetParams): string {
return `
${TS_IMPORT_STATEMENT} from '@cowprotocol/widget-lib'
const container = document.getElementById('<YOUR_CONTAINER>')
// ${COMMENTS_BEFORE_PARAMS}
const params: CowSwapWidgetParams = ${formatParameters(params, 0, true)}
const updateWidget = cowSwapWidget(container, params)
`
}
1 change: 1 addition & 0 deletions libs/assets/src/cow-swap/ts.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

2 comments on commit 1b703ea

@vercel
Copy link

@vercel vercel bot commented on 1b703ea Nov 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on 1b703ea Nov 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

cosmos – ./

cosmos.cow.fi
cosmos-cowswap.vercel.app
cosmos-git-main-cowswap.vercel.app
cowswap-seven.vercel.app

Please sign in to comment.