diff --git a/README.md b/README.md index e8de4bae17..7d4200b433 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,142 @@ -

- -

-

- Documentation | - Changelog | - Roadmap -

- -

- The web has evolved. Finally, testing has too. -

- -

- Fast, easy and reliable testing for anything that runs in a browser. -

-

- Join us, we're hiring. -

- -

- - npm - - - Gitter chat - - - StackShare -
-

- -## What is Cypress? - -

- - Why Cypress Video - -

- -## Installing - -[![npm version](https://badge.fury.io/js/cypress.svg)](https://badge.fury.io/js/cypress) - -Install Cypress for Mac, Linux, or Windows, then [get started](https://docs.cypress.io/guides/getting-started/installing-cypress.html). - -```bash -npm install cypress --save-dev -``` -or -```bash -yarn add cypress --dev -``` - -![installing-cli e1693232](https://user-images.githubusercontent.com/1271364/31740846-7bf607f0-b420-11e7-855f-41c996040d31.gif) - - -## Contributing - -- [![CircleCI](https://circleci.com/gh/cypress-io/cypress/tree/develop.svg?style=svg)](https://circleci.com/gh/cypress-io/cypress/tree/develop) - `develop` branch -- [![CircleCI](https://circleci.com/gh/cypress-io/cypress/tree/master.svg?style=svg)](https://circleci.com/gh/cypress-io/cypress/tree/master) - `master` branch - -Please see our [Contributing Guideline](./CONTRIBUTING.md) which explains repo organization, linting, testing, and other steps. - -## License - -[![license](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/cypress-io/cypress/blob/master/LICENSE) - -This project is licensed under the terms of the [MIT license](/LICENSE). - -## Badges - -Let the world know your project is using Cypress.io to test with this cool badge - -[![Cypress.io](https://img.shields.io/badge/tested%20with-Cypress-04C38E.svg)](https://www.cypress.io/) - -``` -[![Cypress.io](https://img.shields.io/badge/tested%20with-Cypress-04C38E.svg)](https://www.cypress.io/) -``` +

+ + Bot logo +

+ +

cypress

