diff --git a/.eslintrc.json b/.eslintrc.json index 860093d7a..5ff682db4 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -19,6 +19,7 @@ }, "plugins": ["typescript-sort-keys", "unused-imports"], "rules": { + "react/prop-types": "off", "typescript-sort-keys/string-enum": [ "error", "asc", diff --git a/.prettierignore b/.prettierignore index 3e1358bbc..af1f7c669 100644 --- a/.prettierignore +++ b/.prettierignore @@ -7,4 +7,5 @@ **/.hg *.mdx *.md -*.hbs \ No newline at end of file +*.hbs +*.gif \ No newline at end of file diff --git a/package.json b/package.json index e08ba6c54..38b74be98 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,8 @@ "postcss": "^8.4.47", "prettier": "3.3.3", "tailwindcss": "^3.4.13", - "typescript": "^4.8.4" + "typescript": "^4.8.4", + "postcss-import": "^16.1.0" }, "engines": { "npm": "please-use-yarn", diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 000000000..b196fc93c --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,8 @@ +/** @type {import('postcss').PostcssConfig} */ +module.exports = { + plugins: { + 'postcss-import': {}, + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/src/components/Icons/index.tsx b/src/components/Icons/index.tsx index e6c361238..5a9edfe51 100644 --- a/src/components/Icons/index.tsx +++ b/src/components/Icons/index.tsx @@ -351,6 +351,26 @@ export const Npm: FC<{ className?: string }> = ({ className }) => { ) } +export const Edit: FC<{ + className?: string + color?: 'neutral-2' +}> = ({ className, color = 'neutral-2' }) => { + return ( + + + + + + ) +} + export const HelpCircle: FC<{ className?: string color?: 'orange-vibrant' | 'blue-vibrant' | 'green-base' | 'pink-vibrant' @@ -370,6 +390,53 @@ export const HelpCircle: FC<{ ) } +export const Happy: FC<{ + className?: string + color?: 'neutral-2' +}> = ({ className, color = 'neutral-2' }) => { + return ( + + + + + + + ) +} + export const Chat: FC<{ className?: string color?: 'brown-vibrant' @@ -386,6 +453,53 @@ export const Chat: FC<{ ) } +export const Neutral: FC<{ + className?: string + color?: 'neutral-2' +}> = ({ className, color = 'neutral-2' }) => { + return ( + + + + + + + ) +} + export const Envelope: FC<{ className?: string color?: 'pink-vibrant' | 'neutral-2' @@ -403,6 +517,53 @@ export const Envelope: FC<{ ) } +export const Sad: FC<{ + className?: string + color?: 'neutral-2' +}> = ({ className, color = 'neutral-2' }) => { + return ( + + + + + + + ) +} + export type Icon = 'sun' | 'moon' export const IconMap: FC<{ diff --git a/src/components/SentimentTracking/SentimentButton.tsx b/src/components/SentimentTracking/SentimentButton.tsx new file mode 100644 index 000000000..3ddc4e3f0 --- /dev/null +++ b/src/components/SentimentTracking/SentimentButton.tsx @@ -0,0 +1,42 @@ +import React from 'react' +import { Sentiment } from '.' +import { TraceEvent } from '@uniswap/analytics' +import { BrowserEvent, DocsSentiment, DocsSentimentSection, SharedEventName } from '@uniswap/analytics-events' +import cn from 'classnames' + +interface SentimentButtonProps { + sentiment: Sentiment + icon: React.ReactNode + selected: boolean + onSelect: (sentiment: Sentiment) => void + analyticsSection: DocsSentimentSection +} + +const SentimentButton: React.FC = ({ sentiment, icon, selected, onSelect, analyticsSection }) => { + const sentimentMap: Record = { + [Sentiment.POSITIVE]: DocsSentiment.POSITIVE_SENTIMENT, + [Sentiment.NEUTRAL]: DocsSentiment.NEUTRAL_SENTIMENT, + [Sentiment.NEGATIVE]: DocsSentiment.NEGATIVE_SENTIMENT, + } + + const handleClick = () => onSelect(sentiment) + + return ( + + + + ) +} + +export default SentimentButton diff --git a/src/components/SentimentTracking/index.tsx b/src/components/SentimentTracking/index.tsx index c019226e3..675882828 100644 --- a/src/components/SentimentTracking/index.tsx +++ b/src/components/SentimentTracking/index.tsx @@ -1,9 +1,9 @@ -import { TraceEvent } from '@uniswap/analytics' -import { BrowserEvent, DocsSentiment, DocsSentimentSection, SharedEventName } from '@uniswap/analytics-events' +import { DocsSentimentSection } from '@uniswap/analytics-events' import React, { useCallback, useState } from 'react' -import { Frown, Meh, Smile } from 'react-feather' +import { Happy, Sad, Neutral } from '../Icons' +import SentimentButton from './SentimentButton' -enum Sentiment { +export enum Sentiment { NEGATIVE = 'NEGATIVE', NEUTRAL = 'NEUTRAL', POSITIVE = 'POSITIVE', @@ -18,47 +18,31 @@ export default function SentimentTracking({ analyticsSection }: { analyticsSecti ) return ( -
-
Helpful?
- - {/* +
Was this helpful?
+
+ } selected={isSentimentSelected(Sentiment.POSITIVE)} - onClick={() => { - setSelectedSentiment(Sentiment.POSITIVE) - }} - /> */} - - - {/* + } selected={isSentimentSelected(Sentiment.NEUTRAL)} - onClick={() => { - setSelectedSentiment(Sentiment.NEUTRAL) - }} - /> */} - - - {/* + } selected={isSentimentSelected(Sentiment.NEGATIVE)} - onClick={() => { - setSelectedSentiment(Sentiment.NEGATIVE) - }} - /> */} - + onSelect={setSelectedSentiment} + analyticsSection={analyticsSection} + /> +
) } diff --git a/src/css/custom.css b/src/css/custom.css index abff70514..76e68fd98 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -30,3 +30,109 @@ .divider { @apply border-t border-light-surface-3 dark:border-dark-surface-3; } + +.breadcrumbs__link { + @apply !text-light-neutral-1 dark:!text-dark-neutral-1 !bg-transparent !p-0 !body-3; +} +.breadcrumbs__item:first-child, +.breadcrumbs__item:first-child:after { + @apply !hidden; +} +.breadcrumbs__item:not(:last-child):after { + background: url('/img/chevron.svg') center !important; + @apply text-light-neutral-1 dark:text-dark-neutral-1 !h-4 !opacity-100; +} +.docMainContainer_src-theme-DocPage-Layout-Main-styles-module { + @apply !mt-nav-h; +} +.breadcrumbs__item { + @apply inline-flex flex-row items-center; +} +.Toc__title { + @apply !body-3 text-light-neutral-1 dark:text-dark-neutral-1; +} +.theme-edit-this-page { + all: initial; +} +.theme-edit-this-page { + @apply text-light-neutral-2 dark:text-dark-neutral-2 !button-label-3; +} +.theme-edit-this-page svg { + @apply !hidden; +} +.theme-doc-toc-desktop { + @apply !relative !top-auto; +} +.Toc__container { + @apply max-h-[calc(100vh-(theme(spacing.nav-h)+2rem))] overflow-y-auto sticky top-[calc(theme(spacing.nav-h)+1rem)] hidden md:block; +} +.theme-doc-toc-mobile { + @apply !hidden; +} +.table-of-contents { + @apply !pl-0; +} +.table-of-contents__link { + @apply !text-light-neutral-2 dark:!text-dark-neutral-2 hover:!text-light-neutral-1 hover:dark:!text-dark-neutral-1 !body-3; +} +.table-of-contents__left-border { + @apply !border-0; +} +.table-of-contents__left-border li { + @apply !ml-0; +} +.table-of-contents__left-border ul { + @apply border-y-0 border-r-0 border-l-2 border-solid border-l-light-surface-3 dark:border-l-dark-surface-3 !pl-4; +} +.pagination-nav { + @apply !flex !flex-col md:!flex-row !w-full !h-auto !gap-y-2 md:!gap-y-0 md:!gap-x-3 !mt-8; +} +.pagination-nav__link { + @apply md:w-1/2 md:!grow-0 !flex !flex-col !space-y-1 bg-light-accent-2 dark:bg-dark-accent-2 hover:bg-light-accent-2-hovered hover:dark:bg-dark-accent-2-hovered text-light-accent-1 !rounded-lg !p-4 !border-0 !min-h-fit !h-auto; +} +.pagination-nav__sublabel { + @apply text-light-accent-1 !body-4 flex flex-row items-center w-fit; +} +.pagination-nav__label { + @apply !subheading-2 !text-light-accent-1; +} +.pagination-nav__label::before, +.pagination-nav__label::after { + @apply !content-none; +} +.pagination-nav:has(.pagination-nav__link--next):not(:has(.pagination-nav__link--prev)) { + @apply md:!flex-row-reverse; +} +.pagination-nav__link--next > .pagination-nav__sublabel::after { + @apply hidden md:inline-block w-4 h-4 bg-cover content-[""] bg-[url("/img/arrow-right.svg")] ml-2; +} +.pagination-nav__link--next > .pagination-nav__sublabel::before { + @apply md:hidden inline-block w-4 h-4 bg-cover content-[""] bg-[url("/img/arrow-right.svg")] mr-2; +} +.pagination-nav__link--prev > .pagination-nav__sublabel::before { + @apply inline-block w-4 h-4 bg-cover content-[""] bg-[url("/img/arrow-left.svg")] mr-2; +} +.pagination-nav__link--next > .pagination-nav__label { + @apply self-start md:self-end; +} +.pagination-nav__link--next > .pagination-nav__sublabel { + @apply md:self-end; +} +.pagination-nav__link--prev > .pagination-nav__sublabel { + @apply self-start; +} +.Sentiment__question { + @apply !mono-body-5 !text-light-neutral-1 dark:!text-dark-neutral-1; +} +.col.docItemCol_src-theme-DocItem-Layout-styles-module { + @apply sm:!max-w-full md:!max-w-[75%]; +} +.container { + @apply !mt-nav-h; +} +.theme-doc-footer-edit-meta-row { + @apply !hidden; +} +.navbar { + @apply !p-0; +} diff --git a/src/css/index.css b/src/css/index.css new file mode 100644 index 000000000..e69de29bb diff --git a/src/css/infima-overrides.css b/src/css/infima-overrides.css index dfaed7356..39b9fea0a 100644 --- a/src/css/infima-overrides.css +++ b/src/css/infima-overrides.css @@ -102,3 +102,7 @@ select { scroll-behavior: auto !important; } } + +.navbar { + all: initial; +} diff --git a/src/theme/DocBreadcrumbs.tsx b/src/theme/DocBreadcrumbs.tsx index b185b817c..ea2e501b0 100644 --- a/src/theme/DocBreadcrumbs.tsx +++ b/src/theme/DocBreadcrumbs.tsx @@ -1,16 +1,10 @@ import OriginalDocBreadcrumbs from '@theme-original/DocBreadcrumbs' -import { DocsSentimentSection } from '@uniswap/analytics-events' import React from 'react' -import SentimentTracking from '../components/SentimentTracking' - export default function DocBreadcrumbs(props) { return (
- -
- -
+
) } diff --git a/src/theme/DocItem/Layout/index.js b/src/theme/DocItem/Layout/index.js new file mode 100644 index 000000000..62410525b --- /dev/null +++ b/src/theme/DocItem/Layout/index.js @@ -0,0 +1,67 @@ +import React from 'react' +import clsx from 'clsx' +import { useWindowSize } from '@docusaurus/theme-common' +import { useDoc } from '@docusaurus/theme-common/internal' +import DocItemPaginator from '@theme/DocItem/Paginator' +import DocVersionBanner from '@theme/DocVersionBanner' +import DocVersionBadge from '@theme/DocVersionBadge' +import DocItemFooter from '@theme/DocItem/Footer' +import DocItemTOCMobile from '@theme/DocItem/TOC/Mobile' +import DocItemTOCDesktop from '@theme/DocItem/TOC/Desktop' +import DocItemContent from '@theme/DocItem/Content' +import DocBreadcrumbs from '@theme/DocBreadcrumbs' +import EditThisPage from '@theme/EditThisPage' +import styles from './styles.module.css' +import { Edit } from '../../../components/Icons' +/** + * Decide if the toc should be rendered, on mobile or desktop viewports + */ +function useDocTOC() { + const { frontMatter, toc } = useDoc() + const windowSize = useWindowSize() + const hidden = frontMatter.hide_table_of_contents + const canRender = !hidden && toc.length > 0 + const mobile = canRender ? : undefined + const desktop = canRender && (windowSize === 'desktop' || windowSize === 'ssr') ? : undefined + return { + hidden, + mobile, + desktop, + } +} +export default function DocItemLayout({ children }) { + const docTOC = useDocTOC() + const { metadata } = useDoc() + const { editUrl } = metadata + return ( +
+
+ +
+
+ + + {docTOC.mobile} + {children} + +
+ +
+
+
+ {docTOC.desktop && ( +
+

On this page

+ {docTOC.desktop} +
+ )} + {editUrl && ( +
+ + +
+ )} +
+
+ ) +} diff --git a/src/theme/DocItem/Layout/styles.module.css b/src/theme/DocItem/Layout/styles.module.css new file mode 100644 index 000000000..d5aaec132 --- /dev/null +++ b/src/theme/DocItem/Layout/styles.module.css @@ -0,0 +1,10 @@ +.docItemContainer header + *, +.docItemContainer article > *:first-child { + margin-top: 0; +} + +@media (min-width: 997px) { + .docItemCol { + max-width: 75% !important; + } +} diff --git a/static/img/arrow-left-dark.svg b/static/img/arrow-left-dark.svg new file mode 100644 index 000000000..587a72e20 --- /dev/null +++ b/static/img/arrow-left-dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/static/img/arrow-left.svg b/static/img/arrow-left.svg new file mode 100644 index 000000000..e019a2bf0 --- /dev/null +++ b/static/img/arrow-left.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/static/img/arrow-right-dark.svg b/static/img/arrow-right-dark.svg new file mode 100644 index 000000000..0f43bd2d4 --- /dev/null +++ b/static/img/arrow-right-dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/static/img/arrow-right.svg b/static/img/arrow-right.svg new file mode 100644 index 000000000..0b3d6aa3e --- /dev/null +++ b/static/img/arrow-right.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/static/img/chevron.svg b/static/img/chevron.svg new file mode 100644 index 000000000..5cd695d63 --- /dev/null +++ b/static/img/chevron.svg @@ -0,0 +1,3 @@ + + + diff --git a/static/img/edit.svg b/static/img/edit.svg new file mode 100644 index 000000000..014c34e44 --- /dev/null +++ b/static/img/edit.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/tailwind.config.js b/tailwind.config.js index 8b449cb0d..0eda7025d 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -28,7 +28,7 @@ module.exports = { preflight: false, container: false, }, - content: ['./src/**/*.{ts,tsx}'], + content: ['./src/**/*.{ts,tsx}', './docusaurus.config.js'], darkMode: 'class', theme: { screens: { diff --git a/yarn.lock b/yarn.lock index 5c47bb09a..36e604feb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7176,6 +7176,15 @@ postcss-import@^15.1.0: read-cache "^1.0.0" resolve "^1.1.7" +postcss-import@^16.1.0: + version "16.1.0" + resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-16.1.0.tgz#258732175518129667fe1e2e2a05b19b5654b96a" + integrity sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg== + dependencies: + postcss-value-parser "^4.0.0" + read-cache "^1.0.0" + resolve "^1.1.7" + postcss-js@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.1.tgz#61598186f3703bab052f1c4f7d805f3991bee9d2"