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.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-## What is Cypress?
-
-
-
-
-
-
-
-## Installing
-
-[](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
-```
-
-
-
-
-## Contributing
-
-- [](https://circleci.com/gh/cypress-io/cypress/tree/develop) - `develop` branch
-- [](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
-
-[](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
-
-[](https://www.cypress.io/)
-
-```
-[](https://www.cypress.io/)
-```
+
+
+
+
+
+cypress
+
+
+
+[]()
+[](https://www.reddit.com/user/Wordbook_Bot)
+[](https://github.com/kylelobo/The-Documentation-Compendium/issues)
+[](https://github.com/kylelobo/The-Documentation-Compendium/pulls)
+[](/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
+
+
+
+## π 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('', () => {
it('playground', { viewportWidth: 200, viewportHeight: 300 }, () => {
diff --git a/packages/launchpad/src/components/button/Button.vue b/packages/frontend-shared/src/components/Button.vue
similarity index 86%
rename from packages/launchpad/src/components/button/Button.vue
rename to packages/frontend-shared/src/components/Button.vue
index 10599cd2b4..3a4fc910d0 100644
--- a/packages/launchpad/src/components/button/Button.vue
+++ b/packages/frontend-shared/src/components/Button.vue
@@ -35,13 +35,21 @@
diff --git a/packages/launchpad/src/settings/device/ExternalEditorSettings.spec.tsx b/packages/launchpad/src/settings/device/ExternalEditorSettings.spec.tsx
index adddb3859a..e46ec06c72 100644
--- a/packages/launchpad/src/settings/device/ExternalEditorSettings.spec.tsx
+++ b/packages/launchpad/src/settings/device/ExternalEditorSettings.spec.tsx
@@ -1,5 +1,5 @@
import ExternalEditorSettings from './ExternalEditorSettings.vue'
-import { defaultMessages } from '../../locales/i18n'
+import { defaultMessages } from '@cy/i18n'
const editorText = defaultMessages.settingsPage.editor
diff --git a/packages/launchpad/src/settings/device/ExternalEditorSettings.vue b/packages/launchpad/src/settings/device/ExternalEditorSettings.vue
index b10c1587c8..c2e3715d74 100644
--- a/packages/launchpad/src/settings/device/ExternalEditorSettings.vue
+++ b/packages/launchpad/src/settings/device/ExternalEditorSettings.vue
@@ -38,17 +38,17 @@