+ +
+ +[![Status](https://img.shields.io/badge/status-active-success.svg)]() +[![Platform](https://img.shields.io/badge/platform-reddit-orange.svg)](https://www.reddit.com/user/Wordbook_Bot) +[![GitHub Issues](https://img.shields.io/github/issues/kylelobo/The-Documentation-Compendium.svg)](https://github.com/kylelobo/The-Documentation-Compendium/issues) +[![GitHub Pull Requests](https://img.shields.io/github/issues-pr/kylelobo/The-Documentation-Compendium.svg)](https://github.com/kylelobo/The-Documentation-Compendium/pulls) +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](/LICENSE) + +
+ +--- + +

πŸ€– Few lines describing what your bot does. +
+

+ +## πŸ“ Table of Contents + +- [About](#about) +- [Demo / Working](#demo) +- [How it works](#working) +- [Usage](#usage) +- [Getting Started](#getting_started) +- [Deploying your own bot](#deployment) +- [Built Using](#built_using) +- [TODO](../TODO.md) +- [Contributing](../CONTRIBUTING.md) +- [Authors](#authors) +- [Acknowledgments](#acknowledgement) + +## 🧐 About + +Write about 1-2 paragraphs describing the purpose of your bot. + +## πŸŽ₯ Demo / Working + +![Working](https://media.giphy.com/media/20NLMBm0BkUOwNljwv/giphy.gif) + +## πŸ’­ How it works + +The bot first extracts the word from the comment and then fetches word definitions, part of speech, example and source from the Oxford Dictionary API. + +If the word does not exist in the Oxford Dictionary, the Oxford API then returns a 404 response upon which the bot then tries to fetch results form the Urban Dictionary API. + +The bot uses the Pushshift API to fetch comments, PRAW module to reply to comments and Heroku as a server. + +The entire bot is written in Python 3.6 + +## 🎈 Usage + +To use the bot, type: + +``` +!dict word +``` + +The first part, i.e. "!dict" **is not** case sensitive. + +The bot will then give you the Oxford Dictionary (or Urban Dictionary; if the word does not exist in the Oxford Dictionary) definition of the word as a comment reply. + +### Example: + +> !dict what is love + +**Definition:** + +Baby, dont hurt me~ +Dont hurt me~ no more. + +**Example:** + +Dude1: Bruh, what is love? +Dude2: Baby, dont hurt me, dont hurt me- no more! +Dude1: dafuq? + +**Source:** https://www.urbandictionary.com/define.php?term=what%20is%20love + +--- + +Beep boop. I am a bot. If there are any issues, contact my [Master](https://www.reddit.com/message/compose/?to=PositivePlayer1&subject=/u/Wordbook_Bot) + +Want to make a similar reddit bot? Check out: [GitHub](https://github.com/kylelobo/Reddit-Bot) + +## 🏁 Getting Started + +These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See [deployment](#deployment) for notes on how to deploy the project on a live system. + +### Prerequisites + +What things you need to install the software and how to install them. + +``` +Give examples +``` + +### Installing + +A step by step series of examples that tell you how to get a development env running. + +Say what the step will be + +``` +Give the example +``` + +And repeat + +``` +until finished +``` + +End with an example of getting some data out of the system or using it for a little demo. + +## πŸš€ Deploying your own bot + +To see an example project on how to deploy your bot, please see my own configuration: + +- **Heroku**: https://github.com/kylelobo/Reddit-Bot#deploying_the_bot + +## ⛏️ Built Using + +- [PRAW](https://praw.readthedocs.io/en/latest/) - Python Reddit API Wrapper +- [Heroku](https://www.heroku.com/) - SaaS hosting platform + +## ✍️ Authors + +- [@kylelobo](https://github.com/kylelobo) - Idea & Initial work + +See also the list of [contributors](https://github.com/kylelobo/The-Documentation-Compendium/contributors) who participated in this project. + +## πŸŽ‰ Acknowledgements + +- Hat tip to anyone whose code was used +- Inspiration +- References diff --git a/packages/app/.windicss/icon-color-plugins.ts b/packages/app/.windicss/icon-color-plugins.ts index ea9122c58d..883152ff4c 100644 --- a/packages/app/.windicss/icon-color-plugins.ts +++ b/packages/app/.windicss/icon-color-plugins.ts @@ -17,7 +17,7 @@ interface RuleConfig { } const makeRuleForClass = ({ name, theme, weight, color }: RuleConfig) => { - const resolvedColor = color ? color : weight ? theme(`colors.${name}.${weight}`) : theme(`colors.${name}`) + const resolvedColor = color ? color : weight ? theme?.(`colors.${name}.${weight}`) : theme?.(`colors.${name}`) let [lightKey, darkKey] = [`.icon-light-${name}`, `.icon-dark-${name}`] // transparent, black, and white diff --git a/packages/app/cypress/support/index.ts b/packages/app/cypress/support/index.ts index b8d33ad4c6..a137da4712 100644 --- a/packages/app/cypress/support/index.ts +++ b/packages/app/cypress/support/index.ts @@ -1,4 +1,4 @@ -import { registerMountFn } from '@packages/frontend-shared/cypress/support/commands' +import { registerMountFn } from '@packages/frontend-shared/cypress/support/common' // *********************************************************** // This example support/index.js is processed and // loaded automatically before your test files. @@ -19,7 +19,6 @@ import { registerMountFn } from '@packages/frontend-shared/cypress/support/comma import 'virtual:windi.css' import '../../src/main.scss' import '@iconify/iconify' -import '@purge-icons/generated' import { createRouter } from '../../src/router/router' registerMountFn({ plugins: [() => createRouter()] }) diff --git a/packages/app/package.json b/packages/app/package.json index 4b76c8e73e..d4a4c8ad0b 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -26,6 +26,7 @@ "@iconify/json": "1.1.368", "@iconify/vue": "3.0.0-beta.1", "@intlify/vite-plugin-vue-i18n": "2.4.0", + "@packages/frontend-shared": "0.0.0-development", "@testing-library/cypress": "8.0.0", "@urql/core": "2.3.1", "@urql/vue": "0.4.3", diff --git a/packages/app/src/locales/en-US.json b/packages/app/src/locales/en-US.json deleted file mode 100644 index 9049951d6f..0000000000 --- a/packages/app/src/locales/en-US.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "links": { - "learnMore": "Learn more." - }, - "components": { - "modal": { - "dismiss": "Dismiss" - }, - "select": { - "placeholder": "Choose an option..." - } - }, - "clipboard": { - "copy": "Copy", - "copied": "Copied" - }, - "file": { - "edit": "Edit" - }, - "status": { - "enabled": "Enabled", - "disabled": "Disabled" - }, - "setupPage": { - "projectSetup": { - "frameworkLabel": "Front-end Framework", - "frameworkPlaceholder": "Pick a framework", - "bundlerLabel": "Bundler", - "bundlerPlaceholder": "Pick a bundler" - }, - "install": { - "startButton": "Install", - "confirmManualInstall": "I've installed them" - }, - "step": { - "next": "Next Step", - "back": "Back" - } - }, - "globalPage": { - "empty": { - "title": "Welcome to Cypress!", - "helper": "Add your first project below to start testing with Cypress.", - "dropText": "Drag your project here or {0}", - "browseManually": "browse manually." - }, - "searchPlaceholder": "Search Projects", - "newProjectButton": "New Project" - }, - "welcomeGuide": { - "header": { - "title": "Cypress", - "description": "A powerful open-source testing platform for developers and engineering teams all around the world." - }, - "projectListHeader": "Recently Viewed Projects", - "linkHeader": "Quick Access", - "confirmWelcomeGuide": "Show the welcome guide when opening Cypress." - }, - "settingsPage": { - "config": { - "title": "Resolved Configuration", - "description": "Since the options in the {0} can be set dynamically by your development environment, please refer to the legend below to understand how the configuration options are resolved.", - "legend": { - "env": { - "label": "env", - "description": "Set from environment variables" - }, - "default": { - "label": "default", - "description": "Default values" - }, - "dynamic": { - "label": "dynamic", - "description": "Set by the {0} function" - }, - "cli": { - "label": "cli", - "description": "Set from CLI arguments" - }, - "config": { - "label": "config", - "description": "Set from {0}" - } - } - }, - "proxy": { - "title": "Proxy Settings", - "description": "Cypress auto-detected the following proxy settings from your operating system.", - "bypassList": "Proxy Bypass List", - "proxyServer": "Proxy Server" - }, - "editor": { - "title": "External Editor", - "description": "External editor to use for editing code opened when using Cypress.", - "noEditorSelectedPlaceholder": "Choose your editor..." - }, - "projectId": { - "title": "Project ID", - "description": "The Project ID configured for this project inside of Cypress Cloud. {0}" - }, - "recordKey": { - "title": "Record Key", - "description": "The Record Key configured for this project inside of Cypress Cloud. {0}", - "manageKeys": "Manage Keys" - }, - "project": { - "title": "Project Settings", - "description": "Settings for this project." - }, - "experiments": { - "title": "Experiments", - "description": "If you'd like to try out new features that we're working on, you can enable beta features for your project by turning on the experimental features you'd like to try. {0}" - }, - "device": { - "title": "Device Settings", - "description": "Settings for this device." - } - } -} diff --git a/packages/app/src/main.scss b/packages/app/src/main.scss index 6e298a151c..62a35b5b9d 100644 --- a/packages/app/src/main.scss +++ b/packages/app/src/main.scss @@ -1,21 +1,4 @@ -/* Define the "system" font family */ -@font-face { - font-family: system; - font-style: normal; - font-weight: 300; - src: local(".SFNSText-Light"), local(".HelveticaNeueDeskInterface-Light"), - local(".LucidaGrandeUI"), local("Ubuntu Light"), local("Segoe UI Light"), - local("Roboto-Light"), local("DroidSans"), local("Tahoma"); -} - -body { - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif; -} - -/** - * Animations - * ------------------------- - */ +@use '@packages/frontend-shared/src/styles/shared.scss'; .fade-enter-active, .fade-leave-active { @@ -42,251 +25,3 @@ body { height: 0; } } - -/** - * Global Resets - * ------------------------- - */ - -// Input Resets -// Taken from Tailwind CSS Forms -- a plugin for tailwind. -// We could probably add these into WindiCSS directly -// https://github.com/tailwindlabs/tailwindcss-forms - -[multiple], -[type=date], -[type=datetime-local], -[type=email], -[type=month], -[type=number], -[type=password], -[type=search], -[type=tel], -[type=text], -[type=time], -[type=url], -[type=week], -select, -textarea { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - background-color: #fff; - border-color: #6b7280; - border-width: 1px; - border-radius: 0; - padding-top: 0.35rem; - padding-bottom: 0.35rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - font-size: 1rem; - line-height: 1.25rem; -} - -[multiple]:focus, -[type=date]:focus, -[type=datetime-local]:focus, -[type=email]:focus, -[type=month]:focus, -[type=number]:focus, -[type=password]:focus, -[type=search]:focus, -[type=tel]:focus, -[type=text]:focus, -[type=time]:focus, -[type=url]:focus, -[type=week]:focus, -select:focus, -textarea:focus { - outline: 2px solid transparent; - outline-offset: 2px; - --tw-ring-inset: var(--tw-empty, ); - /*!*/ - /*!*/ - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #2563eb; - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); - border-color: #2563eb; -} - -input::-moz-placeholder, -textarea::-moz-placeholder { - color: #6b7280; - opacity: 1; -} - -input:-ms-input-placeholder, -textarea:-ms-input-placeholder { - color: #6b7280; - opacity: 1; -} - -input::placeholder, -textarea::placeholder { - color: #6b7280; - opacity: 1; -} - -::-webkit-datetime-edit-fields-wrapper { - padding: 0; -} - -::-webkit-date-and-time-value { - min-height: 1.5em; -} - -select { - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); - background-position: right .5rem center; - background-repeat: no-repeat; - background-size: 1.5em 1.5em; - padding-right: 2.5rem; - -webkit-print-color-adjust: exact; - color-adjust: exact; -} - -[multiple] { - background-image: initial; - background-position: initial; - background-repeat: unset; - background-size: initial; - padding-right: .75rem; - -webkit-print-color-adjust: unset; - color-adjust: unset; -} - -[type=checkbox], -[type=radio] { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; - padding: 0; - -webkit-print-color-adjust: exact; - color-adjust: exact; - display: inline-block; - vertical-align: middle; - background-origin: border-box; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - flex-shrink: 0; - height: 1rem; - width: 1rem; - color: #2563eb; - background-color: #fff; - border-color: #6b7280; - border-width: 1px; -} - -[type=checkbox] { - border-radius: 0; -} - -[type=radio] { - border-radius: 100%; -} - -[type=checkbox]:focus, -[type=radio]:focus { - outline: 2px solid transparent; - outline-offset: 2px; - --tw-ring-inset: var(--tw-empty); - --tw-ring-offset-width: 2px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #2563eb; - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); -} - -[type=checkbox]:checked, -[type=radio]:checked { - border-color: transparent; - background-color: currentColor; - background-size: 100% 100%; - background-position: center; - background-repeat: no-repeat; -} - -[type=checkbox]:checked { - background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); -} - -[type=radio]:checked { - background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e"); -} - -[type=checkbox]:checked:focus, -[type=checkbox]:checked:hover, -[type=radio]:checked:focus, -[type=radio]:checked:hover { - border-color: transparent; - background-color: currentColor; -} - -[type=checkbox]:indeterminate { - background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e"); - border-color: transparent; - background-color: currentColor; - background-size: 100% 100%; - background-position: center; - background-repeat: no-repeat; -} - -[type=checkbox]:indeterminate:focus, -[type=checkbox]:indeterminate:hover { - border-color: transparent; - background-color: currentColor; -} - -[type=file] { - background: unset; - border-color: inherit; - border-width: 0; - border-radius: 0; - padding: 0; - font-size: unset; - line-height: inherit; -} - -[type=file]:focus { - outline: 1px auto -webkit-focus-ring-color; -} - - -input[type="search"].dark { - background: #222; - color: #fff; -} - -input[type="search"].light { - background: #fff; - color: #222; -} -input[type="search"].suffix::-webkit-search-cancel-button { - @apply pr-3.25em; -} - -input[type="search"]::-webkit-search-cancel-button { - -webkit-appearance: none; - margin: 1em; - height: 1em; - width: 1em; - border-radius: 50em; - background: url(https://pro.fontawesome.com/releases/v5.10.0/svgs/solid/times-circle.svg) - no-repeat 50% 50%; - background-size: contain; - opacity: 0; - pointer-events: none; -} - -input[type="search"]:focus::-webkit-search-cancel-button { - opacity: 0.3; - pointer-events: all; -} - -input[type="search"].dark::-webkit-search-cancel-button { - filter: invert(1); -} diff --git a/packages/app/src/main.ts b/packages/app/src/main.ts index e2daa8b133..662a8ff113 100644 --- a/packages/app/src/main.ts +++ b/packages/app/src/main.ts @@ -4,7 +4,7 @@ import 'virtual:windi.css' import urql from '@urql/vue' import App from './App.vue' import { makeUrqlClient } from '@packages/frontend-shared/src/graphql/urqlClient' -import { createI18n } from './locales/i18n' +import { createI18n } from '@cy/i18n' import { createRouter } from './router/router' const app = createApp(App) diff --git a/packages/app/tsconfig.json b/packages/app/tsconfig.json index 43406f48dd..919b1a77d3 100644 --- a/packages/app/tsconfig.json +++ b/packages/app/tsconfig.json @@ -1,4 +1,19 @@ { "extends": "../frontend-shared/tsconfig.json", - "include": ["src/**/*.vue", "src/**/*.tsx", "cypress/**/*.ts"] + "include": [ + "src/**/*.vue", + "src/**/*.tsx", + "cypress/**/*.ts", + "cypress/**/*.tsx", + "../frontend-shared/src/**/*.vue", + "../frontend-shared/src/**/*.tsx", + "../frontend-shared/cypress/**/*.ts" + ], + "compilerOptions": { + "paths": { + "@cy/i18n": ["../frontend-shared/src/locales/i18n"], + "@cy/components/*": ["../frontend-shared/src/components/*"], + "@packages/*": ["../*"] + } + } } diff --git a/packages/app/vite.config.ts b/packages/app/vite.config.ts index 7a6cb7d40a..67bd37a18f 100644 --- a/packages/app/vite.config.ts +++ b/packages/app/vite.config.ts @@ -1,51 +1,10 @@ -import path from 'path' -import { defineConfig } from 'vite' -import vue from '@vitejs/plugin-vue' -import vueJsx from '@vitejs/plugin-vue-jsx' -import WindiCSS from 'vite-plugin-windicss' -import PurgeIcons from 'vite-plugin-purge-icons' -import VueI18n from '@intlify/vite-plugin-vue-i18n' -import VueSvgLoader from 'vite-svg-loader' +import { makeConfig } from '../frontend-shared/vite.config' import Layouts from 'vite-plugin-vue-layouts' import Pages from 'vite-plugin-pages' -import Components from 'unplugin-vue-components/vite' -import Icons from 'unplugin-icons/vite' -import IconsResolver from 'unplugin-icons/resolver' -import { FileSystemIconLoader } from 'unplugin-icons/loaders' -export default defineConfig({ - base: './', - build: { - minify: false, - }, +export default makeConfig({}, { plugins: [ - vue(), - vueJsx(), Layouts(), - Pages({ - extensions: ['vue'], - }), - PurgeIcons(), - VueI18n({ - include: path.resolve(__dirname, './src/locales/**'), - }), - Icons({ - customCollections: { - // ~icons/cy/book-x16 - cy: FileSystemIconLoader('./src/assets/icons'), - }, - }), - Components({ - // - resolvers: IconsResolver({ - customCollections: ['cy'], - }), - }), - WindiCSS(), - VueSvgLoader(), + Pages({ extensions: ['vue'] }), ], - define: { - 'process.env': {}, - 'setImmediate': {}, - }, }) diff --git a/packages/app/windi.config.ts b/packages/app/windi.config.ts index 83439e9d60..4a5295851a 100644 --- a/packages/app/windi.config.ts +++ b/packages/app/windi.config.ts @@ -1,32 +1,3 @@ -import { defineConfig } from 'windicss/helpers' -import InteractionVariants from '@windicss/plugin-interaction-variants' -import { IconDuotoneColorsPlugin } from './.windicss/icon-color-plugins' -import { safelist } from './.windicss/safelist' +import WindiConfig from '@packages/frontend-shared/windi.config' -export default defineConfig({ - // This adds !important to all utility classes. https://csswizardry.com/2016/05/the-importance-of-important/ - important: true, - theme: { - extend: { - gridTemplateColumns: { - launchpad: '64px 1fr', - }, - gridTemplateRows: { - launchpad: '64px 1fr', - }, - }, - }, - safelist, - variants: { - backgroundColor: ['group-focus-within', 'group-focus-visible', 'group-active', 'group-visited', 'group-disabled', 'hocus', 'group-hocus', 'can-hover', 'no-hover'], - }, - plugins: [ - InteractionVariants, - IconDuotoneColorsPlugin, - ], - extract: { - // accepts globs and file paths relative to project root - include: ['index.html', 'src/**/*.{vue,html,tsx}'], - exclude: ['node_modules/**/*', '.git/**/*'], - }, -}) +export default WindiConfig diff --git a/packages/launchpad/src/design/colors.ts b/packages/frontend-shared/.windicss/colors.ts similarity index 77% rename from packages/launchpad/src/design/colors.ts rename to packages/frontend-shared/.windicss/colors.ts index a5d1353578..9bf1ebe343 100644 --- a/packages/launchpad/src/design/colors.ts +++ b/packages/frontend-shared/.windicss/colors.ts @@ -1,4 +1,6 @@ -const colors = { +import Colors from 'windicss/colors' + +const customColors = { jade: { 50: '#E0F6FA', 100: '#C2F1DE', @@ -144,46 +146,48 @@ const colors = { }, } -export const customColors = { - ...colors, +export const cyColors = { + ...customColors, primary: { - ...colors.indigo, - DEFAULT: colors.indigo[500], + ...customColors.indigo, + DEFAULT: customColors.indigo[500], }, secondary: { - ...colors.indigo, - DEFAULT: colors.indigo[50], + ...customColors.indigo, + DEFAULT: customColors.indigo[50], }, error: { - ...colors.red, - DEFAULT: colors.red[400], + ...customColors.red, + DEFAULT: customColors.red[400], }, caution: { - ...colors.red, - DEFAULT: colors.red[500], + ...customColors.red, + DEFAULT: customColors.red[500], }, warning: { - ...colors.orange, - DEFAULT: colors.orange[500], + ...customColors.orange, + DEFAULT: customColors.orange[500], }, 'warning-light': { - ...colors.orange, - DEFAULT: colors.orange[400], + ...customColors.orange, + DEFAULT: customColors.orange[400], }, success: { - ...colors.jade, - DEFAULT: colors.jade[400], + ...customColors.jade, + DEFAULT: customColors.jade[400], }, 'success-light': { - ...colors.jade, - DEFAULT: colors.jade[300], + ...customColors.jade, + DEFAULT: customColors.jade[300], }, confirm: { - ...colors.jade, - DEFAULT: colors.jade[500], + ...customColors.jade, + DEFAULT: customColors.jade[500], }, 'body-gray': { - ...colors.gray, - DEFAULT: colors.gray[600], + ...customColors.gray, + DEFAULT: customColors.gray[600], }, } + +export const colors = { ...Colors, ...cyColors } diff --git a/packages/frontend-shared/.windicss/icon-color-plugins.ts b/packages/frontend-shared/.windicss/icon-color-plugins.ts new file mode 100644 index 0000000000..eabe6a5eb4 --- /dev/null +++ b/packages/frontend-shared/.windicss/icon-color-plugins.ts @@ -0,0 +1,108 @@ +/** + * This package adds support for targeting + * light vs dark classes in duotone icons. + * + * It works by adding utility classes and specific selectors + */ + +import createPlugin from 'windicss/plugin' +import { reduce, kebabCase, isObject } from 'lodash' +import Colors from 'windicss/colors' + +interface RuleConfig { + name: string + theme?: (key: string) => string + weight?: string + color?: string +} + +const makeRuleForClass = ({ name, theme, weight, color }: RuleConfig) => { + const resolvedColor = color ? color : weight ? theme?.(`colors.${name}.${weight}`) : theme?.(`colors.${name}`) + let [lightKey, darkKey] = [`.icon-light-${name}`, `.icon-dark-${name}`] + + // transparent, black, and white + if (weight) { + lightKey += `-${weight}` + darkKey += `-${weight}` + } + + return { + // When we're targeting an svg with icon-light-red-500 + // only attach the fill and stroke for those same icons + // and vice versa for icon-dark + [lightKey]: { + '> *[fill].icon-light': { + fill: resolvedColor, + }, + '> *[stroke].icon-light': { + stroke: resolvedColor, + }, + '> *[fill][stroke].icon-light-fill': { + fill: resolvedColor, + }, + }, + [darkKey]: { + '> *[fill].icon-dark-fill': { + fill: resolvedColor, + }, + '> *[fill].icon-dark': { + fill: resolvedColor, + }, + '> *[stroke].icon-dark': { + stroke: resolvedColor, + }, + '> *[fill][stroke].icon-dark-stroke': { + stroke: resolvedColor, + }, + }, + } +} + +function addIconUtilityClasses (theme) { + return reduce(Colors, (acc, variants, colorName) => { + // lightGray => light-gray + const name = kebabCase(colorName) + + // Collect the classes we're going to add to the windicss class registry + let additionalClasses = {} + + // There are both nested and not-nested colors (e.g. black, white) + if (isObject(variants)) { + // multiple levels of colors + additionalClasses = reduce(variants, (variantAcc, _, weight) => { + const rules = makeRuleForClass({ name, theme, weight }) + + return { ...variantAcc, ...rules } + }, {}) + } else { + // single values like black, white + additionalClasses = makeRuleForClass({ name, theme }) + } + + // Output is an object where each new class is a key + // And the selectors and values affected are values + /** + * { + * `.icon-light-green-500`: { + * '> *[stroke].icon-light': { + * stroke: resolvedColor + * }, + * '> *[fill].icon-light': { + * fill: resolvedColor + * } + * } + * } + */ + return { ...acc, ...additionalClasses } + }, { + + // These technically aren't under "colors" + ...makeRuleForClass({ name: 'transparent', color: 'transparent' }), + ...makeRuleForClass({ name: 'current', color: 'currentColor' }), + }) +} + +export const IconDuotoneColorsPlugin = createPlugin(({ theme, addUtilities }) => { + // @ts-ignore - dunno + addUtilities(addIconUtilityClasses(theme)) +}) diff --git a/packages/frontend-shared/.windicss/safelist.ts b/packages/frontend-shared/.windicss/safelist.ts new file mode 100644 index 0000000000..10f99edce9 --- /dev/null +++ b/packages/frontend-shared/.windicss/safelist.ts @@ -0,0 +1,22 @@ +/** + * WindiCSS will strip out any styles that aren't used. + * We do a lot of dynamic stuff, and we're not too concerned + * ith bundle size, so this is a pretty greedy list + */ +import { colors } from './colors' +import { map, reduce, kebabCase } from 'lodash' + +const textSafelist = ['xs', 'sm', 'lg', 'xl', '2xl', '3xl', '4xl', '5xl', '6xl'].map((v) => `text-${v}`).join(' ') +const colorSafelist = reduce(colors, (acc, variants, colorName) => { + const name = kebabCase(colorName) + + return `${acc} + ${map(variants, (_: string, k: string) => { + return `bg-${name}-${k} + text-${name}-${k} + before:bg-${name}-${k} + before:text-${name}-${k}` + }).join(' ')}` +}, '') + +export const safelist = `${textSafelist} ${colorSafelist}` diff --git a/packages/frontend-shared/README.md b/packages/frontend-shared/README.md new file mode 100644 index 0000000000..1d1054f0f5 --- /dev/null +++ b/packages/frontend-shared/README.md @@ -0,0 +1,31 @@ +# Frontend Shared + +## Building + +### For development + +We only use Cypress Component Tests to develop the components in isolation + +```bash +## from repo root +yarn workspace @packages/frontend-shared cypress:open +``` + +## Developing + +For the best development experience, you will want to use VS Code with the [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar) extension. This will give you type completion inside `vue` files. + +## Testing + +```bash +yarn workspace @packages/frontend-shared test-unit +``` + +## Utility class usage + +Windi CSS can create an awesome interactive summary showing our usage of utility classes and design tokens. Running this command will generate this report and serve it on localhost. + +```bash +## from this directory +yarn windi +``` diff --git a/packages/frontend-shared/cypress.json b/packages/frontend-shared/cypress.json new file mode 100644 index 0000000000..865d734369 --- /dev/null +++ b/packages/frontend-shared/cypress.json @@ -0,0 +1,23 @@ +{ + "projectId": "sehy69", + "baseUrl": "http://localhost:5555", + "viewportWidth": 800, + "viewportHeight": 850, + "video": false, + "retries": { + "runMode": 2, + "openMode": 0 + }, + "nodeVersion": "system", + "testFiles": "**/*.spec.{js,ts,tsx,jsx}", + "reporter": "../../node_modules/cypress-multi-reporters/index.js", + "reporterOptions": { + "configFile": "../../mocha-reporter-config.json" + }, + "component": { + "componentFolder": "src/components" + }, + "e2e": { + "supportFile": false + } +} diff --git a/packages/frontend-shared/cypress/fixtures/example.json b/packages/frontend-shared/cypress/fixtures/example.json new file mode 100644 index 0000000000..02e4254378 --- /dev/null +++ b/packages/frontend-shared/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} diff --git a/packages/frontend-shared/cypress/plugins/index.js b/packages/frontend-shared/cypress/plugins/index.js new file mode 100644 index 0000000000..a4615f1780 --- /dev/null +++ b/packages/frontend-shared/cypress/plugins/index.js @@ -0,0 +1,42 @@ +/** + * @type {import('@cypress/vite-dev-server')} + */ +const { startDevServer } = require('@cypress/vite-dev-server') + +/// +// *********************************************************** +// This example plugins/index.js can be used to load plugins +// +// You can change the location of this file or turn off loading +// the plugins file with the 'pluginsFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/plugins-guide +// *********************************************************** +// This function is called when a project is opened or re-opened (e.g. due to +// the project's config changing) + +/** + * @type {Cypress.PluginConfig} + */ +// eslint-disable-next-line no-unused-vars +module.exports = (on, config) => { + // `on` is used to hook into various events Cypress emits + // `config` is the resolved Cypress config + + if (config.testingType === 'component') { + on('dev-server:start', async (options) => { + return startDevServer({ + options, + viteConfig: { + // TODO(tim): Figure out why this isn't being picked up + optimizeDeps: { + include: ['@headlessui/vue', 'vue-prism-component'], + }, + }, + }) + }) + } + + return config // IMPORTANT to return a config +} diff --git a/packages/frontend-shared/cypress/support/commands.ts b/packages/frontend-shared/cypress/support/common.ts similarity index 95% rename from packages/frontend-shared/cypress/support/commands.ts rename to packages/frontend-shared/cypress/support/common.ts index 5e54b15e79..2c2b27775a 100644 --- a/packages/frontend-shared/cypress/support/commands.ts +++ b/packages/frontend-shared/cypress/support/common.ts @@ -15,13 +15,14 @@ import { navigationMenu } from '../../src/graphql/testNavigationMenu' import { query as stubQuery } from '../../src/graphql/testQuery' import { wizard as stubWizard } from '../../src/graphql/testWizard' import { app as stubApp } from '../../src/graphql/testApp' +import { createI18n } from '@cy/i18n' /** * This variable is mimicing ipc provided by electron. * It has to be loaded run before initializing GraphQL * because graphql uses it. */ -(window as any).ipc = { +;(window as any).ipc = { on: () => {}, send: () => {}, } @@ -37,7 +38,11 @@ const createContext = (): ClientTestContext => { } } -export const registerMountFn = ({ plugins }) => { +export interface MountFnOptions { + plugins?: (() => any)[] +} + +export const registerMountFn = ({ plugins }: MountFnOptions = {}) => { Cypress.Commands.add( 'mount', [0]>(comp: C, options: CyMountOptions = {}) => { @@ -49,6 +54,8 @@ export const registerMountFn = ({ plugins }) => { options?.global?.plugins?.push(pluginFn()) }) + options.global.plugins.push(createI18n()) + const context = createContext() options.global.plugins.push({ @@ -75,6 +82,7 @@ export const registerMountFn = ({ plugins }) => { transition: false, }, plugins: [ + createI18n(), { install (app) { app.use(urql, testUrqlClient({ diff --git a/packages/frontend-shared/cypress/support/index.ts b/packages/frontend-shared/cypress/support/index.ts new file mode 100644 index 0000000000..10d9c219bb --- /dev/null +++ b/packages/frontend-shared/cypress/support/index.ts @@ -0,0 +1,5 @@ +import { registerMountFn } from './common' +import '../../src/styles/shared.scss' +import 'virtual:windi.css' + +registerMountFn() diff --git a/packages/frontend-shared/package.json b/packages/frontend-shared/package.json index d45db5f9e4..c4cb4a41c2 100644 --- a/packages/frontend-shared/package.json +++ b/packages/frontend-shared/package.json @@ -4,29 +4,56 @@ "private": true, "scripts": { "build-prod": "tsc || echo 'built, with type errors'", - "check-ts": "tsc --noEmit", + "check-ts": "vue-tsc --noEmit", "clean-deps": "rimraf node_modules", - "clean": "rimraf src/*.js src/**/*.js" + "clean": "rimraf dist ./node_modules/.vite src/*.js src/**/*.js && echo 'cleaned'", + "test": "yarn cypress:run && yarn types", + "windi": "yarn windicss-analysis", + "cypress:open": "cross-env TZ=America/New_York node ../../scripts/cypress open-ct --project ${PWD}", + "cypress:run": "cross-env TZ=America/New_York node ../../scripts/cypress run-ct --project ${PWD}", + "dev": "vite --open" }, "dependencies": {}, "devDependencies": { + "@antfu/utils": "^0.3.0", + "@cypress/vite-dev-server": "0.0.0-development", + "@cypress/vue": "0.0.0-development", + "@headlessui/vue": "1.4.0", + "@iconify/json": "1.1.368", + "@iconify/vue": "3.0.0-beta.1", "@intlify/vite-plugin-vue-i18n": "2.4.0", "@testing-library/cypress": "8.0.0", "@urql/core": "2.3.1", "@urql/exchange-execute": "1.1.0", "@urql/exchange-graphcache": "4.3.3", "@urql/vue": "0.4.3", + "@vitejs/plugin-vue": "^1.9.2", + "@vitejs/plugin-vue-jsx": "^1.1.8", + "@vue/compiler-core": "3.2.6", + "@vue/compiler-dom": "3.2.6", + "@vue/compiler-sfc": "3.2.6", + "@windicss/plugin-interaction-variants": "1.0.0", "bluebird": "3.5.3", "classnames": "2.3.1", "fake-uuid": "^1.0.0", "graphql": "^15.5.1", "graphql-relay": "^0.9.0", "graphql-tag": "^2.12.5", + "lodash": "^4.17.21", + "modern-normalize": "1.1.0", "rimraf": "3.0.2", + "unplugin-icons": "^0.11.4", + "unplugin-vue-components": "^0.15.4", + "vite": "^2.5.10", "vite-plugin-icons": "0.6.3", + "vite-plugin-windicss": "^1.4.7", + "vite-svg-loader": "^2.2.0", "vue": "3.2.6", "vue-eslint-parser": "7.11.0", - "vue-i18n": "9.2.0-beta.1", + "vue-i18n": "^9.2.0-beta.7", + "vue-tsc": "^0.3.0", + "windicss": "3.1.8", + "windicss-analysis": "^0.3.4", "wonka": "^4.0.15" } } diff --git a/packages/app/src/assets/icons/book.svg b/packages/frontend-shared/src/assets/icons/book.svg similarity index 100% rename from packages/app/src/assets/icons/book.svg rename to packages/frontend-shared/src/assets/icons/book.svg diff --git a/packages/app/src/assets/icons/book_x16.svg b/packages/frontend-shared/src/assets/icons/book_x16.svg similarity index 100% rename from packages/app/src/assets/icons/book_x16.svg rename to packages/frontend-shared/src/assets/icons/book_x16.svg diff --git a/packages/app/src/assets/icons/book_x24.svg b/packages/frontend-shared/src/assets/icons/book_x24.svg similarity index 100% rename from packages/app/src/assets/icons/book_x24.svg rename to packages/frontend-shared/src/assets/icons/book_x24.svg diff --git a/packages/app/src/assets/icons/book_x48.svg b/packages/frontend-shared/src/assets/icons/book_x48.svg similarity index 100% rename from packages/app/src/assets/icons/book_x48.svg rename to packages/frontend-shared/src/assets/icons/book_x48.svg diff --git a/packages/app/src/assets/icons/bookmark_x16.svg b/packages/frontend-shared/src/assets/icons/bookmark_x16.svg similarity index 100% rename from packages/app/src/assets/icons/bookmark_x16.svg rename to packages/frontend-shared/src/assets/icons/bookmark_x16.svg diff --git a/packages/app/src/assets/icons/bookmark_x24.svg b/packages/frontend-shared/src/assets/icons/bookmark_x24.svg similarity index 100% rename from packages/app/src/assets/icons/bookmark_x24.svg rename to packages/frontend-shared/src/assets/icons/bookmark_x24.svg diff --git a/packages/app/src/assets/icons/code-editor_x16.svg b/packages/frontend-shared/src/assets/icons/code-editor_x16.svg similarity index 100% rename from packages/app/src/assets/icons/code-editor_x16.svg rename to packages/frontend-shared/src/assets/icons/code-editor_x16.svg diff --git a/packages/app/src/assets/icons/code-editor_x24.svg b/packages/frontend-shared/src/assets/icons/code-editor_x24.svg similarity index 100% rename from packages/app/src/assets/icons/code-editor_x24.svg rename to packages/frontend-shared/src/assets/icons/code-editor_x24.svg diff --git a/packages/app/src/assets/icons/command-key_x16.svg b/packages/frontend-shared/src/assets/icons/command-key_x16.svg similarity index 100% rename from packages/app/src/assets/icons/command-key_x16.svg rename to packages/frontend-shared/src/assets/icons/command-key_x16.svg diff --git a/packages/app/src/assets/icons/grid-2x2_x16.svg b/packages/frontend-shared/src/assets/icons/grid-2x2_x16.svg similarity index 100% rename from packages/app/src/assets/icons/grid-2x2_x16.svg rename to packages/frontend-shared/src/assets/icons/grid-2x2_x16.svg diff --git a/packages/app/src/assets/icons/grid-2x2_x24.svg b/packages/frontend-shared/src/assets/icons/grid-2x2_x24.svg similarity index 100% rename from packages/app/src/assets/icons/grid-2x2_x24.svg rename to packages/frontend-shared/src/assets/icons/grid-2x2_x24.svg diff --git a/packages/app/src/assets/icons/placeholder_x12.svg b/packages/frontend-shared/src/assets/icons/placeholder_x12.svg similarity index 100% rename from packages/app/src/assets/icons/placeholder_x12.svg rename to packages/frontend-shared/src/assets/icons/placeholder_x12.svg diff --git a/packages/app/src/assets/icons/placeholder_x16.svg b/packages/frontend-shared/src/assets/icons/placeholder_x16.svg similarity index 100% rename from packages/app/src/assets/icons/placeholder_x16.svg rename to packages/frontend-shared/src/assets/icons/placeholder_x16.svg diff --git a/packages/app/src/assets/icons/placeholder_x24.svg b/packages/frontend-shared/src/assets/icons/placeholder_x24.svg similarity index 100% rename from packages/app/src/assets/icons/placeholder_x24.svg rename to packages/frontend-shared/src/assets/icons/placeholder_x24.svg diff --git a/packages/app/src/assets/icons/placeholder_x32.svg b/packages/frontend-shared/src/assets/icons/placeholder_x32.svg similarity index 100% rename from packages/app/src/assets/icons/placeholder_x32.svg rename to packages/frontend-shared/src/assets/icons/placeholder_x32.svg diff --git a/packages/app/src/assets/icons/placeholder_x40.svg b/packages/frontend-shared/src/assets/icons/placeholder_x40.svg similarity index 100% rename from packages/app/src/assets/icons/placeholder_x40.svg rename to packages/frontend-shared/src/assets/icons/placeholder_x40.svg diff --git a/packages/app/src/assets/icons/placeholder_x48.svg b/packages/frontend-shared/src/assets/icons/placeholder_x48.svg similarity index 100% rename from packages/app/src/assets/icons/placeholder_x48.svg rename to packages/frontend-shared/src/assets/icons/placeholder_x48.svg diff --git a/packages/app/src/assets/icons/play-large_x16.svg b/packages/frontend-shared/src/assets/icons/play-large_x16.svg similarity index 100% rename from packages/app/src/assets/icons/play-large_x16.svg rename to packages/frontend-shared/src/assets/icons/play-large_x16.svg diff --git a/packages/app/src/assets/icons/play-small_x16.svg b/packages/frontend-shared/src/assets/icons/play-small_x16.svg similarity index 100% rename from packages/app/src/assets/icons/play-small_x16.svg rename to packages/frontend-shared/src/assets/icons/play-small_x16.svg diff --git a/packages/app/src/assets/icons/settings_x16.svg b/packages/frontend-shared/src/assets/icons/settings_x16.svg similarity index 100% rename from packages/app/src/assets/icons/settings_x16.svg rename to packages/frontend-shared/src/assets/icons/settings_x16.svg diff --git a/packages/app/src/assets/icons/settings_x24.svg b/packages/frontend-shared/src/assets/icons/settings_x24.svg similarity index 100% rename from packages/app/src/assets/icons/settings_x24.svg rename to packages/frontend-shared/src/assets/icons/settings_x24.svg diff --git a/packages/app/src/assets/icons/test-results_x16.svg b/packages/frontend-shared/src/assets/icons/test-results_x16.svg similarity index 100% rename from packages/app/src/assets/icons/test-results_x16.svg rename to packages/frontend-shared/src/assets/icons/test-results_x16.svg diff --git a/packages/app/src/assets/icons/test-results_x24.svg b/packages/frontend-shared/src/assets/icons/test-results_x24.svg similarity index 100% rename from packages/app/src/assets/icons/test-results_x24.svg rename to packages/frontend-shared/src/assets/icons/test-results_x24.svg diff --git a/packages/launchpad/src/components/button/Button.spec.tsx b/packages/frontend-shared/src/components/Button.spec.tsx similarity index 91% rename from packages/launchpad/src/components/button/Button.spec.tsx rename to packages/frontend-shared/src/components/Button.spec.tsx index ae55ca8e0c..41a5ede668 100644 --- a/packages/launchpad/src/components/button/Button.spec.tsx +++ b/packages/frontend-shared/src/components/Button.spec.tsx @@ -1,5 +1,5 @@ import Button from './Button.vue' -import IconCoffee from 'virtual:vite-icons/mdi/coffee' +import IconCoffee from '~icons/mdi/coffee' describe('