feat(unification): adding specs list for the app (#18391)
* wip * wip * Adding required icons and strings for spec list * adding icons with some duplication * wip * fixing the colors and classes * removing the Icon from usage in the button and input * green => jade * wip * Fixes * wip * merge * fixing no projects state * Adding better spec pattern parsing * Adding routing for the runner * adding more tests * update tests * chore: lint * update types * types * chore: align vue-i18n version * update findSpecs * remove old spec * omit new properties returned from findSpecs * fix test * use different type Co-authored-by: Jessica Sachs <jess@jessicasachs.io> Co-authored-by: Tim Griesser <tgriesser10@gmail.com>
@@ -9,6 +9,6 @@ module.exports = {
|
||||
localSchemaFile: path.join(__dirname, 'packages/graphql/schemas/schema.graphql'),
|
||||
},
|
||||
tagName: 'gql',
|
||||
includes: [path.join(__dirname, 'packages/launchpad/src/**/*.vue')],
|
||||
includes: [path.join(__dirname, 'packages/{launchpad,app}/src/**/*.vue')],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
/**
|
||||
* 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 }) => {
|
||||
addUtilities(addIconUtilityClasses(theme))
|
||||
})
|
||||
@@ -1,29 +0,0 @@
|
||||
/**
|
||||
* 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 'windicss/colors'
|
||||
import { map, reduce, kebabCase, isObject } from 'lodash'
|
||||
|
||||
export const safelist = reduce(Colors, (acc, variants, colorName) => {
|
||||
const name = kebabCase(colorName)
|
||||
|
||||
const classesForColor = map(variants, (_: string, k: string) => {
|
||||
const classes = `before:bg-${name}
|
||||
before:text-${name}
|
||||
bg-${name}
|
||||
text-${name}
|
||||
`
|
||||
|
||||
if (isObject(variants)) {
|
||||
// weighted colors
|
||||
return classes.split(' ').map((selector) => `${selector}-${k}`)
|
||||
}
|
||||
|
||||
// else, black + white
|
||||
return classes
|
||||
})
|
||||
|
||||
return `${acc} ${classesForColor.join(' ')}`
|
||||
}, '')
|
||||
@@ -9,7 +9,7 @@
|
||||
"openMode": 0
|
||||
},
|
||||
"nodeVersion": "system",
|
||||
"testFiles": "**/*.spec.{js,ts,tsx,jsx}",
|
||||
"testFiles": "**/*.spec.{j,ts,tsx,jsx}",
|
||||
"reporter": "../../node_modules/cypress-multi-reporters/index.js",
|
||||
"reporterOptions": {
|
||||
"configFile": "../../mocha-reporter-config.json"
|
||||
|
||||
152
packages/app/cypress/support/fixtures.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
// @ts-nocheck
|
||||
// @ts-ignore
|
||||
import * as JustMyLuck from 'just-my-luck'
|
||||
import faker from 'faker'
|
||||
import { template, keys, reduce, templateSettings } from 'lodash'
|
||||
import combineProperties from 'combine-properties'
|
||||
|
||||
templateSettings.interpolate = /{{([\s\S]+?)}}/g
|
||||
|
||||
let jml
|
||||
const setupSeeds = () => {
|
||||
const seed = 2
|
||||
|
||||
faker.seed(seed)
|
||||
jml = new JustMyLuck(JustMyLuck.MersenneTwister(seed))
|
||||
}
|
||||
|
||||
setupSeeds()
|
||||
|
||||
beforeEach(() => setupSeeds)
|
||||
|
||||
/**
|
||||
* Component Naming Fixtures
|
||||
*/
|
||||
export const modifiers = [
|
||||
'Async',
|
||||
'Dynamic',
|
||||
'Static',
|
||||
'Virtual',
|
||||
'Lazy',
|
||||
]
|
||||
|
||||
export const domainModels = [
|
||||
'Person',
|
||||
'Product',
|
||||
'Spec',
|
||||
'Settings',
|
||||
'Account',
|
||||
'Login',
|
||||
'Logout',
|
||||
'Launchpad',
|
||||
'Wizard',
|
||||
]
|
||||
|
||||
export const componentNames = [
|
||||
'List',
|
||||
'Table',
|
||||
'Header',
|
||||
'Footer',
|
||||
'Button',
|
||||
'Cell',
|
||||
'Row',
|
||||
'Skeleton',
|
||||
'Loader',
|
||||
'Layout',
|
||||
]
|
||||
|
||||
export const specPattern = ['.spec', '_spec']
|
||||
|
||||
export const fileExtension = ['.tsx', '.jsx', '.ts', '.js']
|
||||
|
||||
export const directories = {
|
||||
rootDedicated: template('tests'),
|
||||
rootSrc: template('src'),
|
||||
monorepo: template('packages/{{component}}/test'),
|
||||
jestRoot: template('__test__'),
|
||||
jestNestedLib: template('lib/{{component}}{{component2}}/__test__'),
|
||||
dedicatedNested: template('lib/{{component}}/test'),
|
||||
jestNested: template('src/{{component}}/__test__'),
|
||||
componentsNested: template('src/components/{{component}}'),
|
||||
componentsFlat: template('src/{{component}}'),
|
||||
viewsFlat: template('src/views'),
|
||||
frontendFlat: template('frontend'),
|
||||
frontendComponentsFlat: template('frontend/components'),
|
||||
}
|
||||
|
||||
const nameTemplates = {
|
||||
// Business Logic Components
|
||||
longDomain: template(`{{prefix}}{{modifier}}{{domain}}{{component}}`),
|
||||
longDomain2: template(`{{prefix}}{{domain}}{{component}}{{component2}}`),
|
||||
|
||||
// App Components
|
||||
page1: template(`{{domain}}Page`),
|
||||
layout: template(`{{domain}}Layout`),
|
||||
|
||||
presentationalShort: template(`Base{{component}}`),
|
||||
presentationalLong: template(`Base{{component}}{{component2}}`),
|
||||
medium1: template(`{{prefix}}{{modifier}}{{component}}`),
|
||||
medium2: template(`{{prefix}}{{component}}{{component2}}`),
|
||||
short: template(`{{prefix}}{{component}}`),
|
||||
}
|
||||
|
||||
const prefixes = ['I', 'V', 'Cy', null]
|
||||
|
||||
export const componentNameGenerator = (options: { template: any, omit: any, overrides: any } = { template: nameTemplates.medium1, omit: [], overrides: {} }) => {
|
||||
const withoutValues = reduce(options.omit, (acc, v) => {
|
||||
acc[v] = null
|
||||
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const components = jml.pickCombination(componentNames, 2)
|
||||
const defaultOptions = {
|
||||
modifier: jml.pick(modifiers),
|
||||
domain: jml.pick(domainModels),
|
||||
prefix: jml.pick(prefixes),
|
||||
component: components[0],
|
||||
component2: components[1],
|
||||
}
|
||||
|
||||
return options.template({
|
||||
...defaultOptions,
|
||||
...withoutValues,
|
||||
...options.overrides,
|
||||
})
|
||||
}
|
||||
|
||||
const allRandomComponents = combineProperties({
|
||||
domain: domainModels,
|
||||
modifier: modifiers,
|
||||
prefix: prefixes,
|
||||
component: componentNames,
|
||||
component2: componentNames,
|
||||
fileExtension,
|
||||
specPattern,
|
||||
directory: keys(directories),
|
||||
})
|
||||
|
||||
export const randomComponents = (n = 200) => {
|
||||
return faker.random.arrayElements(allRandomComponents, n).map((d) => {
|
||||
const name = componentNameGenerator({
|
||||
overrides: d,
|
||||
template: faker.random.objectElement(nameTemplates),
|
||||
})
|
||||
|
||||
const gitFileState = jml.pick(['modified', 'unmodified', 'added', 'deleted'])
|
||||
|
||||
return {
|
||||
componentName: name,
|
||||
relativePath: directories[d.directory](d),
|
||||
specExtension: d.specPattern,
|
||||
fileExtension: d.fileExtension,
|
||||
name: `${name}${d.specPattern}${d.fileExtension}`,
|
||||
id: faker.datatype.uuid(),
|
||||
gitInfo: {
|
||||
comitter: gitFileState ? faker.internet.userName() : undefined,
|
||||
timeAgo: gitFileState ? faker.datatype.datetime() : undefined,
|
||||
fileState: gitFileState,
|
||||
},
|
||||
}
|
||||
}, n)
|
||||
}
|
||||
@@ -28,6 +28,7 @@
|
||||
"@intlify/vite-plugin-vue-i18n": "2.4.0",
|
||||
"@packages/frontend-shared": "0.0.0-development",
|
||||
"@testing-library/cypress": "8.0.0",
|
||||
"@types/faker": "5.5.8",
|
||||
"@urql/core": "2.3.1",
|
||||
"@urql/vue": "0.4.3",
|
||||
"@vitejs/plugin-vue": "1.2.4",
|
||||
@@ -36,11 +37,14 @@
|
||||
"@windicss/plugin-interaction-variants": "1.0.0",
|
||||
"bluebird": "3.5.3",
|
||||
"classnames": "2.3.1",
|
||||
"combine-properties": "0.1.0",
|
||||
"concurrently": "^6.2.0",
|
||||
"cross-env": "6.0.3",
|
||||
"faker": "5.5.3",
|
||||
"graphql": "^15.5.1",
|
||||
"graphql-tag": "^2.12.5",
|
||||
"javascript-time-ago": "2.3.8",
|
||||
"just-my-luck": "3.0.0",
|
||||
"prismjs": "1.24.0",
|
||||
"rimraf": "3.0.2",
|
||||
"rollup-plugin-polyfill-node": "^0.7.0",
|
||||
@@ -55,7 +59,7 @@
|
||||
"vite-plugin-windicss": "1.2.4",
|
||||
"vite-svg-loader": "2.1.1",
|
||||
"vue": "3.2.6",
|
||||
"vue-i18n": "9.2.0-beta.1",
|
||||
"vue-i18n": "9.2.0-beta.7",
|
||||
"vue-prism-component": "2.0.0",
|
||||
"vue-prism-editor": "^2.0.0-alpha.2",
|
||||
"vue-router": "4",
|
||||
|
||||
@@ -4,6 +4,9 @@ import Foo from './Foo.vue'
|
||||
describe('Foo', () => {
|
||||
it('renders something', () => {
|
||||
cy.mountFragment(FooFragmentDoc, {
|
||||
onResult: (ctx) => {
|
||||
return ctx
|
||||
},
|
||||
render: (gqlVal) => {
|
||||
return <Foo gql={gqlVal} />
|
||||
},
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 9L8 12L11 9M5 4L8 7L11 4" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 242 B |
3
packages/app/src/assets/icons/chevron-down-large_x16.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 5L8 11L14 5" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 229 B |
3
packages/app/src/assets/icons/chevron-down-small_x16.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 6L8 10L12 6" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 229 B |
3
packages/app/src/assets/icons/chevron-down-small_x8.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 2.5L4 5.5L7 2.5" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 229 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7 11L4 8L7 5M12 11L9 8L12 5" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 243 B |
3
packages/app/src/assets/icons/chevron-left-large_x16.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.9999 13.9999L4.99994 7.99988L10.9999 1.99988" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 263 B |
3
packages/app/src/assets/icons/chevron-left-small_x16.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 4L6 8L10 12" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 230 B |
3
packages/app/src/assets/icons/chevron-left-small_x8.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5.5 1L2.5 4L5.5 7" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 229 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9 11L12 8L9 5M4 11L7 8L4 5" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 242 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.99994 13.9999L10.9999 7.99988L4.99994 1.99988" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 263 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 12L10 8L6 4" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 229 B |
3
packages/app/src/assets/icons/chevron-right-small_x8.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2.5 1L5.5 4L2.5 7" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 229 B |
3
packages/app/src/assets/icons/chevron-up-double_x16.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M5 7L8 4L11 7M5 12L8 9L11 12" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 243 B |
3
packages/app/src/assets/icons/chevron-up-large_x16.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 11L8 5L14 11" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 230 B |
3
packages/app/src/assets/icons/chevron-up-small_x16.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.9999 9.99988L7.99991 5.99988L3.99991 9.99988" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 263 B |
3
packages/app/src/assets/icons/chevron-up-small_x8.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1 5.5L4 2.5L7 5.5" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 229 B |
4
packages/app/src/assets/icons/document-added_x16.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M6 10L6.5 9M10 10L9.5 9M6.5 9L8 6L9.5 9M6.5 9H9.5M14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 705 B |
4
packages/app/src/assets/icons/document-blank_x16.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 14V2C2 1.44772 2.44772 1 3 1H13C13.5523 1 14 1.44772 14 2V14C14 14.5523 13.5523 15 13 15H3C2.44772 15 2 14.5523 2 14Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M5 8H8M5 5H11M5 11H10M13 1L3 1C2.44772 1 2 1.44772 2 2V14C2 14.5523 2.44772 15 3 15H13C13.5523 15 14 14.5523 14 14V2C14 1.44772 13.5523 1 13 1Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 525 B |
4
packages/app/src/assets/icons/document-blank_x24.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 20V4C4 2.89543 4.89543 2 6 2H14L20 8V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M14 2H6C4.89543 2 4 2.89543 4 4V20C4 21.1046 4.89543 22 6 22H18C19.1046 22 20 21.1046 20 20V8M14 2L20 8M14 2V8H20" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 474 B |
4
packages/app/src/assets/icons/document-blank_x48.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 39V9C10 8.44772 10.4477 8 11 8H37C37.5523 8 38 8.44772 38 9V39C38 39.5523 37.5523 40 37 40H11C10.4477 40 10 39.5523 10 39Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M17 24H24M17 17.1429H31M17 30.8571H28.6667M37 8L11 8C10.4477 8 10 8.44772 10 9V39C10 39.5523 10.4477 40 11 40H37C37.5523 40 38 39.5523 38 39V9C38 8.44772 37.5523 8 37 8Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 557 B |
7
packages/app/src/assets/icons/document-deleted_x16.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071
|
||||
11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843V13C14
|
||||
14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13Z" fill="#D0D2E0"
|
||||
stroke="#1B1E2E" class="icon-dark-stroke icon-light-fill" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 447 B |
4
packages/app/src/assets/icons/document-download_x16.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M8 5V11M8 11L10 9M8 11L6 9M14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 682 B |
4
packages/app/src/assets/icons/document-download_x24.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M12 16V8M12 16L15 13M12 16L9 13M20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 687 B |
4
packages/app/src/assets/icons/document-minus_x16.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 15C2.89543 15 2 14.1046 2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843V13C14 14.1046 13.1046 15 12 15H4Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M6 8H10M14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 663 B |
4
packages/app/src/assets/icons/document-minus_x24.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M15 12H9M20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 664 B |
4
packages/app/src/assets/icons/document-modified_x16.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M5 10L6 6L8 9L10 6L11 10M14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 680 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 15C2.44772 15 2 14.5523 2 14V2C2 1.44772 2.44772 1 3 1L13 1C13.5523 1 14 1.44772 14 2V14C14 14.5523 13.5523 15 13 15H3Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M6 6.5H10M8 8.5V4.5M6 11.5H10M13 1L3 1C2.44772 1 2 1.44772 2 2V14C2 14.5523 2.44772 15 3 15H13C13.5523 15 14 14.5523 14 14V2C14 1.44772 13.5523 1 13 1Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 535 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M12 13V10M12 7V10M12 10H15M12 10H9M9 17H15M20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 698 B |
4
packages/app/src/assets/icons/document-plus_x16.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 15C2.44772 15 2 14.5523 2 14V2C2 1.44772 2.44772 1 3 1H13C13.5523 1 14 1.44772 14 2V14C14 14.5523 13.5523 15 13 15H3Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M6 8H10M8 10V6M13 1H3C2.44772 1 2 1.44772 2 2V14C2 14.5523 2.44772 15 3 15H13C13.5523 15 14 14.5523 14 14V2C14 1.44772 13.5523 1 13 1Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 516 B |
4
packages/app/src/assets/icons/document-plus_x24.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M12 15V12M12 9V12M12 12H15M12 12H9M20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 690 B |
6
packages/app/src/assets/icons/document-script_x24.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 1H17C18.6569 1 20 2.34315 20 4V19M4 1H3C1.89543 1 1 1.89543 1 3V3C1 4.10457 1.89543 5 3 5H4M4 1V5M11 6H16M11 10H16M11 14H16M4 5V20C4 21.6569 5.34315 23 7 23V23M20 19H21C22.1046 19 23 19.8954 23 21V21C23 22.1046 22.1046 23 21 23H20H7M20 19H7V19C8.10457 20.1046 8.10457 21.8954 7 23V23" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9 6C9 6.55228 8.55228 7 8 7C7.44772 7 7 6.55228 7 6C7 5.44772 7.44772 5 8 5C8.55228 5 9 5.44772 9 6Z" fill="#1B1E2E"/>
|
||||
<path d="M9 10C9 10.5523 8.55228 11 8 11C7.44772 11 7 10.5523 7 10C7 9.44772 7.44772 9 8 9C8.55228 9 9 9.44772 9 10Z" fill="#1B1E2E"/>
|
||||
<path d="M9 14C9 14.5523 8.55228 15 8 15C7.44772 15 7 14.5523 7 14C7 13.4477 7.44772 13 8 13C8.55228 13 9 13.4477 9 14Z" fill="#1B1E2E"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 903 B |
3
packages/app/src/assets/icons/document-sheet_x24.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 1C9.73481 1.00006 9.48049 1.10545 9.293 1.293L3.293 7.293C3.10545 7.48049 3.00006 7.73481 3 8V20C3 20.7956 3.31607 21.5587 3.87868 22.1213C4.44129 22.6839 5.20435 23 6 23H7C7.26522 23 7.51957 22.8946 7.70711 22.7071C7.89464 22.5196 8 22.2652 8 22C8 21.7348 7.89464 21.4804 7.70711 21.2929C7.51957 21.1054 7.26522 21 7 21H6C5.73478 21 5.48043 20.8946 5.29289 20.7071C5.10536 20.5196 5 20.2652 5 20V9H10C10.2652 9 10.5196 8.89464 10.7071 8.70711C10.8946 8.51957 11 8.26522 11 8V3H18C18.2652 3 18.5196 3.10536 18.7071 3.29289C18.8946 3.48043 19 3.73478 19 4V9C19 9.26522 19.1054 9.51957 19.2929 9.70711C19.4804 9.89464 19.7348 10 20 10C20.2652 10 20.5196 9.89464 20.7071 9.70711C20.8946 9.51957 21 9.26522 21 9V4C21 3.20435 20.6839 2.44129 20.1213 1.87868C19.5587 1.31607 18.7956 1 18 1H10ZM9 7H6.414L9 4.414V7ZM11 12C10.7348 12 10.4804 12.1054 10.2929 12.2929C10.1054 12.4804 10 12.7348 10 13V21C10 21.2652 10.1054 21.5196 10.2929 21.7071C10.4804 21.8946 10.7348 22 11 22H21C21.2652 22 21.5196 21.8946 21.7071 21.7071C21.8946 21.5196 22 21.2652 22 21V13C22 12.7348 21.8946 12.4804 21.7071 12.2929C21.5196 12.1054 21.2652 12 21 12H11ZM12 16V14H14V16H12ZM16 16V14H20V16H16ZM16 20V18H20V20H16ZM14 18V20H12V18H14Z" fill="#1B1E2E"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
4
packages/app/src/assets/icons/document-star_x16.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 15C2.44772 15 2 14.5523 2 14V2C2 1.44772 2.44772 1 3 1H13C13.5523 1 14 1.44772 14 2V14C14 14.5523 13.5523 15 13 15H3Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M8.00001 5.75001L8.00133 7.99819M8.00133 7.99819L10.1399 7.30472M8.00133 7.99819L9.32253 9.8203M8.00133 7.99819L6.67749 9.8203M8.00133 7.99819L5.86013 7.30472M13 1H3C2.44772 1 2 1.44772 2 2V14C2 14.5523 2.44772 15 3 15H13C13.5523 15 14 14.5523 14 14V2C14 1.44772 13.5523 1 13 1Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 660 B |
4
packages/app/src/assets/icons/document-star_x24.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 22C4.89543 22 4 21.1046 4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264V20C20 21.1046 19.1046 22 18 22H6Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M12 8.84375V12.0032M12 12.0032L15.0018 11.0247M12 12.0032L13.8552 14.5535M12 12.0032L10.1448 14.5535M12 12.0032L8.99823 11.0247M20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 783 B |
4
packages/app/src/assets/icons/magnifying-glass_x16.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 7C12 8.38071 11.4404 9.63071 10.5355 10.5355C9.63071 11.4404 8.38071 12 7 12C4.23858 12 2 9.76142 2 7C2 4.23858 4.23858 2 7 2C9.76142 2 12 4.23858 12 7Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M10.5355 10.5355C11.4404 9.63071 12 8.38071 12 7C12 4.23858 9.76142 2 7 2C4.23858 2 2 4.23858 2 7C2 9.76142 4.23858 12 7 12C8.38071 12 9.63071 11.4404 10.5355 10.5355ZM10.5355 10.5355L14 14" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 607 B |
4
packages/app/src/assets/logos/github.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="48" height="48" rx="4" fill="white"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.9997 17.0024C20.1345 17.0024 17 20.1364 17 24.0021C17 27.095 19.0055 29.718 21.7868 30.644C22.1369 30.7088 22.2656 30.4918 22.2656 30.3068C22.2656 30.1399 22.2586 29.5885 22.2558 29.0041C20.3082 29.4276 19.8976 28.1778 19.8976 28.1778C19.5793 27.3686 19.1204 27.1534 19.1204 27.1534C18.4854 26.7186 19.1688 26.7281 19.1688 26.7281C19.8715 26.7772 20.2415 27.449 20.2415 27.449C20.8663 28.5192 21.8796 28.2094 22.2787 28.0308C22.3418 27.5784 22.5226 27.2694 22.7231 27.0945C21.1683 26.918 19.5338 26.3176 19.5338 23.6352C19.5338 22.8712 19.8077 22.2465 20.2549 21.7566C20.1821 21.5799 19.9423 20.8683 20.3224 19.9043C20.3224 19.9043 20.9102 19.716 22.248 20.6218C22.8061 20.4671 23.4047 20.389 23.9992 20.3864C24.5942 20.389 25.1939 20.4668 25.7528 20.6218C27.0888 19.7165 27.6761 19.9043 27.6761 19.9043C28.0567 20.8686 27.8179 21.5806 27.7451 21.7566C28.1939 22.2465 28.4654 22.8712 28.4654 23.6352C28.4654 26.3238 26.8273 26.9149 25.2691 27.0883C25.5202 27.3053 25.7445 27.7314 25.7445 28.384C25.7445 29.3201 25.7365 30.0745 25.7365 30.3047C25.7365 30.491 25.8626 30.7088 26.2176 30.6406C28.9974 29.7141 31.0003 27.0909 31.0003 23.9997C31.0003 20.1345 27.8663 17 24.0003 17L23.9998 17.0023L23.9997 17.0024Z" fill="black"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
90
packages/app/src/components/button/Button.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<button
|
||||
style="width: fit-content"
|
||||
class="flex items-center border rounded-sm gap-8px focus:border-indigo-600 focus:outline-transparent"
|
||||
:class="classes"
|
||||
>
|
||||
<span
|
||||
v-if="prefixIcon || $slots.prefix"
|
||||
:class="iconClasses"
|
||||
class="justify-self-start"
|
||||
>
|
||||
<slot name="prefix">
|
||||
<component
|
||||
:is="prefixIcon"
|
||||
:class="prefixIconClass"
|
||||
/>
|
||||
</slot>
|
||||
</span>
|
||||
<span class="flex-grow">
|
||||
<slot />
|
||||
</span>
|
||||
<span
|
||||
v-if="suffixIcon || $slots.suffix"
|
||||
:class="iconClasses"
|
||||
class="justify-self-end"
|
||||
>
|
||||
<slot name="suffix">
|
||||
<component
|
||||
:is="suffixIcon"
|
||||
:class="suffixIconClass"
|
||||
/>
|
||||
</slot>
|
||||
</span>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default defineComponent({
|
||||
inheritAttrs: true,
|
||||
})
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, defineComponent, useAttrs, ButtonHTMLAttributes, FunctionalComponent, SVGAttributes } from 'vue'
|
||||
|
||||
const VariantClassesTable = {
|
||||
primary: 'border-indigo-600 bg-indigo-600 text-white',
|
||||
outline: 'border-gray-200 text-indigo-600 bg-white',
|
||||
link: 'border-transparent text-indigo-600',
|
||||
text: 'border-0',
|
||||
}
|
||||
|
||||
const SizeClassesTable = {
|
||||
sm: 'px-1 py-1 text-xs',
|
||||
md: 'px-2 py-1 text-sm',
|
||||
lg: 'px-4 py-2 text-sm',
|
||||
xl: 'px-6 py-3 text-lg',
|
||||
}
|
||||
|
||||
const IconClassesTable = {
|
||||
md: 'min-h-1.25em min-w-1.25em max-h-1.25em max-w-1.25em',
|
||||
lg: 'min-h-2em min-w-2em max-h-2em max-w-2em',
|
||||
xl: 'min-h-2.5em min-w-2.5em max-w-2.5em max-h-2.5em ',
|
||||
}
|
||||
|
||||
const props = defineProps<{
|
||||
prefixIcon?: FunctionalComponent<SVGAttributes>
|
||||
suffixIcon?: FunctionalComponent<SVGAttributes>
|
||||
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
||||
variant?: 'primary' | 'outline' | 'link' | 'text'
|
||||
prefixIconClass?: string
|
||||
suffixIconClass?: string
|
||||
}>()
|
||||
|
||||
const attrs = useAttrs() as ButtonHTMLAttributes
|
||||
|
||||
const variantClasses = VariantClassesTable[props.variant || 'primary']
|
||||
const sizeClasses = SizeClassesTable[props.size || 'md']
|
||||
|
||||
const iconClasses = ['flex', 'items-center', IconClassesTable[props.size || 'md']]
|
||||
|
||||
const classes = computed(() => {
|
||||
return [
|
||||
variantClasses,
|
||||
sizeClasses,
|
||||
attrs.class,
|
||||
attrs.disabled ? 'opacity-50' : '',
|
||||
]
|
||||
})
|
||||
</script>
|
||||
106
packages/app/src/components/input/Input.vue
Normal file
@@ -0,0 +1,106 @@
|
||||
<template>
|
||||
<div
|
||||
class="p-0 m-0 border-0 h-full"
|
||||
:class="$attrs.class"
|
||||
>
|
||||
<div class="relative rounded-md h-full">
|
||||
<div
|
||||
v-if="hasPrefix"
|
||||
class="absolute inset-y-0 left-0 pl-4 flex items-center"
|
||||
>
|
||||
<span class="text-gray-500 flex items-center justify-center">
|
||||
<slot name="prefix">
|
||||
<component
|
||||
:is="prefixIcon"
|
||||
v-if="prefixIcon"
|
||||
class="pointer-events-none"
|
||||
:class="prefixIconClasses"
|
||||
/>
|
||||
<IconMagnify
|
||||
v-else-if="type === 'search'"
|
||||
:class="prefixIconClasses"
|
||||
/>
|
||||
</slot>
|
||||
</span>
|
||||
</div>
|
||||
<input
|
||||
v-model="localValue"
|
||||
:type="type"
|
||||
:class="_inputClasses"
|
||||
class="h-full placeholder-gray-400 disabled:bg-gray-100 disabled:text-gray-400 leading-tight focus:ring-indigo-500 focus:border-indigo-500 block w-full pl-10 py-2 border-gray-300 rounded-md"
|
||||
v-bind="inputAttrs"
|
||||
>
|
||||
<div
|
||||
v-if="hasSuffix"
|
||||
class="absolute inset-y-0 right-0 pr-3 flex items-center"
|
||||
>
|
||||
<span class="text-gray-500 flex items-center justify-center">
|
||||
<slot name="suffix">
|
||||
<component
|
||||
:is="suffixIcon"
|
||||
class="pointer-events-none"
|
||||
:class="suffixIconClasses"
|
||||
/>
|
||||
</slot>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
inheritAttrs: false,
|
||||
}
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import _ from 'lodash'
|
||||
import IconMagnify from '~icons/cy/magnifying-glass_x16'
|
||||
import { computed, useSlots, useAttrs, InputHTMLAttributes, FunctionalComponent, SVGAttributes } from 'vue'
|
||||
import { useModelWrapper } from '../../composables'
|
||||
|
||||
const slots = useSlots()
|
||||
const attrs = useAttrs()
|
||||
|
||||
const inputAttrs = _.omit(attrs, 'class')
|
||||
|
||||
const props = withDefaults(defineProps<{
|
||||
type?: InputHTMLAttributes['type']
|
||||
inputClasses?: string | string[] | Record<string, string>
|
||||
prefixIcon?: FunctionalComponent<SVGAttributes, {}>
|
||||
prefixIconClasses?: string | string[] | Record<string, string>
|
||||
suffixIcon?: FunctionalComponent<SVGAttributes, {}>
|
||||
suffixIconClasses?: string | string[] | Record<string, string>
|
||||
modelValue?: string
|
||||
}>(), {
|
||||
type: 'text',
|
||||
modelValue: '',
|
||||
inputClasses: undefined,
|
||||
prefixIcon: undefined,
|
||||
prefixIconClasses: undefined,
|
||||
suffixIcon: undefined,
|
||||
suffixIconClasses: undefined,
|
||||
})
|
||||
|
||||
const emits = defineEmits(['update:modelValue'])
|
||||
|
||||
const localValue = useModelWrapper(props, emits, 'modelValue')
|
||||
|
||||
const hasPrefix = computed(() => {
|
||||
return !!(slots.prefix || props.prefixIcon || props.type === 'search')
|
||||
})
|
||||
|
||||
const hasSuffix = computed(() => {
|
||||
return !!(slots.suffix || props.suffixIcon)
|
||||
})
|
||||
|
||||
const _inputClasses = computed(() => {
|
||||
return ([
|
||||
props.inputClasses,
|
||||
hasPrefix.value ? 'pl-10' : 'pl-4',
|
||||
hasSuffix.value ? 'pr-6' : 'pr-0',
|
||||
])
|
||||
})
|
||||
|
||||
</script>
|
||||
24
packages/app/src/composables/index.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { computed } from 'vue'
|
||||
import { useI18n as _useI18n } from 'vue-i18n'
|
||||
import type { MessageSchema } from '@packages/frontend-shared/src/locales/schema'
|
||||
|
||||
/**
|
||||
* This snippet comes from Thorsten Lünborg and is explained in this blog post https://www.vuemastery.com/blog/vue-3-data-down-events-up/
|
||||
* @example const localValue = useModelWrapper(props, emit, 'modelValue')
|
||||
*/
|
||||
export function useModelWrapper<T, N extends string = 'modelValue'> (
|
||||
props: T,
|
||||
emit: (event: N, ...args: any[]) => void,
|
||||
name = 'modelValue',
|
||||
) {
|
||||
return computed({
|
||||
get: () => props[name],
|
||||
set: (value: any) => {
|
||||
emit(`update:${name}` as any, value)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function useI18n () {
|
||||
return _useI18n<{ message: MessageSchema }>({ useScope: 'global' })
|
||||
}
|
||||
30
packages/app/src/locales/en-US.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"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"
|
||||
},
|
||||
"specsPage": {
|
||||
"searchPlaceholder": "Search Specs",
|
||||
"newSpecButton": "New Spec",
|
||||
"componentSpecsHeader": "Component Specs",
|
||||
"gitStatusHeader": "Git Status"
|
||||
}
|
||||
}
|
||||
@@ -1,17 +1,17 @@
|
||||
<template>
|
||||
<div class="flex flex-col flex-1 min-h-0 bg-gray-800">
|
||||
<div class="flex flex-col flex-1 min-h-0 bg-gray-1000">
|
||||
<div class="flex flex-col flex-1 pt-5 pb-4 overflow-y-auto">
|
||||
<div class="flex items-center flex-shrink-0 px-4">
|
||||
<i-cy-bookmark_x24
|
||||
class="icon-dark-gray-300
|
||||
icon-light-gray-800
|
||||
class="icon-dark-gray-200
|
||||
icon-light-gray-900
|
||||
w-24px
|
||||
h-24px"
|
||||
/>
|
||||
<i-bi-bookmark-star class="text-white w-18px h-18px" />
|
||||
</div>
|
||||
<nav
|
||||
class="flex-1 px-2 mt-5 space-y-1 bg-gray-800"
|
||||
class="flex-1 px-2 mt-5 space-y-1 bg-gray-1000"
|
||||
aria-label="Sidebar"
|
||||
>
|
||||
<router-link
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<a
|
||||
href="#"
|
||||
:class="[active ? 'before:bg-green-300' : 'before:bg-transparent']"
|
||||
:class="[active ? 'before:bg-jade-300' : 'before:bg-transparent']"
|
||||
class="w-full
|
||||
min-w-40px
|
||||
relative
|
||||
@@ -33,11 +33,11 @@
|
||||
<component
|
||||
:is="icon"
|
||||
v-if="icon"
|
||||
:class="[active ? 'icon-dark-green-300 icon-light-green-800' : 'icon-dark-gray-500 icon-light-gray-800']"
|
||||
class="min-w-24px min-h-24px group-hover:icon-dark-indigo-300 group-hover:icon-light-indigo-900 group-focus:icon-dark-indigo-300 group-focus:icon-light-indigo-900"
|
||||
:class="[active ? 'icon-dark-jade-300 icon-light-jade-800' : 'icon-dark-gray-800 icon-light-gray-900']"
|
||||
class="min-w-24px min-h-24px group-hover:icon-dark-indigo-300 group-hover:icon-light-indigo-600 group-focus:icon-dark-indigo-300 group-focus:icon-light-indigo-600"
|
||||
/>
|
||||
<span
|
||||
:class="[active ? 'text-green-300' : 'text-gray-500']"
|
||||
:class="[active ? 'text-jade-300' : 'text-gray-400']"
|
||||
class="truncate"
|
||||
>
|
||||
<slot />
|
||||
|
||||
35
packages/app/src/pages/Runner/[...all].vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>Runs Page</h2>
|
||||
<h4 v-if="!ready">
|
||||
Loading
|
||||
</h4>
|
||||
<h4 v-else>
|
||||
Error: TODO add gql backend for getting the base64Config into the browser
|
||||
</h4>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { renderRunner } from '../../runner/renderRunner'
|
||||
|
||||
const ready = ref(false)
|
||||
|
||||
// @ts-ignore
|
||||
window.__Cypress__ = true
|
||||
|
||||
renderRunner(() => {
|
||||
setTimeout(function () {
|
||||
// @ts-ignore
|
||||
window.Runner.start(document.getElementById('app'), '{{base64Config | safe}}')
|
||||
}, 0)
|
||||
|
||||
ready.value = true
|
||||
})
|
||||
</script>
|
||||
<route>
|
||||
{
|
||||
name: "Runner"
|
||||
}
|
||||
</route>
|
||||
@@ -1,9 +1,34 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2>Specs Page</h2>
|
||||
<template v-if="query.data.value?.app">
|
||||
<SpecsList :gql="query.data.value?.app" />
|
||||
</template>
|
||||
<p v-else>
|
||||
Loading...
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { gql } from '@urql/core'
|
||||
import { useQuery } from '@urql/vue'
|
||||
import { Specs_AppDocument } from '../generated/graphql'
|
||||
import SpecsList from '../specs/SpecsList.vue'
|
||||
|
||||
gql`
|
||||
query Specs_App {
|
||||
app {
|
||||
...SpecsList
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const query = useQuery({
|
||||
query: Specs_AppDocument,
|
||||
})
|
||||
|
||||
</script>
|
||||
<route>
|
||||
{
|
||||
name: "Specs Page"
|
||||
|
||||
11
packages/app/src/specs/SpecListHeader.spec.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import SpecsListHeader from './SpecsListHeader.vue'
|
||||
|
||||
describe('<SpecsListHeader />', () => {
|
||||
beforeEach(() => {
|
||||
cy.mount(() => (
|
||||
<div class="py-4 px-8">
|
||||
<SpecsListHeader modelValue='' />
|
||||
</div>
|
||||
))
|
||||
})
|
||||
})
|
||||
68
packages/app/src/specs/SpecsList.spec.tsx
Normal file
@@ -0,0 +1,68 @@
|
||||
import SpecsList from './SpecsList.vue'
|
||||
import { SpecsListFragmentDoc, SpecListRowFragment } from '../generated/graphql-test'
|
||||
import { defaultMessages } from '@cy/i18n'
|
||||
|
||||
const rowSelector = '[data-testid=specs-list-row]'
|
||||
const inputSelector = 'input'
|
||||
const fullFile = (s) => `${s.node.fileName}${s.node.specFileExtension}${s.node.fileExtension}`
|
||||
const hasSpecText = (_node: JQuery<HTMLElement>, spec: SpecListRowFragment) => {
|
||||
const $node = _node as JQuery<HTMLDivElement>
|
||||
|
||||
expect($node).to.contain(spec.node.fileName)
|
||||
expect($node).to.contain(spec.node.fileExtension)
|
||||
expect($node).to.contain(spec.node.gitInfo?.author)
|
||||
expect($node).to.contain(defaultMessages.file.git.modified)
|
||||
|
||||
return $node
|
||||
}
|
||||
|
||||
let specs: Array<SpecListRowFragment> = []
|
||||
|
||||
describe('<SpecsList />', { keystrokeDelay: 0 }, () => {
|
||||
beforeEach(() => {
|
||||
cy.mountFragment(SpecsListFragmentDoc, {
|
||||
onResult: (ctx) => {
|
||||
specs = ctx.activeProject?.specs?.edges || []
|
||||
|
||||
return ctx
|
||||
},
|
||||
render: (gqlVal) => {
|
||||
return <SpecsList gql={gqlVal} />
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
it('renders specs', () => {
|
||||
cy.get(rowSelector).first()
|
||||
.should(($node) => hasSpecText($node, specs[0]))
|
||||
})
|
||||
|
||||
it('filters the specs', () => {
|
||||
cy.get(rowSelector).first()
|
||||
// Establish a baseline for what the spec rendered is
|
||||
.should(($node) => hasSpecText($node, specs[0]))
|
||||
.should('be.visible')
|
||||
|
||||
// Cause an empty spec state
|
||||
.get(inputSelector).type('garbage 🗑', { delay: 0 })
|
||||
.get(rowSelector)
|
||||
.should('not.exist')
|
||||
|
||||
// Clear the input, make sure that the right spec is showing up
|
||||
.get(inputSelector)
|
||||
.type('{selectall}{backspace}', { delay: 0 })
|
||||
|
||||
// Check the spec and its values
|
||||
.get(rowSelector).first()
|
||||
.should('be.visible')
|
||||
.should(($node) => hasSpecText($node, specs[0]))
|
||||
.get(inputSelector)
|
||||
.type(fullFile(specs[0]), { delay: 0 })
|
||||
.get(rowSelector).first()
|
||||
.should('contain.text', specs[0].node.fileName)
|
||||
.and('contain.text', specs[0].node.fileExtension)
|
||||
.click()
|
||||
.url()
|
||||
.should('contain', fullFile(specs[0]))
|
||||
})
|
||||
})
|
||||
73
packages/app/src/specs/SpecsList.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<template>
|
||||
<div class="p-24px">
|
||||
<SpecsListHeader
|
||||
v-model="search"
|
||||
class="pb-32px"
|
||||
/>
|
||||
<div class="grid items-center divide-y-1 children:h-40px">
|
||||
<div class="grid grid-cols-2 children:text-gray-800 children:font-medium">
|
||||
<div>{{ t('specPage.componentSpecsHeader') }}</div>
|
||||
<div>{{ t('specPage.gitStatusHeader') }}</div>
|
||||
</div>
|
||||
<router-link
|
||||
v-for="spec in filteredSpecs"
|
||||
v-slot="{ navigate }"
|
||||
:key="spec.node.id"
|
||||
:to="path(spec)"
|
||||
custom
|
||||
>
|
||||
<SpecsListRow
|
||||
:gql="spec"
|
||||
@click="navigate"
|
||||
@keypress.enter="navigate"
|
||||
/>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SpecsListHeader from './SpecsListHeader.vue'
|
||||
import SpecsListRow from './SpecsListRow.vue'
|
||||
import { gql } from '@urql/vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import type { SpecsListFragment } from '../generated/graphql'
|
||||
import { useI18n } from '@cy/i18n'
|
||||
|
||||
const { t } = useI18n()
|
||||
const path = (spec) => `/runner/tests/${spec.node.specType}/${spec.node.name}${spec.node.fileExtension}`
|
||||
|
||||
gql`
|
||||
fragment SpecsList on App {
|
||||
activeProject {
|
||||
id
|
||||
projectRoot
|
||||
specs(first: 1) {
|
||||
edges {
|
||||
node {
|
||||
name
|
||||
specType
|
||||
relative
|
||||
}
|
||||
...SpecListRow
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const props = defineProps<{
|
||||
gql: SpecsListFragment
|
||||
}>()
|
||||
|
||||
const search = ref('')
|
||||
const specs = computed(() => props.gql.activeProject?.specs?.edges)
|
||||
|
||||
// If this search becomes any more complex, push it into the server
|
||||
const sortByGitStatus = (a, b) => a.node.gitInfo ? 1 : -1
|
||||
const filteredSpecs = computed(() => {
|
||||
return specs.value?.filter((s) => {
|
||||
return s.node.relative.toLowerCase().includes(search.value.toLowerCase())
|
||||
})?.sort(sortByGitStatus)
|
||||
})
|
||||
</script>
|
||||
33
packages/app/src/specs/SpecsListHeader.spec.tsx
Normal file
@@ -0,0 +1,33 @@
|
||||
import SpecsListHeader from './SpecsListHeader.vue'
|
||||
import { ref } from 'vue'
|
||||
|
||||
const buttonSelector = '[data-testid=new-spec-button]'
|
||||
const inputSelector = 'input[type=search]'
|
||||
|
||||
describe('<SpecsListHeader />', { keystrokeDelay: 0 }, () => {
|
||||
it('can be searched', () => {
|
||||
const search = ref('')
|
||||
const searchString = 'my/component.cy.tsx'
|
||||
|
||||
cy.mount(<SpecsListHeader modelValue={search.value} />)
|
||||
.get(inputSelector)
|
||||
.type(searchString, { delay: 0 })
|
||||
.should(() => {
|
||||
expect(search.value).to.equal(searchString)
|
||||
})
|
||||
})
|
||||
|
||||
it('emits a new spec event', () => {
|
||||
const onNewSpec = cy.spy().as('new-spec')
|
||||
const search = ref('')
|
||||
|
||||
cy.mount(<SpecsListHeader
|
||||
modelValue={search.value}
|
||||
onNewSpec={onNewSpec}
|
||||
/>)
|
||||
.get(buttonSelector)
|
||||
.click()
|
||||
.get('@new-spec')
|
||||
.should('have.been.called')
|
||||
})
|
||||
})
|
||||
51
packages/app/src/specs/SpecsListHeader.vue
Normal file
@@ -0,0 +1,51 @@
|
||||
<template>
|
||||
<div class="flex w-full gap-16px">
|
||||
<Input
|
||||
type="search"
|
||||
class="flex-grow h-full min-w-200px"
|
||||
prefix-icon-classes="icon-light-gray-50 icon-dark-gray-500"
|
||||
:prefix-icon="IconMagnifyingGlass"
|
||||
:model-value="inputValue"
|
||||
:placeholder="t('specPage.searchPlaceholder')"
|
||||
@input="onInput"
|
||||
/>
|
||||
|
||||
<div class="flex h-40px gap-16px min-w-127px">
|
||||
<Button
|
||||
data-testid="new-spec-button"
|
||||
:prefix-icon="IconAdd"
|
||||
prefix-icon-class="justify-center text-lg text-center icon-light-transparent icon-dark-white"
|
||||
class="min-w-127px text-size-16px focus-within:ring-2 focus-within:ring-offset-2 focus-within:ring-indigo-500"
|
||||
@click="$emit('newSpec')"
|
||||
>
|
||||
{{ t('specPage.newSpecButton') }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { useI18n } from '@cy/i18n'
|
||||
import Button from '@cy/components/Button.vue'
|
||||
import Input from '@cy/components/Input.vue'
|
||||
import IconMagnifyingGlass from '~icons/cy/magnifying-glass_x16'
|
||||
import IconAdd from '~icons/cy/add-large_x16'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
const props = defineProps<{
|
||||
modelValue: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: string): void,
|
||||
(e: 'newSpec'): void
|
||||
}>()
|
||||
|
||||
const inputValue = useVModel(props, 'modelValue', emit)
|
||||
|
||||
const onInput = (e) => {
|
||||
inputValue.value = (e as Event & { target: HTMLInputElement | null }).target?.value || ''
|
||||
}
|
||||
</script>
|
||||
129
packages/app/src/specs/SpecsListRow.vue
Normal file
@@ -0,0 +1,129 @@
|
||||
<template>
|
||||
<div
|
||||
class="grid grid-cols-2 outline-none children:cursor-pointer group"
|
||||
data-testid="specs-list-row"
|
||||
role="link"
|
||||
tabindex="0"
|
||||
>
|
||||
<div class="grid grid-cols-[16px,auto,auto] items-center gap-10px">
|
||||
<component
|
||||
:is="icon.component"
|
||||
:class="icon.classes"
|
||||
/>
|
||||
<div>
|
||||
<span class="font-medium text-gray-700 group-hocus:text-indigo-500">{{ spec.fileName }}</span>
|
||||
<span class="font-light text-gray-400 group-hocus:text-indigo-500">{{ spec.specFileExtension + spec.fileExtension }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid git-info-row grid-cols-[16px,auto] items-center gap-9px">
|
||||
<span class="flex items-center justify-center w-16px">
|
||||
<span
|
||||
v-if="fileState !== 'unmodified'"
|
||||
class="rounded-full min-w-6px max-w-6px min-h-6px max-h-6px border-1"
|
||||
:class="classes?.indicator"
|
||||
/>
|
||||
<IconGithub
|
||||
v-else
|
||||
class="min-w-16px max-w-16px min-h-16px icon-dark-gray-300 group-hocus:icon-dark-indigo-500 max-h-16px"
|
||||
/>
|
||||
</span>
|
||||
<div :class="classes?.gitText">
|
||||
{{ gitInfoText }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { gql } from '@urql/core'
|
||||
import type { SpecListRowFragment } from '../generated/graphql'
|
||||
import { computed } from 'vue'
|
||||
import { useTimeAgo } from '@vueuse/core'
|
||||
import { useI18n } from '@cy/i18n'
|
||||
import DocumentIconBlank from '~icons/cy/document-blank_x16'
|
||||
import DocumentIconPlus from '~icons/cy/document-plus_x16'
|
||||
import DocumentIconPlusMinus from '~icons/cy/document-plus-minus_x16'
|
||||
import DocumentIconMinus from '~icons/cy/document-minus_x16'
|
||||
import IconGithub from '~icons/cy/github'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
gql`
|
||||
fragment SpecListRow on SpecEdge {
|
||||
node {
|
||||
id
|
||||
specFileExtension
|
||||
fileExtension
|
||||
fileName
|
||||
gitInfo {
|
||||
lastModifiedTimestamp
|
||||
author
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const props = defineProps<{
|
||||
gql: SpecListRowFragment
|
||||
}>()
|
||||
|
||||
const spec = computed(() => props.gql.node)
|
||||
const timeAgo = useTimeAgo(spec.value.gitInfo?.lastModifiedTimestamp || '')
|
||||
|
||||
// TODO: File state needs to come from git,
|
||||
// but the data context doesn't contain this info yet
|
||||
const fileState = computed(() => spec.value.gitInfo ? 'unmodified' : 'modified')
|
||||
|
||||
const classes = computed(() => {
|
||||
return {
|
||||
created: {
|
||||
indicator: 'border-jade-400 bg-jade-300',
|
||||
gitText: 'text-jade-500',
|
||||
icon: DocumentIconPlus,
|
||||
iconClasses: 'icon-dark-jade-400 icon-light-jade-50',
|
||||
},
|
||||
modified: {
|
||||
indicator: 'border-orange-400 bg-orange-300',
|
||||
gitText: 'text-orange-500',
|
||||
icon: DocumentIconPlusMinus,
|
||||
iconClasses: 'icon-dark-orange-400 icon-light-orange-50',
|
||||
},
|
||||
unmodified: {
|
||||
indicator: 'border-transparent bg-transparent',
|
||||
gitText: 'text-gray-600 group-hocus:text-indigo-500',
|
||||
},
|
||||
deleted: {
|
||||
indicator: 'border-red-400 bg-red-300',
|
||||
gitText: 'text-red-500',
|
||||
iconClasses: 'icon-dark-red-400 icon-light-red-50',
|
||||
icon: DocumentIconMinus,
|
||||
},
|
||||
}[fileState.value]
|
||||
})
|
||||
|
||||
const icon = computed(() => {
|
||||
return {
|
||||
component: classes.value?.icon || DocumentIconBlank,
|
||||
classes: classes.value?.iconClasses || 'icon-light-gray-50 icon-dark-gray-200',
|
||||
}
|
||||
})
|
||||
|
||||
const gitInfoText = computed(() => {
|
||||
if (fileState.value === 'unmodified') {
|
||||
// Modified x days ago by AuthorName
|
||||
return t('specPage.rows.gitInfoWithAuthor', {
|
||||
fileState: t('file.git.modified'),
|
||||
timeAgo: timeAgo.value,
|
||||
author: spec.value.gitInfo?.author,
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: implement the backend for git to report this info
|
||||
// Created|Deleted|Modified x days ago by AuthorName
|
||||
return t('specPage.rows.gitInfo', {
|
||||
fileState: t(`file.git.${fileState.value}`),
|
||||
timeAgo: timeAgo.value,
|
||||
})
|
||||
})
|
||||
|
||||
</script>
|
||||
@@ -1,3 +1,4 @@
|
||||
import WindiConfig from '@packages/frontend-shared/windi.config'
|
||||
import { defaultConfig } from '@packages/frontend-shared/windi.config'
|
||||
import { defineConfig } from 'windicss/helpers'
|
||||
|
||||
export default WindiConfig
|
||||
export default defineConfig(defaultConfig)
|
||||
|
||||
@@ -55,7 +55,7 @@ export class ProjectActions {
|
||||
return this
|
||||
}
|
||||
|
||||
async findSpecs (projectRoot: string, specType: Maybe<SpecType>) {
|
||||
async findSpecs (projectRoot: string, specType: Maybe<SpecType>): Promise<FoundSpec[]> {
|
||||
const config = await this.ctx.loaders.projectConfig(projectRoot)
|
||||
const specs = await this.api.findSpecs({
|
||||
projectRoot,
|
||||
@@ -63,7 +63,7 @@ export class ProjectActions {
|
||||
supportFile: config.supportFile ?? false,
|
||||
testFiles: config.testFiles ?? [],
|
||||
ignoreTestFiles: config.ignoreTestFiles as string[] ?? [],
|
||||
componentFolder: config.componentFolder ?? false,
|
||||
componentFolder: config.projectRoot ?? false,
|
||||
integrationFolder: config.integrationFolder ?? '',
|
||||
})
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ function addIconUtilityClasses (theme) {
|
||||
// And the selectors and values affected are values
|
||||
/**
|
||||
* {
|
||||
* `.icon-light-green-500`: {
|
||||
* `.icon-light-jade-500`: {
|
||||
* '> *[stroke].icon-light': {
|
||||
* stroke: resolvedColor
|
||||
* },
|
||||
|
||||
@@ -12,7 +12,12 @@ const colorSafelist = reduce(colors, (acc, variants, colorName) => {
|
||||
|
||||
return `${acc}
|
||||
${map(variants, (_: string, k: string) => {
|
||||
return `bg-${name}-${k}
|
||||
if (k === 'DEFAULT') return ``
|
||||
|
||||
return `
|
||||
icon-light-${name}-${k}
|
||||
icon-dark-${name}-${k}
|
||||
bg-${name}-${k}
|
||||
text-${name}-${k}
|
||||
before:bg-${name}-${k}
|
||||
before:text-${name}-${k}`
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import _ from 'lodash'
|
||||
import { randomComponents } from '../../../src/graphql/specs/testStubSpecs'
|
||||
|
||||
import type {
|
||||
Project,
|
||||
@@ -9,6 +10,7 @@ import { MaybeResolver, testNodeId } from './clientTestUtils'
|
||||
export const createTestProject = (title: string): CodegenTypeMap['Project'] => {
|
||||
const snakeTitle = _.kebabCase(title)
|
||||
|
||||
// TODO: What a mess, type this without all the hacks
|
||||
return {
|
||||
...testNodeId('Project'),
|
||||
isFirstTimeCT: true,
|
||||
@@ -16,6 +18,27 @@ export const createTestProject = (title: string): CodegenTypeMap['Project'] => {
|
||||
projectId: `${snakeTitle}-id`,
|
||||
title,
|
||||
projectRoot: `/usr/local/dev/projects/${snakeTitle}`,
|
||||
specs: {
|
||||
pageInfo: {
|
||||
__typename: 'PageInfo',
|
||||
hasNextPage: true,
|
||||
hasPreviousPage: false,
|
||||
},
|
||||
__typename: 'SpecConnection' as const,
|
||||
edges: [
|
||||
...randomComponents(200).map((c) => {
|
||||
return {
|
||||
__typename: 'SpecEdge' as const,
|
||||
cursor: 'eoifjew',
|
||||
node: {
|
||||
id: c.absolute,
|
||||
__typename: 'Spec' as const,
|
||||
...c,
|
||||
},
|
||||
}
|
||||
}),
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 8H8M14 8H8M8 8V2M8 8V14" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-dark"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 241 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 3V13M13 8H3" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-dark"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 229 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M8 4V12M12 8H4" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-dark"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 229 B |
3
packages/frontend-shared/src/assets/icons/add.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 1V7M7 4H1" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-dark"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 223 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 9L8 13M8 13L12 9M8 13V3" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 241 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7 4L3 8M3 8L7 12M3 8L13 8" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 241 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9 12L13 8M13 8L9 4M13 8L3 8" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 243 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.9999 6.99994L7.99994 2.99994M7.99994 2.99994L3.99994 6.99994M7.99994 2.99994L7.99994 12.9999" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 311 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M6 10L6.5 9M10 10L9.5 9M6.5 9L8 6L9.5 9M6.5 9H9.5M14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 705 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 14V2C2 1.44772 2.44772 1 3 1H13C13.5523 1 14 1.44772 14 2V14C14 14.5523 13.5523 15 13 15H3C2.44772 15 2 14.5523 2 14Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M5 8H8M5 5H11M5 11H10M13 1L3 1C2.44772 1 2 1.44772 2 2V14C2 14.5523 2.44772 15 3 15H13C13.5523 15 14 14.5523 14 14V2C14 1.44772 13.5523 1 13 1Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 525 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 20V4C4 2.89543 4.89543 2 6 2H14L20 8V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M14 2H6C4.89543 2 4 2.89543 4 4V20C4 21.1046 4.89543 22 6 22H18C19.1046 22 20 21.1046 20 20V8M14 2L20 8M14 2V8H20" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 456 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 39V9C10 8.44772 10.4477 8 11 8H37C37.5523 8 38 8.44772 38 9V39C38 39.5523 37.5523 40 37 40H11C10.4477 40 10 39.5523 10 39Z" class="icon-light" fill="#D0D2E0"/>
|
||||
<path d="M17 24H24M17 17.1429H31M17 30.8571H28.6667M37 8L11 8C10.4477 8 10 8.44772 10 9V39C10 39.5523 10.4477 40 11 40H37C37.5523 40 38 39.5523 38 39V9C38 8.44772 37.5523 8 37 8Z" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 539 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13Z" fill="#D0D2E0" stroke="#1B1E2E" class="icon-dark-stroke icon-light-fill" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 447 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M8 5V11M8 11L10 9M8 11L6 9M14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843Z" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 664 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20Z" class="icon-light" fill="#D0D2E0"/>
|
||||
<path d="M12 16V8M12 16L15 13M12 16L9 13M20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264Z" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-dark"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 687 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 15C2.89543 15 2 14.1046 2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843V13C14 14.1046 13.1046 15 12 15H4Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M6 8H10M14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843Z" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-dark"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 663 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M15 12H9M20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264Z" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-dark"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 664 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M5 10L6 6L8 9L10 6L11 10M14 4.82843V13C14 14.1046 13.1046 15 12 15H4C2.89543 15 2 14.1046 2 13V3C2 1.89543 2.89543 1 4 1H10.1716C10.702 1 11.2107 1.21071 11.5858 1.58579L13.4142 3.41421C13.7893 3.78929 14 4.29799 14 4.82843Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 680 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 15C2.44772 15 2 14.5523 2 14V2C2 1.44772 2.44772 1 3 1L13 1C13.5523 1 14 1.44772 14 2V14C14 14.5523 13.5523 15 13 15H3Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M6 6.5H10M8 8.5V4.5M6 11.5H10M13 1L3 1C2.44772 1 2 1.44772 2 2V14C2 14.5523 2.44772 15 3 15H13C13.5523 15 14 14.5523 14 14V2C14 1.44772 13.5523 1 13 1Z" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-dark"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 535 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M12 13V10M12 7V10M12 10H15M12 10H9M9 17H15M20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264Z" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-dark"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 698 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 15C2.44772 15 2 14.5523 2 14V2C2 1.44772 2.44772 1 3 1H13C13.5523 1 14 1.44772 14 2V14C14 14.5523 13.5523 15 13 15H3Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M6 8H10M8 10V6M13 1H3C2.44772 1 2 1.44772 2 2V14C2 14.5523 2.44772 15 3 15H13C13.5523 15 14 14.5523 14 14V2C14 1.44772 13.5523 1 13 1Z" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-dark"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 516 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M12 15V12M12 9V12M12 12H15M12 12H9M20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264Z" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-dark"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 690 B |
@@ -0,0 +1,6 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4 1H17C18.6569 1 20 2.34315 20 4V19M4 1H3C1.89543 1 1 1.89543 1 3V3C1 4.10457 1.89543 5 3 5H4M4 1V5M11 6H16M11 10H16M11 14H16M4 5V20C4 21.6569 5.34315 23 7 23V23M20 19H21C22.1046 19 23 19.8954 23 21V21C23 22.1046 22.1046 23 21 23H20H7M20 19H7V19C8.10457 20.1046 8.10457 21.8954 7 23V23" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9 6C9 6.55228 8.55228 7 8 7C7.44772 7 7 6.55228 7 6C7 5.44772 7.44772 5 8 5C8.55228 5 9 5.44772 9 6Z" fill="#1B1E2E" class="icon-dark"/>
|
||||
<path d="M9 10C9 10.5523 8.55228 11 8 11C7.44772 11 7 10.5523 7 10C7 9.44772 7.44772 9 8 9C8.55228 9 9 9.44772 9 10Z" fill="#1B1E2E" class="icon-dark"/>
|
||||
<path d="M9 14C9 14.5523 8.55228 15 8 15C7.44772 15 7 14.5523 7 14C7 13.4477 7.44772 13 8 13C8.55228 13 9 13.4477 9 14Z" fill="#1B1E2E" class="icon-dark"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 957 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M10 1C9.73481 1.00006 9.48049 1.10545 9.293 1.293L3.293 7.293C3.10545 7.48049 3.00006 7.73481 3 8V20C3 20.7956 3.31607 21.5587 3.87868 22.1213C4.44129 22.6839 5.20435 23 6 23H7C7.26522 23 7.51957 22.8946 7.70711 22.7071C7.89464 22.5196 8 22.2652 8 22C8 21.7348 7.89464 21.4804 7.70711 21.2929C7.51957 21.1054 7.26522 21 7 21H6C5.73478 21 5.48043 20.8946 5.29289 20.7071C5.10536 20.5196 5 20.2652 5 20V9H10C10.2652 9 10.5196 8.89464 10.7071 8.70711C10.8946 8.51957 11 8.26522 11 8V3H18C18.2652 3 18.5196 3.10536 18.7071 3.29289C18.8946 3.48043 19 3.73478 19 4V9C19 9.26522 19.1054 9.51957 19.2929 9.70711C19.4804 9.89464 19.7348 10 20 10C20.2652 10 20.5196 9.89464 20.7071 9.70711C20.8946 9.51957 21 9.26522 21 9V4C21 3.20435 20.6839 2.44129 20.1213 1.87868C19.5587 1.31607 18.7956 1 18 1H10ZM9 7H6.414L9 4.414V7ZM11 12C10.7348 12 10.4804 12.1054 10.2929 12.2929C10.1054 12.4804 10 12.7348 10 13V21C10 21.2652 10.1054 21.5196 10.2929 21.7071C10.4804 21.8946 10.7348 22 11 22H21C21.2652 22 21.5196 21.8946 21.7071 21.7071C21.8946 21.5196 22 21.2652 22 21V13C22 12.7348 21.8946 12.4804 21.7071 12.2929C21.5196 12.1054 21.2652 12 21 12H11ZM12 16V14H14V16H12ZM16 16V14H20V16H16ZM16 20V18H20V20H16ZM14 18V20H12V18H14Z" class="icon-dark" fill="#1B1E2E"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 15C2.44772 15 2 14.5523 2 14V2C2 1.44772 2.44772 1 3 1H13C13.5523 1 14 1.44772 14 2V14C14 14.5523 13.5523 15 13 15H3Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M8.00001 5.75001L8.00133 7.99819M8.00133 7.99819L10.1399 7.30472M8.00133 7.99819L9.32253 9.8203M8.00133 7.99819L6.67749 9.8203M8.00133 7.99819L5.86013 7.30472M13 1H3C2.44772 1 2 1.44772 2 2V14C2 14.5523 2.44772 15 3 15H13C13.5523 15 14 14.5523 14 14V2C14 1.44772 13.5523 1 13 1Z" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 660 B |
@@ -0,0 +1,4 @@
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 22C4.89543 22 4 21.1046 4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264V20C20 21.1046 19.1046 22 18 22H6Z" fill="#D0D2E0" class="icon-light"/>
|
||||
<path d="M12 8.84375V12.0032M12 12.0032L15.0018 11.0247M12 12.0032L13.8552 14.5535M12 12.0032L10.1448 14.5535M12 12.0032L8.99823 11.0247M20 9.24264V20C20 21.1046 19.1046 22 18 22H6C4.89543 22 4 21.1046 4 20V4C4 2.89543 4.89543 2 6 2H12.7574C13.553 2 14.3161 2.31607 14.8787 2.87868L19.1213 7.12132C19.6839 7.68393 20 8.44699 20 9.24264Z" stroke="#1B1E2E" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon-dark"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 783 B |
3
packages/frontend-shared/src/assets/icons/github.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.99974 1.00236C4.13453 1.00236 1 4.13637 1 8.00208C1 11.095 3.00546 13.718 5.78682 14.644C6.13691 14.7088 6.26557 14.4918 6.26557 14.3068C6.26557 14.1399 6.2586 13.5885 6.25575 13.0041C4.30818 13.4276 3.89763 12.1778 3.89763 12.1778C3.5793 11.3686 3.12043 11.1534 3.12043 11.1534C2.48536 10.7186 3.16875 10.7281 3.16875 10.7281C3.87151 10.7772 4.2415 11.449 4.2415 11.449C4.86625 12.5192 5.87957 12.2094 6.27874 12.0308C6.34179 11.5784 6.52265 11.2694 6.72313 11.0945C5.16826 10.918 3.53382 10.3176 3.53382 7.63519C3.53382 6.87118 3.8077 6.24646 4.25493 5.75657C4.18209 5.57986 3.94232 4.86831 4.32238 3.90432C4.32238 3.90432 4.91016 3.71598 6.24801 4.62182C6.80608 4.46706 7.40472 4.38903 7.99923 4.38645C8.59423 4.38903 9.19392 4.46679 9.75278 4.62182C11.0888 3.7165 11.6761 3.90432 11.6761 3.90432C12.0567 4.86857 11.8179 5.58063 11.7451 5.75659C12.1939 6.24646 12.4654 6.87118 12.4654 7.63519C12.4654 10.3238 10.8273 10.9149 9.2691 11.0883C9.52025 11.3053 9.74451 11.7314 9.74451 12.384C9.74451 13.3201 9.7365 14.0745 9.7365 14.3047C9.7365 14.491 9.86259 14.7088 10.2176 14.6406C12.9974 13.7141 15.0003 11.0909 15.0003 7.99974C15.0003 4.13453 11.8663 1 8.00026 1L7.99976 1.00234L7.99974 1.00236Z" fill="black" class="icon-dark"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 7C12 8.38071 11.4404 9.63071 10.5355 10.5355C9.63071 11.4404 8.38071 12 7 12C4.23858 12 2 9.76142 2 7C2 4.23858 4.23858 2 7 2C9.76142 2 12 4.23858 12 7Z" class="icon-light" fill="#D0D2E0"/>
|
||||
<path d="M10.5355 10.5355C11.4404 9.63071 12 8.38071 12 7C12 4.23858 9.76142 2 7 2C4.23858 2 2 4.23858 2 7C2 9.76142 4.23858 12 7 12C8.38071 12 9.63071 11.4404 10.5355 10.5355ZM10.5355 10.5355L14 14" stroke="#1B1E2E" class="icon-dark" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 607 B |
@@ -9,8 +9,8 @@
|
||||
class="justify-self-start flex items-center"
|
||||
>
|
||||
<slot name="prefix">
|
||||
<Icon
|
||||
:icon="prefixIcon"
|
||||
<component
|
||||
:is="prefixIcon"
|
||||
:class="prefixIconClass"
|
||||
/>
|
||||
</slot>
|
||||
@@ -23,8 +23,8 @@
|
||||
class="justify-self-start flex items-center"
|
||||
>
|
||||
<slot name="suffix">
|
||||
<Icon
|
||||
:icon="suffixIcon"
|
||||
<component
|
||||
:is="suffixIcon"
|
||||
:class="suffixIconClass"
|
||||
/>
|
||||
</slot>
|
||||
@@ -41,7 +41,6 @@ export default defineComponent({
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import Icon from './Icon.vue'
|
||||
|
||||
// eslint-disable-next-line no-duplicate-imports
|
||||
import { computed, useAttrs } from 'vue'
|
||||
|
||||
@@ -6,20 +6,17 @@
|
||||
<div class="relative rounded-md">
|
||||
<div
|
||||
v-if="hasPrefix"
|
||||
class="absolute inset-y-0 left-0 pl-4 flex items-center"
|
||||
class="absolute inset-y-0 left-0 flex items-center pl-4"
|
||||
>
|
||||
<span class="text-gray-500 flex items-center justify-center">
|
||||
<span class="flex items-center justify-center text-gray-500">
|
||||
<slot name="prefix">
|
||||
<Icon
|
||||
<component
|
||||
:is="prefixIcon"
|
||||
v-if="prefixIcon"
|
||||
class="pointer-events-none"
|
||||
:icon="prefixIcon"
|
||||
:class="prefixIconClasses"
|
||||
/>
|
||||
<Icon
|
||||
v-else-if="type === 'search'"
|
||||
:icon="IconSearch"
|
||||
/>
|
||||
<i-cy-magnifying-glass_x16 v-else-if="type === 'search'" />
|
||||
</slot>
|
||||
</span>
|
||||
</div>
|
||||
@@ -27,17 +24,18 @@
|
||||
v-model="localValue"
|
||||
:type="type"
|
||||
:class="_inputClasses"
|
||||
class="placeholder-gray-400 disabled:bg-gray-100 disabled:text-gray-400 leading-tight focus:ring-indigo-500 focus:border-indigo-500 block w-full pl-10 py-2 border-gray-300 rounded-md"
|
||||
class="block w-full pl-10 leading-tight placeholder-gray-400 border-gray-300 rounded-md disabled:bg-gray-100 disabled:text-gray-400 focus:ring-indigo-500 focus:border-indigo-500 py-9px"
|
||||
v-bind="inputAttrs"
|
||||
>
|
||||
<div
|
||||
v-if="hasSuffix"
|
||||
class="absolute inset-y-0 right-0 pr-3 flex items-center"
|
||||
class="absolute inset-y-0 right-0 flex items-center pr-3"
|
||||
>
|
||||
<span class="text-gray-500 flex items-center justify-center">
|
||||
<span class="flex items-center justify-center text-gray-500">
|
||||
<slot name="suffix">
|
||||
<Icon
|
||||
:icon="suffixIcon"
|
||||
<component
|
||||
:is="suffixIcon"
|
||||
v-if="suffixIcon"
|
||||
class="pointer-events-none"
|
||||
:class="suffixIconClasses"
|
||||
/>
|
||||
@@ -56,8 +54,6 @@ export default {
|
||||
|
||||
<script lang="ts" setup>
|
||||
import _ from 'lodash'
|
||||
import Icon from './Icon.vue'
|
||||
import IconSearch from '~icons/mdi/magnify'
|
||||
|
||||
import type { InputHTMLAttributes, FunctionalComponent, SVGAttributes } from 'vue'
|
||||
// eslint-disable-next-line no-duplicate-imports
|
||||
|
||||
@@ -17,7 +17,7 @@ import { computed } from 'vue'
|
||||
export type StatusIndicatorType = 'success' | 'warning' | 'error' | 'disabled'
|
||||
|
||||
const typeClasses: Record<StatusIndicatorType, string> = {
|
||||
success: 'text-green-600',
|
||||
success: 'text-jade-600',
|
||||
error: 'text-red-600',
|
||||
warning: 'text-amber-600',
|
||||
disabled: 'text-cool-gray-400',
|
||||
|
||||
162
packages/frontend-shared/src/graphql/specs/testStubSpecs.ts
Normal file
@@ -0,0 +1,162 @@
|
||||
import * as JustMyLuck from 'just-my-luck'
|
||||
import faker from 'faker'
|
||||
import { template, keys, reduce, templateSettings } from 'lodash'
|
||||
import combineProperties from 'combine-properties'
|
||||
import type { FoundSpec } from '@packages/types'
|
||||
|
||||
templateSettings.interpolate = /{{([\s\S]+?)}}/g
|
||||
|
||||
let jml
|
||||
const setupSeeds = () => {
|
||||
const seed = 2
|
||||
|
||||
faker.seed(seed)
|
||||
jml = new JustMyLuck(JustMyLuck.MersenneTwister(seed))
|
||||
}
|
||||
|
||||
setupSeeds()
|
||||
|
||||
// TODO BEFORE MERGE, REMOVE
|
||||
beforeEach(() => setupSeeds)
|
||||
|
||||
/**
|
||||
* Component Naming Fixtures
|
||||
*/
|
||||
export const modifiers = [
|
||||
'Async',
|
||||
'Dynamic',
|
||||
'Static',
|
||||
'Virtual',
|
||||
'Lazy',
|
||||
]
|
||||
|
||||
export const domainModels = [
|
||||
'Person',
|
||||
'Product',
|
||||
'Spec',
|
||||
'Settings',
|
||||
'Account',
|
||||
'Login',
|
||||
'Logout',
|
||||
'Launchpad',
|
||||
'Wizard',
|
||||
]
|
||||
|
||||
export const componentNames = [
|
||||
'List',
|
||||
'Table',
|
||||
'Header',
|
||||
'Footer',
|
||||
'Button',
|
||||
'Cell',
|
||||
'Row',
|
||||
'Skeleton',
|
||||
'Loader',
|
||||
'Layout',
|
||||
]
|
||||
|
||||
export const specPattern = ['.spec', '_spec']
|
||||
|
||||
export const fileExtension = ['.tsx', '.jsx', '.ts', '.js']
|
||||
|
||||
export const directories = {
|
||||
rootDedicated: template('tests'),
|
||||
rootSrc: template('src'),
|
||||
monorepo: template('packages/{{component}}/test'),
|
||||
jestRoot: template('__test__'),
|
||||
jestNestedLib: template('lib/{{component}}{{component2}}/__test__'),
|
||||
dedicatedNested: template('lib/{{component}}/test'),
|
||||
jestNested: template('src/{{component}}/__test__'),
|
||||
componentsNested: template('src/components/{{component}}'),
|
||||
componentsFlat: template('src/{{component}}'),
|
||||
viewsFlat: template('src/views'),
|
||||
frontendFlat: template('frontend'),
|
||||
frontendComponentsFlat: template('frontend/components'),
|
||||
}
|
||||
|
||||
const nameTemplates = {
|
||||
// Business Logic Components
|
||||
longDomain: template(`{{prefix}}{{modifier}}{{domain}}{{component}}`),
|
||||
longDomain2: template(`{{prefix}}{{domain}}{{component}}{{component2}}`),
|
||||
|
||||
// App Components
|
||||
page1: template(`{{domain}}Page`),
|
||||
layout: template(`{{domain}}Layout`),
|
||||
|
||||
presentationalShort: template(`Base{{component}}`),
|
||||
presentationalLong: template(`Base{{component}}{{component2}}`),
|
||||
medium1: template(`{{prefix}}{{modifier}}{{component}}`),
|
||||
medium2: template(`{{prefix}}{{component}}{{component2}}`),
|
||||
short: template(`{{prefix}}{{component}}`),
|
||||
}
|
||||
|
||||
const prefixes = ['I', 'V', 'Cy', null]
|
||||
|
||||
export const componentNameGenerator = (options: { template: any, omit?: any, overrides?: any } = { template: nameTemplates.medium1, omit: [], overrides: {} }) => {
|
||||
const withoutValues = reduce(options.omit, (acc, v) => {
|
||||
acc[v] = null
|
||||
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const components = jml.pickCombination(componentNames, 2)
|
||||
const defaultOptions = {
|
||||
modifier: jml.pick(modifiers),
|
||||
domain: jml.pick(domainModels),
|
||||
prefix: jml.pick(prefixes),
|
||||
component: components[0],
|
||||
component2: components[1],
|
||||
}
|
||||
|
||||
return options.template({
|
||||
...defaultOptions,
|
||||
...withoutValues,
|
||||
...options.overrides,
|
||||
})
|
||||
}
|
||||
|
||||
const allRandomComponents = combineProperties({
|
||||
domain: domainModels,
|
||||
modifier: modifiers,
|
||||
prefix: prefixes,
|
||||
component: componentNames,
|
||||
component2: componentNames,
|
||||
fileExtension,
|
||||
specPattern,
|
||||
directory: keys(directories),
|
||||
})
|
||||
|
||||
export const randomComponents = (n = 200): FoundSpec[] => {
|
||||
return faker.random.arrayElements(allRandomComponents, n).map((d: ReturnType<typeof combineProperties>) => {
|
||||
const componentName = componentNameGenerator({
|
||||
overrides: d,
|
||||
template: faker.random.objectElement(nameTemplates),
|
||||
})
|
||||
|
||||
const name = `${componentName}${d.specPattern}${d.fileExtension}`
|
||||
|
||||
return {
|
||||
baseName: componentName,
|
||||
relative: `${directories[d.directory](d)}/${name}`,
|
||||
absolute: `${faker.system.directoryPath()}/${directories[d.directory](d)}/${name}`,
|
||||
name: `${componentName}${d.specPattern}`,
|
||||
specFileExtension: d.specPattern,
|
||||
fileExtension: d.fileExtension,
|
||||
specType: 'component',
|
||||
fileName: componentName,
|
||||
__typename: 'Spec',
|
||||
|
||||
id: faker.datatype.uuid(),
|
||||
gitInfo: {
|
||||
__typename: 'GitInfo',
|
||||
id: faker.datatype.uuid(),
|
||||
author: faker.internet.userName(),
|
||||
lastModifiedTimestamp: new Date(faker.random.arrayElement([
|
||||
faker.date.recent(8),
|
||||
faker.date.past(1),
|
||||
faker.date.between(new Date(Date.now() - 6000000).toUTCString(), new Date().toUTCString()),
|
||||
])).toUTCString(),
|
||||
},
|
||||
}
|
||||
}, n)
|
||||
}
|
||||
@@ -15,6 +15,7 @@ export function makeCacheExchange () {
|
||||
keys: {
|
||||
App: (data) => data.__typename,
|
||||
Wizard: (data) => data.__typename,
|
||||
GitInfo: () => null,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -15,12 +15,31 @@
|
||||
"copied": "Copied"
|
||||
},
|
||||
"file": {
|
||||
"edit": "Edit"
|
||||
"edit": "Edit",
|
||||
"git": {
|
||||
"modified": "Modified",
|
||||
"added": "Added",
|
||||
"created": "Created",
|
||||
"unmodified": "Unmodified",
|
||||
"deleted": "Deleted"
|
||||
}
|
||||
},
|
||||
"status": {
|
||||
"enabled": "Enabled",
|
||||
"disabled": "Disabled"
|
||||
},
|
||||
"specPage": {
|
||||
"pageTitle": "Specs",
|
||||
"newSpecButton": "New Spec",
|
||||
"searchPlaceholder": "Search Specs",
|
||||
"componentSpecsHeader": "Component Specs",
|
||||
"e2eSpecsHeader": "E2E Specs",
|
||||
"gitStatusHeader": "Git Status",
|
||||
"rows": {
|
||||
"gitInfoWithAuthor": "{fileState} {timeAgo} by {author}",
|
||||
"gitInfo": "{fileState} {timeAgo}"
|
||||
}
|
||||
},
|
||||
"topNav": {
|
||||
"released": "Released",
|
||||
"version": "Version",
|
||||
|
||||
@@ -14,14 +14,6 @@ body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
em {
|
||||
@apply text-purple-400 not-italic;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply text-indigo-600 hover:underline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utilities
|
||||
* -------------------------
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
/* Basic Options */
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"lib": ["dom", "ESNext"],
|
||||
/*
|
||||
* Allow javascript files to be compiled.
|
||||
* Override this in modules that need JS
|
||||
|
||||
@@ -41,6 +41,7 @@ const makePlugins = (plugins) => {
|
||||
...plugins.vueI18nOptions,
|
||||
}),
|
||||
Icons({
|
||||
scale: 1,
|
||||
customCollections: {
|
||||
// ~icons/cy/book-x16
|
||||
cy: FileSystemIconLoader(path.resolve(__dirname, './src/assets/icons')),
|
||||
|
||||
@@ -3,8 +3,9 @@ import InteractionVariants from '@windicss/plugin-interaction-variants'
|
||||
import { IconDuotoneColorsPlugin } from './.windicss/icon-color-plugins'
|
||||
import { safelist } from './.windicss/safelist'
|
||||
import { colors } from './.windicss/colors'
|
||||
import path from 'path'
|
||||
|
||||
export default defineConfig({
|
||||
export const defaultConfig = {
|
||||
// This adds !important to all utility classes. https://csswizardry.com/2016/05/the-importance-of-important/
|
||||
important: true,
|
||||
theme: {
|
||||
@@ -23,8 +24,8 @@ export default defineConfig({
|
||||
backgroundColor: ['group-focus-within', 'group-focus-visible', 'group-active', 'group-visited', 'group-disabled', 'hocus', 'group-hocus', 'can-hover', 'no-hover'],
|
||||
},
|
||||
plugins: [
|
||||
InteractionVariants,
|
||||
IconDuotoneColorsPlugin,
|
||||
InteractionVariants,
|
||||
],
|
||||
shortcuts: {
|
||||
'focus-default': 'focus:border focus:border-indigo-300 focus:ring-2 focus:ring-indigo-100 focus:outline-transparent transition transition-colors duration-100 disabled:hover:ring-0 disabled:hover:border-0',
|
||||
@@ -32,7 +33,15 @@ export default defineConfig({
|
||||
},
|
||||
extract: {
|
||||
// accepts globs and file paths relative to project root
|
||||
include: ['index.html', '**/*.{vue,html,tsx}', '../frontend-shared/**/*.{vue,html,tsx}'],
|
||||
include: [
|
||||
'index.html',
|
||||
'**/*.{vue,html,tsx}',
|
||||
path.join(__dirname, '../frontend-shared/**/*.{vue,html,tsx,svg}'),
|
||||
path.join(__dirname, '../app/**/*.{vue,html,tsx,svg}'),
|
||||
path.join(__dirname, '../launchpad/**/*.{vue,html,tsx,svg}'),
|
||||
],
|
||||
exclude: ['node_modules/**/*', '.git/**/*'],
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export default defineConfig(defineConfig)
|
||||
|
||||