feat: use component library's dropdown component in learn (#50465)

Co-authored-by: Sboonny <muhammed@freecodecamp.org>
Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
Co-authored-by: Bruce Blaser <bbsmooth@gmail.com>
Co-authored-by: Naomi Carrigan <nhcarrigan@gmail.com>
This commit is contained in:
Ahmad Abdolsaheb
2023-06-22 17:21:05 +03:00
committed by GitHub
parent 29e69ed080
commit eb22bc0a82
21 changed files with 2901 additions and 4271 deletions
+2 -1
View File
@@ -1,5 +1,5 @@
client/.cache/**
client/static/**
client/.cache/**
client/public/**
api-server/src/public/**
api-server/lib/**
@@ -10,3 +10,4 @@ config/donation-settings.js
config/superblocks.js
web/**
docs/**/*.md
tools/ui-components/dist/**
+1
View File
@@ -22,3 +22,4 @@ web/.next
curriculum-server/data/curriculum.json
docs/**/*.md
client/src/components/Donation/types.js
tools/ui-components/dist
+4 -2
View File
@@ -19,11 +19,12 @@
"author": "freeCodeCamp <team@freecodecamp.org>",
"main": "none",
"scripts": {
"prebuild": "pnpm -w run create:config && pnpm run build:workers --env production",
"prebuild": "pnpm -w run create:config && pnpm run build:workers --env production && pnpm run build:components-library",
"build": "cross-env NODE_OPTIONS=\"--max-old-space-size=7168\" gatsby build --prefix-paths",
"build:workers": "cross-env NODE_OPTIONS=\"--max-old-space-size=7168\" webpack --config ./webpack-workers.js",
"clean": "gatsby clean",
"predevelop": "pnpm run build:workers --env development",
"predevelop": "pnpm -w run create:config && pnpm run build:workers --env development && pnpm run build:components-library",
"build:components-library": "pnpm run -F=@freecodecamp/ui build",
"develop": "cross-env NODE_OPTIONS=\"--max-old-space-size=5000\" gatsby develop --inspect=9230",
"lint": "ts-node ./i18n/schema-validation.ts",
"serve": "gatsby serve -p 8000",
@@ -49,6 +50,7 @@
"@freecodecamp/react-bootstrap": "0.32.3",
"@freecodecamp/react-calendar-heatmap": "1.1.0",
"@freecodecamp/strip-comments": "3.0.1",
"@freecodecamp/ui": "workspace:*",
"@growthbook/growthbook-react": "0.16.0",
"@loadable/component": "5.15.3",
"@reach/router": "1.3.4",
@@ -65,22 +65,6 @@ describe('<TimeLine />', () => {
);
});
it('Render button when both githubLink and solution is present', () => {
// @ts-expect-error
render(<TimeLine {...propsForOnlySolution} />, store);
const menuItems = screen.getAllByRole('menuitem');
expect(menuItems).toHaveLength(2);
expect(menuItems[0]).toHaveAttribute(
'href',
'https://github.com/freeCodeCamp/freeCodeCamp1'
);
expect(menuItems[1]).toHaveAttribute(
'href',
'https://github.com/freeCodeCamp/freeCodeCamp2'
);
});
it('rendering the correct button when files is present', () => {
// @ts-expect-error
render(<TimeLine {...propsForOnlySolution} />, store);
@@ -72,37 +72,6 @@ describe('<certification />', () => {
})
).toHaveAttribute('href', 'https://github.com/freeCodeCamp/freeCodeCamp');
});
it('Render button when both githubLink and solution is present', () => {
renderWithRedux(<CertificationSettings {...propsForOnlySolution} />);
const links = screen.getAllByRole('menuitem');
expect(links[0]).toHaveAttribute(
'href',
'https://github.com/freeCodeCamp/freeCodeCamp1'
);
expect(links[1]).toHaveAttribute(
'href',
'https://github.com/freeCodeCamp/freeCodeCamp2'
);
});
it('rendering the correct button when files is present', () => {
renderWithRedux(<CertificationSettings {...propsForMultifileProject} />);
expect(
screen.getByRole('menuitem', {
name: 'buttons.view-code'
})
).toBeInTheDocument();
expect(
screen.getByRole('menuitem', {
name: 'buttons.view-project'
})
).toBeInTheDocument();
});
});
const defaultTestProps = {
@@ -351,23 +320,3 @@ const propsForOnlySolution = {
}
]
};
const propsForMultifileProject = {
...defaultTestProps,
completedChallenges: [
{
id: '587d78af367417b2b2512b03',
completedDate: 123456789,
challengeFiles: [
{
contents,
ext,
fileKey,
name,
path
}
],
challengeType: 14
}
]
};
@@ -1,11 +1,13 @@
import { faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Button, Dropdown, MenuItem } from '@freecodecamp/react-bootstrap';
import { Button } from '@freecodecamp/react-bootstrap';
import { Dropdown, MenuItem } from '@freecodecamp/ui';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { CompletedChallenge } from '../../redux/prop-types';
import { getSolutionDisplayType } from '../../utils/solution-display-type';
import './solution-display-widget.css';
import '@freecodecamp/ui/dist/base.css';
interface Props {
completedChallenge: CompletedChallenge;
dataCy?: string;
@@ -21,7 +21,6 @@
.tool-panel-group-mobile > .dropdown > .btn-block {
margin: 0 2px 0 0;
padding: 5px 0;
height: 37px;
}
.tool-panel-group .btn-group {
@@ -37,7 +36,11 @@
}
.tool-panel-group-mobile .btn {
margin-bottom: 0 !important;
margin: 0 !important;
}
.tool-panel-group-mobile *:focus-visible {
outline-offset: -3px;
}
.tool-panel-group .dropdown-menu {
@@ -52,7 +55,3 @@
.tool-panel-group .dropdown-menu a {
padding: 0.5rem;
}
#get-help-dropdown > .caret {
transform: rotate(180deg);
}
@@ -1,8 +1,7 @@
import {
Button,
DropdownButton,
MenuItem
} from '@freecodecamp/react-bootstrap';
import { Button } from '@freecodecamp/react-bootstrap';
import { Dropdown, MenuItem } from '@freecodecamp/ui';
import { faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { connect } from 'react-redux';
@@ -104,40 +103,28 @@ function ToolPanel({
{isMobile ? t('buttons.reset') : t('buttons.reset-lesson')}
</Button>
)}
<DropdownButton
block={true}
bsStyle='primary'
className='btn-invert'
id='get-help-dropdown'
title={isMobile ? t('buttons.help') : t('buttons.get-help')}
>
{guideUrl ? (
<MenuItem
bsStyle='primary'
className='btn-invert'
href={guideUrl}
target='_blank'
>
{t('buttons.get-hint')}
<Dropdown dropup>
<Dropdown.Toggle dropup id={'get-help-dropdown'}>
{isMobile ? t('buttons.help') : t('buttons.get-help')}
</Dropdown.Toggle>
<Dropdown.Menu dropup>
{guideUrl ? (
<MenuItem href={guideUrl} target='_blank'>
{t('buttons.get-hint')}{' '}
<FontAwesomeIcon icon={faExternalLinkAlt} />
<span className='sr-only'>, {t('aria.opens-new-window')}</span>
</MenuItem>
) : null}
{videoUrl ? (
<MenuItem onClick={openVideoModal}>
{t('buttons.watch-video')}
</MenuItem>
) : null}
<MenuItem onClick={openHelpModal}>
{t('buttons.ask-for-help')}
</MenuItem>
) : null}
{videoUrl ? (
<MenuItem
bsStyle='primary'
className='btn-invert'
onClick={openVideoModal}
>
{t('buttons.watch-video')}
</MenuItem>
) : null}
<MenuItem
bsStyle='primary'
className='btn-invert'
onClick={openHelpModal}
>
{t('buttons.ask-for-help')}
</MenuItem>
</DropdownButton>
</Dropdown.Menu>
</Dropdown>
</div>
);
}
+1
View File
@@ -0,0 +1 @@
/* Don't delete! The empty config is needed when building the client */
@@ -8,17 +8,19 @@ describe('Help Button', () => {
it('should toggle the dropdown menu', () => {
cy.get('#get-help-dropdown').scrollIntoView().click();
cy.get('.tool-panel-group ul[role="menu"]')
cy.get('.tool-panel-group [role="menu"]')
.scrollIntoView()
.should('be.visible');
});
it('should render three links when video is available', () => {
cy.get('.tool-panel-group ul[role="menu"]').within(() => {
cy.get('a').should('have.length', 3);
cy.get('a').eq(0).contains('Get a Hint');
cy.get('a').eq(1).contains('Watch a Video');
cy.get('a').eq(2).contains('Ask for Help');
cy.get('.tool-panel-group [role="menu"]')
.children()
.should('have.length', 3);
cy.get('.tool-panel-group [role="menu"]').within(() => {
cy.get('a').contains('Get a Hint');
cy.get('button').contains('Watch a Video');
cy.get('button').contains('Ask for Help');
});
});
@@ -27,10 +29,12 @@ describe('Help Button', () => {
'/learn/front-end-development-libraries/bootstrap/apply-the-default-bootstrap-button-style'
);
cy.get('#get-help-dropdown').scrollIntoView().click();
cy.get('.tool-panel-group ul[role="menu"]').within(() => {
cy.get('a').should('have.length', 2);
cy.get('a').eq(0).contains('Get a Hint');
cy.get('a').eq(1).contains('Ask for Help');
cy.get('.tool-panel-group [role="menu"]')
.children()
.should('have.length', 2);
cy.get('.tool-panel-group [role="menu"]').within(() => {
cy.get('a').contains('Get a Hint');
cy.get('button').contains('Ask for Help');
});
});
});
+2141 -4114
View File
File diff suppressed because it is too large Load Diff
@@ -1,3 +1,6 @@
/* the styled-elements and normalized are included here to replicate the presets that exist in the learn app */
import '../src/normalize.css';
import '../src/global-element-styles.css';
import '../src/base.css';
export const parameters = {
+5 -1
View File
@@ -29,6 +29,7 @@
"@headlessui/react": "1.7.15",
"react": "16.14.0",
"react-dom": "16.14.0",
"tslib": "2.5.2",
"typescript": "4.9.5"
},
"devDependencies": {
@@ -58,6 +59,7 @@
"babel-loader": "8.3.0",
"babel-plugin-transform-react-remove-prop-types": "0.4.24",
"cross-env": "7.0.3",
"npm-run-all": "4.1.5",
"postcss": "8.4.24",
"postcss-import": "14.1.0",
"rollup": "2.79.1",
@@ -72,7 +74,9 @@
"build": "pnpm run build:css && pnpm run build:js",
"build:js": "cross-env NODE_ENV=production rollup -c",
"build:css": "pnpm dlx tailwindcss -i ./src/base.css -o ./dist/base.css --minify",
"dev": "cross-env NODE_ENV=development rollup -c -w",
"dev:js": "cross-env NODE_ENV=development rollup -c -w ",
"dev:css": "pnpm tailwindcss -i ./src/base.css -o ./dist/base.css --watch",
"develop": "npm-run-all --parallel dev:css dev:js storybook",
"clean": "rm -rf dist/*",
"gen-component": "ts-node ./utils/gen-component-script"
}
@@ -32,14 +32,19 @@ const DropUpChildren = () => (
);
export const Menus = (): JSX.Element => (
<>
<div
style={{
height: '220px',
width: '220px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-start'
}}
>
<Dropdown>
<DropDownChildren />
</Dropdown>
<Dropdown>
<DropDownChildren />
</Dropdown>
</>
</div>
);
const UpTemplate: Story<DropdownProps> = args => {
@@ -47,14 +52,13 @@ const UpTemplate: Story<DropdownProps> = args => {
<div
style={{
height: '220px',
width: '220px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-end'
}}
>
<div style={{ width: '220px' }}>
<Dropdown {...args} />
</div>
<Dropdown {...args} />
</div>
);
};
@@ -39,7 +39,7 @@ describe('<DropDownButton>', () => {
userEvent.click(dropdownTrigger);
const unorderedList = screen.getByRole('menu');
expect(unorderedList).toHaveClass(
'shadow-lg bg-foreground-primary text-background-primary text-center ring-1 ring-black ring-opacity-5 focus:outline-transparent origin-top-right absolute min-w-full py-1 z-10 transform -translate-y-full top-0'
'list-none bg-foreground-secondary text-center border-1 border-solid border-background-quaternary focus:outline-transparent origin-top-right absolute w-full min-w-max py-1 px-0 z-10 transform -translate-y-full top-0'
);
});
+22 -11
View File
@@ -1,4 +1,4 @@
import React, { createContext, useContext } from 'react';
import React, { createContext, useContext, useRef } from 'react';
import { Menu } from '@headlessui/react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCaretDown, faCaretUp } from '@fortawesome/free-solid-svg-icons';
@@ -11,24 +11,33 @@ export type DropdownProps = React.ComponentPropsWithoutRef<typeof Menu> & {
type DropDownButtonProps = React.ComponentPropsWithoutRef<typeof Menu>;
const DropDownContext = createContext<DropdownProps>({});
type DropDownContextProps = DropdownProps & {
menuButtonRef: React.MutableRefObject<HTMLButtonElement | null>;
};
const DropDownContext = createContext<DropDownContextProps>({
menuButtonRef: React.createRef()
});
const dropDownItems =
'shadow-lg bg-foreground-primary text-background-primary text-center ring-1 ring-black ring-opacity-5 focus:outline-transparent origin-top-right absolute min-w-full py-1 z-10';
'list-none bg-foreground-secondary text-center border-1 border-solid border-background-quaternary focus:outline-transparent origin-top-right absolute w-full min-w-max py-1 px-0 z-10';
const dropUpItems = dropDownItems + ' transform -translate-y-full top-0';
const toggleClassNames =
'cursor-pointer border-3 text-center touch-manipulation bg-background-quaternary text-foreground-secondary px-3 py-1.5 relative hover:bg-foreground-primary hover:text-background-primary btn-block border-foreground-primary';
'cursor-pointer border-3 border-solid w-full block text-center touch-manipulation bg-background-quaternary text-foreground-secondary px-3 py-1.5 relative hover:bg-foreground-secondary hover:text-background-secondary btn-block border-foreground-secondary';
export const MenuItems = React.forwardRef<
React.ElementRef<typeof Menu.Items>,
MenuItemsProps
>(({ children, className }, ref) => {
const { dropup } = useContext(DropDownContext);
const { dropup, menuButtonRef } = useContext(DropDownContext);
const handleClick = () => {
menuButtonRef.current?.focus();
};
const itemsClasses = dropup ? dropUpItems : dropDownItems;
const buttonClass: string = [className, itemsClasses].join(' ');
return (
<Menu.Items as='ul' className={buttonClass} ref={ref}>
<Menu.Items className={buttonClass} ref={ref} onClick={handleClick}>
{children}
</Menu.Items>
);
@@ -39,15 +48,15 @@ const DropDownButton = ({
className,
...rest
}: DropDownButtonProps) => {
const { dropup } = useContext(DropDownContext);
const { dropup, menuButtonRef } = useContext(DropDownContext);
const classes = [className, toggleClassNames].join(' ');
return (
<Menu.Button className={classes} {...rest}>
<Menu.Button ref={menuButtonRef} className={classes} {...rest}>
{children}
<FontAwesomeIcon
icon={dropup ? faCaretUp : faCaretDown}
className='mt-2 ml-2 -mr-1 h-3 w-3 text-violet-200'
className='mt-2 mx-2 h-3'
aria-hidden='true'
/>
</Menu.Button>
@@ -59,9 +68,11 @@ export const Dropdown = ({
dropup,
...props
}: DropdownProps): JSX.Element => {
const menuButtonRef = useRef(null);
const context = { dropup, menuButtonRef };
return (
<DropDownContext.Provider value={{ dropup }}>
<Menu className='relative' as='div' {...props}>
<DropDownContext.Provider value={context}>
<Menu className='relative w-full' as='div' {...props}>
{children}
</Menu>
</DropDownContext.Provider>
@@ -87,19 +87,26 @@ export const HeadlessButton = React.forwardRef<
);
const defaultClass =
'block text-center no-underline px-[20px] py-[3px] bg-foreground-primary text-background-primary bg-foreground-primary text-background-primary focus:bg-background-primary focus:text-foreground-primary hover:text-foreground-primary hover:bg-background-primary w-full';
'block text-center no-underline border-none px-4 py-1.5 focus:bg-background-secondary focus:text-foreground-secondary hover:text-foreground-secondary hover:bg-background-secondary w-full';
export const MenuItem = ({
children,
className,
...props
}: MenuItemsProps): JSX.Element => {
const classes = [defaultClass, className].join(' ');
return (
<Menu.Item as='li'>
<HeadlessButton className={classes} {...props}>
{children}
</HeadlessButton>
<Menu.Item>
{({ active }) => {
const activeStyles = active
? 'text-foreground-secondary bg-background-secondary outline outline-3 outline-blue-500 outline-offset-[-3px]'
: 'text-background-secondary bg-foreground-secondary';
const classes = [defaultClass, className, activeStyles].join(' ');
return (
<HeadlessButton className={classes} {...props}>
{children}
</HeadlessButton>
);
}}
</Menu.Item>
);
};
@@ -0,0 +1,457 @@
/*!
element styles of the minified boostrap 3 css file
*/
@media print {
*,
*:before,
*:after {
background: transparent !important;
color: #000 !important;
-webkit-box-shadow: none !important;
box-shadow: none !important;
text-shadow: none !important;
}
a,
a:visited {
text-decoration: underline;
}
a[href]:after {
content: ' (' attr(href) ')';
}
abbr[title]:after {
content: ' (' attr(title) ')';
}
a[href^='#']:after,
a[href^='javascript:']:after {
content: '';
}
pre,
blockquote {
border: 1px solid #999;
page-break-inside: avoid;
}
thead {
display: table-header-group;
}
tr,
img {
page-break-inside: avoid;
}
img {
max-width: 100% !important;
}
p,
h2,
h3 {
orphans: 3;
widows: 3;
}
h2,
h3 {
page-break-after: avoid;
}
}
* {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
*:before,
*:after {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
html {
font-size: 10px;
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
}
body {
font-family: 'Lato', Helvetica, Arial, sans-serif;
font-size: 18px;
line-height: 1.42857143;
color: #333;
background-color: #fff;
}
input,
button,
select,
textarea {
font-family: inherit;
font-size: inherit;
line-height: inherit;
}
a {
color: #006400;
text-decoration: none;
}
a:hover,
a:focus {
color: #001800;
text-decoration: underline;
}
figure {
margin: 0;
}
img {
vertical-align: middle;
}
hr {
margin-top: 25px;
margin-bottom: 25px;
border: 0;
border-top: 1px solid #eee;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
margin: -1px;
padding: 0;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
.sr-only-focusable:active,
.sr-only-focusable:focus {
position: static;
width: auto;
height: auto;
margin: 0;
overflow: visible;
clip: auto;
}
[role='button'] {
cursor: pointer;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: inherit;
font-weight: 400;
line-height: 1.1;
color: inherit;
}
h1 small,
h2 small,
h3 small,
h4 small,
h5 small,
h6 small {
font-weight: normal;
line-height: 1;
color: #777;
}
h1,
h2,
h3 {
margin-top: 25px;
margin-bottom: 12.5px;
}
h1 small,
h2 small,
h3 small {
font-size: 65%;
}
h4,
h5,
h6 {
margin-top: 12.5px;
margin-bottom: 12.5px;
}
h4 small,
h6 small {
font-size: 75%;
}
h1 {
font-size: 46px;
}
h2 {
font-size: 38px;
}
h3 {
font-size: 31px;
}
h4 {
font-size: 23px;
}
h5 {
font-size: 18px;
}
h6 {
font-size: 16px;
}
p {
margin: 0 0 12.5px;
}
small {
font-size: 88%;
}
mark {
background-color: #fcf8e3;
padding: 0.2em;
}
ul,
ol {
margin-top: 0;
margin-bottom: 12.5px;
}
ul ul,
ol ul,
ul ol,
ol ol {
margin-bottom: 0;
}
dl {
margin-top: 0;
margin-bottom: 25px;
}
dt,
dd {
line-height: 1.42857143;
}
dt {
font-weight: bold;
}
dd {
margin-left: 0;
}
abbr[title],
abbr[data-original-title] {
cursor: help;
border-bottom: 1px dotted #777;
}
blockquote {
padding: 12.5px 25px;
margin: 0 0 25px;
font-size: 22.5px;
border-left: 5px solid #eee;
}
blockquote p:last-child,
blockquote ul:last-child,
blockquote ol:last-child {
margin-bottom: 0;
}
blockquote footer,
blockquote small {
display: block;
font-size: 80%;
line-height: 1.42857143;
color: #777;
}
blockquote footer:before,
blockquote small:before {
content: '\2014 \00A0';
}
address {
margin-bottom: 25px;
font-style: normal;
line-height: 1.42857143;
}
code,
kbd,
pre,
samp {
font-family: Menlo, Monaco, Consolas, 'Courier New', monospace;
}
code {
padding: 2px 4px;
font-size: 90%;
color: #c7254e;
background-color: #f9f2f4;
border-radius: 4px;
}
kbd {
padding: 2px 4px;
font-size: 90%;
color: #fff;
background-color: #333;
border-radius: 3px;
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.25);
}
kbd kbd {
padding: 0;
font-size: 100%;
font-weight: bold;
-webkit-box-shadow: none;
box-shadow: none;
}
pre {
display: block;
padding: 12px;
margin: 0 0 12.5px;
font-size: 17px;
line-height: 1.42857143;
word-break: break-all;
word-wrap: break-word;
color: #333;
background-color: #f5f5f5;
border: 1px solid #ccc;
border-radius: 4px;
}
pre code {
padding: 0;
font-size: inherit;
color: inherit;
white-space: pre-wrap;
background-color: transparent;
border-radius: 0;
}
fieldset {
padding: 0;
margin: 0;
border: 0;
min-width: 0;
}
legend {
display: block;
width: 100%;
padding: 0;
margin-bottom: 25px;
font-size: 27px;
line-height: inherit;
color: #333;
border: 0;
border-bottom: 1px solid #e5e5e5;
}
label {
display: inline-block;
max-width: 100%;
margin-bottom: 5px;
font-weight: bold;
}
input[type='search'] {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
input[type='radio'],
input[type='checkbox'] {
margin: 4px 0 0;
margin-top: 1px \9;
line-height: normal;
}
input[type='file'] {
display: block;
}
input[type='range'] {
display: block;
width: 100%;
}
select[multiple],
select[size] {
height: auto;
}
output {
display: block;
padding-top: 7px;
font-size: 18px;
line-height: 1.42857143;
color: #555;
}
input[type='search'] {
appearance: none;
}
input[type='radio'][disabled],
input[type='checkbox'][disabled],
fieldset[disabled] input[type='radio'],
fieldset[disabled] input[type='checkbox'] {
cursor: not-allowed;
}
/* Element styles rewrites from global.css that could be moved to presets*/
/* typography should be handled in tailwind config */
html {
height: 100%;
font-size: 18px;
-webkit-font-smoothing: antialiased;
}
body {
height: 100%;
font-family: var(--font-family-sans-serif);
color: var(--secondary-color);
background: var(--secondary-background);
--header-height: 38px;
}
header {
top: 0;
position: fixed;
width: 100%;
z-index: 200;
}
a {
color: inherit;
text-decoration: underline;
}
a:hover,
a:focus {
text-decoration: none;
}
input {
outline-color: transparent;
-webkit-box-shadow: none !important;
-moz-box-shadow: none !important;
box-shadow: none !important;
border-radius: 0;
}
textarea {
resize: vertical;
}
form {
margin-bottom: 5px;
}
code {
border-radius: 0;
overflow-wrap: anywhere;
}
hr {
border-top-width: 1px;
border-top-style: solid;
/* border-top-color: var(--quaternary-background); */
}
code[class*='language-'],
pre[class*='language-'] {
border-radius: 0;
}
pre {
color: inherit;
background-color: inherit;
border: none;
border-radius: 0;
}
blockquote footer,
blockquote small,
blockquote .small {
color: #858591;
}
/* WCAG fix */
.sr-only {
color: white;
background-color: black;
}
+5 -5
View File
@@ -1,8 +1,8 @@
// Use this file as the entry point for component export
export { Button } from './button';
export { Alert } from './alert';
export { Image } from './image';
export { Table } from './table';
export { ToggleButton } from './toggle-button';
// export { Button } from './button';
// export { Alert } from './alert';
// export { Image } from './image';
// export { Table } from './table';
// export { ToggleButton } from './toggle-button';
export { Dropdown } from './drop-down';
export { MenuItem } from './drop-down/menu-item';
+180
View File
@@ -0,0 +1,180 @@
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
html {
font-family: sans-serif;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
section,
summary {
display: block;
}
audio,
canvas,
progress,
video {
display: inline-block;
vertical-align: baseline;
}
audio:not([controls]) {
display: none;
height: 0;
}
[hidden],
template {
display: none;
}
a {
background-color: transparent;
}
abbr[title] {
border-bottom: 1px dotted;
}
b,
strong {
font-weight: bold;
}
dfn {
font-style: italic;
}
h1 {
font-size: 2em;
margin: 0.67em 0;
}
mark {
background: #ff0;
color: #000;
}
small {
font-size: 80%;
}
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
img {
border: 0;
}
svg:not(:root) {
overflow: hidden;
}
figure {
margin: 1em 40px;
}
hr {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
height: 0;
}
pre {
overflow: auto;
}
code,
kbd,
pre,
samp {
font-family: monospace;
font-size: 1em;
}
button,
input,
optgroup,
select,
textarea {
color: inherit;
font: inherit;
margin: 0;
}
button {
overflow: visible;
}
button,
select {
text-transform: none;
}
button,
html input[type='button'],
input[type='reset'],
input[type='submit'] {
-webkit-appearance: button;
cursor: pointer;
}
button[disabled],
html input[disabled] {
cursor: default;
}
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
input {
line-height: normal;
}
input[type='checkbox'],
input[type='radio'] {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 0;
}
input[type='number']::-webkit-inner-spin-button,
input[type='number']::-webkit-outer-spin-button {
height: auto;
}
input[type='search'] {
-webkit-appearance: textfield;
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
input[type='search']::-webkit-search-cancel-button,
input[type='search']::-webkit-search-decoration {
-webkit-appearance: none;
}
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
legend {
border: 0;
padding: 0;
}
textarea {
overflow: auto;
}
optgroup {
font-weight: bold;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}
+7
View File
@@ -1,6 +1,10 @@
const plugin = require('tailwindcss/plugin');
module.exports = {
mode: 'jit',
corePlugins: {
preflight: false
},
content: [
'./src/**/*.html',
'./src/**/*.js',
@@ -78,6 +82,9 @@ module.exports = {
1: '1px',
3: '3px'
},
outlineWidth: {
3: '3px'
},
fontSize: {
// https://tailwindcss.com/docs/font-size#providing-a-default-line-height
// [fontSize, lineHeight]