mirror of
https://github.com/vuejs/vue-cli.git
synced 2026-03-13 12:40:18 -05:00
feat(ui): Preset tab
This commit is contained in:
77
packages/@vue/cli-ui/src/components/ProjectPresetItem.vue
Normal file
77
packages/@vue/cli-ui/src/components/ProjectPresetItem.vue
Normal file
@@ -0,0 +1,77 @@
|
||||
<template>
|
||||
<div
|
||||
class="project-preset-item"
|
||||
:class="{
|
||||
selected
|
||||
}"
|
||||
>
|
||||
<div class="content">
|
||||
<div
|
||||
class="radio-icon"
|
||||
>
|
||||
<VueIcon
|
||||
:icon="selected ? 'radio_button_checked' : 'radio_button_unchecked'"
|
||||
class="medium"
|
||||
/>
|
||||
</div>
|
||||
<div class="name">{{ preset.name }}</div>
|
||||
<div class="description">{{ preset.description }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
preset: {
|
||||
type: Object,
|
||||
required: true
|
||||
},
|
||||
|
||||
selected: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
@import "~@/style/imports"
|
||||
|
||||
.project-preset-item
|
||||
padding 12px
|
||||
padding-left 0
|
||||
user-select none
|
||||
cursor pointer
|
||||
|
||||
.content
|
||||
display grid
|
||||
grid-template-columns 64px auto
|
||||
grid-template-rows 24px 24px
|
||||
grid-template-areas "icon name" "icon description"
|
||||
|
||||
.radio-icon
|
||||
h-box()
|
||||
box-center()
|
||||
grid-area icon
|
||||
|
||||
.name
|
||||
grid-area name
|
||||
|
||||
.description
|
||||
grid-area description
|
||||
color lighten($vue-color-dark, 40%)
|
||||
|
||||
&.selected
|
||||
background rgba($vue-color-primary, .05)
|
||||
.radio-icon
|
||||
>>> svg
|
||||
fill $vue-color-primary
|
||||
.name
|
||||
color $vue-color-primary
|
||||
|
||||
&:hover
|
||||
background rgba($vue-color-primary, .1)
|
||||
|
||||
</style>
|
||||
@@ -35,7 +35,7 @@
|
||||
@click="$emit('console')"
|
||||
>
|
||||
<VueIcon icon="subtitles"/>
|
||||
<span>{{ consoleLog }}</span>
|
||||
<span v-if="consoleLog">{{ consoleLog }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
const Creator = require('@vue/cli/lib/Creator')
|
||||
const { getPromptModules } = require('@vue/cli/lib/util/createTools')
|
||||
const { getFeatures } = require('@vue/cli/lib/util/features')
|
||||
const { toShortPluginId } = require('@vue/cli-shared-utils')
|
||||
const cwd = require('./cwd')
|
||||
|
||||
let currentProject = null
|
||||
let creator = null
|
||||
|
||||
function list (context) {
|
||||
return context.db.get('projects').value()
|
||||
@@ -8,7 +15,55 @@ function getCurrent (context) {
|
||||
return currentProject
|
||||
}
|
||||
|
||||
function generatePresetDescription (preset) {
|
||||
let description = `Features: ${preset.features.join(', ')}`
|
||||
|
||||
if (preset.raw.useConfigFiles) {
|
||||
description += ` (Use config files)`
|
||||
}
|
||||
|
||||
return description
|
||||
}
|
||||
|
||||
function generateProjectCreation (creator) {
|
||||
const presets = creator.getPresets()
|
||||
return {
|
||||
presets: [
|
||||
...Object.keys(presets).map(
|
||||
key => {
|
||||
const preset = presets[key]
|
||||
const features = getFeatures(preset).map(
|
||||
f => toShortPluginId(f)
|
||||
)
|
||||
const info = {
|
||||
id: key,
|
||||
name: key === 'default' ? 'Default preset' : key,
|
||||
features,
|
||||
raw: preset
|
||||
}
|
||||
info.description = generatePresetDescription(info)
|
||||
return info
|
||||
}
|
||||
),
|
||||
{
|
||||
id: 'manual',
|
||||
name: 'No preset',
|
||||
description: 'No included features',
|
||||
features: []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
function getCreation (context) {
|
||||
if (!creator) {
|
||||
creator = new Creator('', cwd.get(), getPromptModules())
|
||||
}
|
||||
return generateProjectCreation(creator)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
list,
|
||||
getCurrent
|
||||
getCurrent,
|
||||
getCreation
|
||||
}
|
||||
|
||||
@@ -15,7 +15,8 @@ module.exports = {
|
||||
folderCurrent: (root, args, context) => folders.getCurrent(args, context),
|
||||
foldersFavorite: (root, args, context) => folders.listFavorite(context),
|
||||
projects: (root, args, context) => projects.list(context),
|
||||
projectCurrent: (root, args, context) => projects.getCurrent(context)
|
||||
projectCurrent: (root, args, context) => projects.getCurrent(context),
|
||||
projectCreation: (root, args, context) => projects.getCreation(context)
|
||||
},
|
||||
|
||||
Mutation: {
|
||||
|
||||
@@ -119,12 +119,24 @@ input PromptInput {
|
||||
value: String!
|
||||
}
|
||||
|
||||
type Preset {
|
||||
id: ID!
|
||||
name: String
|
||||
description: String
|
||||
features: [String]
|
||||
}
|
||||
|
||||
type ProjectCreation {
|
||||
presets: [Preset]
|
||||
}
|
||||
|
||||
type Query {
|
||||
cwd: String!
|
||||
folderCurrent: Folder
|
||||
foldersFavorite: [Folder]
|
||||
projects: [Project]
|
||||
projectCurrent: Project
|
||||
projectCreation: ProjectCreation
|
||||
pluginSearch (input: PluginSearchInput!): [Plugin]
|
||||
}
|
||||
|
||||
|
||||
6
packages/@vue/cli-ui/src/graphql/presetFragment.gql
Normal file
6
packages/@vue/cli-ui/src/graphql/presetFragment.gql
Normal file
@@ -0,0 +1,6 @@
|
||||
fragment preset on Preset {
|
||||
id
|
||||
name
|
||||
description
|
||||
features
|
||||
}
|
||||
7
packages/@vue/cli-ui/src/graphql/projectCreation.gql
Normal file
7
packages/@vue/cli-ui/src/graphql/projectCreation.gql
Normal file
@@ -0,0 +1,7 @@
|
||||
#import "./projectCreationFragment.gql"
|
||||
|
||||
query projectCreation {
|
||||
projectCreation {
|
||||
...projectCreation
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#import "./presetFragment.gql"
|
||||
|
||||
fragment projectCreation on ProjectCreation {
|
||||
presets {
|
||||
...preset
|
||||
}
|
||||
}
|
||||
7
packages/@vue/cli-ui/src/graphql/projectInitCreate.gql
Normal file
7
packages/@vue/cli-ui/src/graphql/projectInitCreate.gql
Normal file
@@ -0,0 +1,7 @@
|
||||
#import "./projectCreationFragment.gql"
|
||||
|
||||
mutation projectInitCreate {
|
||||
projectInitCreate {
|
||||
...projecCreation
|
||||
}
|
||||
}
|
||||
@@ -20,3 +20,8 @@ body,
|
||||
|
||||
> *
|
||||
space-between-x(12px)
|
||||
|
||||
.cta-text
|
||||
margin 12px
|
||||
color lighten($vue-color-dark, 40%)
|
||||
font-size 18px
|
||||
|
||||
@@ -85,6 +85,55 @@
|
||||
label="Presets"
|
||||
icon="check_circle"
|
||||
:disabled="!detailsValid"
|
||||
lazy
|
||||
>
|
||||
<div class="content vue-disable-scroll">
|
||||
<div class="vue-text info banner">
|
||||
<VueIcon icon="info" class="big"/>
|
||||
<span>A preset is an association of plugins and configurations. After you've selected features, you can optionally save it as a preset so that you can reuse it for future projects, without having to reconfigure everything again.</span>
|
||||
</div>
|
||||
|
||||
<div class="cta-text">Select a preset:</div>
|
||||
|
||||
<ProjectPresetItem
|
||||
v-for="preset of projectCreation.presets"
|
||||
:key="preset.id"
|
||||
:preset="preset"
|
||||
:selected="preset.id === selectedPreset"
|
||||
@click.native="selectPreset(preset.id)"
|
||||
/>
|
||||
|
||||
<ProjectPresetItem
|
||||
:preset="remotePresetInfo"
|
||||
:selected="selectedPreset === 'remote'"
|
||||
@click.native="selectPreset('remote')"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="actions-bar">
|
||||
<VueButton
|
||||
icon-left="arrow_back"
|
||||
label="Previous"
|
||||
class="big"
|
||||
@click="$refs.wizard.previous()"
|
||||
/>
|
||||
|
||||
<VueButton
|
||||
icon-right="arrow_forward"
|
||||
label="Next"
|
||||
class="big primary"
|
||||
:disabled="!selectedPreset"
|
||||
@click="$refs.wizard.next()"
|
||||
/>
|
||||
</div>
|
||||
</VueTab>
|
||||
|
||||
<VueTab
|
||||
id="features"
|
||||
label="Features"
|
||||
icon="device_hub"
|
||||
:disabled="!detailsValid || !presetValid"
|
||||
lazy
|
||||
>
|
||||
<div class="content">
|
||||
|
||||
@@ -108,10 +157,11 @@
|
||||
</VueTab>
|
||||
|
||||
<VueTab
|
||||
id="features"
|
||||
label="Features"
|
||||
id="plugins"
|
||||
label="Plugins"
|
||||
icon="widgets"
|
||||
:disabled="!detailsValid"
|
||||
:disabled="!detailsValid || !presetValid"
|
||||
lazy
|
||||
>
|
||||
<div class="content">
|
||||
|
||||
@@ -138,7 +188,8 @@
|
||||
id="config"
|
||||
label="Configuration"
|
||||
icon="settings_applications"
|
||||
:disabled="!detailsValid"
|
||||
:disabled="!detailsValid || !presetValid"
|
||||
lazy
|
||||
>
|
||||
<div class="content">
|
||||
|
||||
@@ -163,30 +214,81 @@
|
||||
</div>
|
||||
|
||||
<StatusBar cwd/>
|
||||
|
||||
<VueModal
|
||||
v-if="remotePreset.openModal"
|
||||
title="Configure Remote preset"
|
||||
class="medium"
|
||||
@close="remotePreset.openModal = false"
|
||||
>
|
||||
<div class="default-body">
|
||||
<div class="vue-empty">
|
||||
<VueIcon icon="cake" class="large"/>
|
||||
<div>Available soon...</div>
|
||||
</div>
|
||||
</div>
|
||||
</VueModal>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import StepWizard from '../components/StepWizard'
|
||||
import ProjectPresetItem from '../components/ProjectPresetItem'
|
||||
import StatusBar from '../components/StatusBar'
|
||||
import StepWizard from '../components/StepWizard'
|
||||
|
||||
import PROJECT_CREATION from '../graphql/projectCreation.gql'
|
||||
import PROJECT_INIT_CREATE from '../graphql/projectInitCreate.gql'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
StepWizard,
|
||||
StatusBar
|
||||
ProjectPresetItem,
|
||||
StatusBar,
|
||||
StepWizard
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
folder: '',
|
||||
folder: 'test-app',
|
||||
force: false,
|
||||
packageManager: undefined
|
||||
packageManager: undefined,
|
||||
projectCreation: null,
|
||||
selectedPreset: null,
|
||||
remotePreset: {
|
||||
url: '',
|
||||
openModal: false
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
apollo: {
|
||||
projectCreation: PROJECT_CREATION
|
||||
},
|
||||
|
||||
computed: {
|
||||
detailsValid () {
|
||||
return !!this.folder
|
||||
},
|
||||
|
||||
presetValid () {
|
||||
return !!this.selectedPreset
|
||||
},
|
||||
|
||||
remotePresetInfo () {
|
||||
return {
|
||||
name: 'Remote preset',
|
||||
description: 'Fetch a preset from a git repository'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
selectPreset (id) {
|
||||
if (id === 'remote') {
|
||||
this.remotePreset.openModal = true
|
||||
return
|
||||
}
|
||||
|
||||
this.selectedPreset = id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ const { installDeps } = require('./util/installDeps')
|
||||
const clearConsole = require('./util/clearConsole')
|
||||
const PromptModuleAPI = require('./PromptModuleAPI')
|
||||
const writeFileTree = require('./util/writeFileTree')
|
||||
const formatFeatures = require('./util/formatFeatures')
|
||||
const { formatFeatures } = require('./util/features')
|
||||
const setupDevProject = require('./util/setupDevProject')
|
||||
const fetchRemotePreset = require('./util/fetchRemotePreset')
|
||||
|
||||
@@ -269,9 +269,13 @@ module.exports = class Creator {
|
||||
})
|
||||
}
|
||||
|
||||
resolveIntroPrompts () {
|
||||
getPresets () {
|
||||
const savedOptions = loadOptions()
|
||||
const presets = Object.assign({}, savedOptions.presets, defaults.presets)
|
||||
return Object.assign({}, savedOptions.presets, defaults.presets)
|
||||
}
|
||||
|
||||
resolveIntroPrompts () {
|
||||
const presets = this.getPresets()
|
||||
const presetChoices = Object.keys(presets).map(name => {
|
||||
return {
|
||||
name: `${name} (${formatFeatures(presets[name])})`,
|
||||
|
||||
@@ -5,6 +5,7 @@ const rimraf = require('rimraf')
|
||||
const inquirer = require('inquirer')
|
||||
const Creator = require('./Creator')
|
||||
const clearConsole = require('./util/clearConsole')
|
||||
const { getPromptModules } = require('./util/createTools')
|
||||
const { error, stopSpinner } = require('@vue/cli-shared-utils')
|
||||
|
||||
async function create (projectName, options) {
|
||||
@@ -50,19 +51,7 @@ async function create (projectName, options) {
|
||||
}
|
||||
}
|
||||
|
||||
const promptModules = [
|
||||
'babel',
|
||||
'typescript',
|
||||
'pwa',
|
||||
'router',
|
||||
'vuex',
|
||||
'cssPreprocessors',
|
||||
'linter',
|
||||
'unit',
|
||||
'e2e'
|
||||
].map(file => require(`./promptModules/${file}`))
|
||||
|
||||
const creator = new Creator(name, targetDir, promptModules)
|
||||
const creator = new Creator(name, targetDir, getPromptModules())
|
||||
await creator.create(options)
|
||||
}
|
||||
|
||||
|
||||
13
packages/@vue/cli/lib/util/createTools.js
Normal file
13
packages/@vue/cli/lib/util/createTools.js
Normal file
@@ -0,0 +1,13 @@
|
||||
exports.getPromptModules = () => {
|
||||
return [
|
||||
'babel',
|
||||
'typescript',
|
||||
'pwa',
|
||||
'router',
|
||||
'vuex',
|
||||
'cssPreprocessors',
|
||||
'linter',
|
||||
'unit',
|
||||
'e2e'
|
||||
].map(file => require(`../promptModules/${file}`))
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
const chalk = require('chalk')
|
||||
const { toShortPluginId } = require('@vue/cli-shared-utils')
|
||||
|
||||
module.exports = function formatFeatures (preset, lead, joiner) {
|
||||
exports.getFeatures = (preset) => {
|
||||
const features = []
|
||||
if (preset.router) {
|
||||
features.push('vue-router')
|
||||
@@ -16,6 +16,11 @@ module.exports = function formatFeatures (preset, lead, joiner) {
|
||||
return dep !== '@vue/cli-service'
|
||||
})
|
||||
features.push.apply(features, plugins)
|
||||
return features
|
||||
}
|
||||
|
||||
exports.formatFeatures = (preset, lead, joiner) => {
|
||||
const features = exports.getFeatures(preset)
|
||||
return features.map(dep => {
|
||||
dep = toShortPluginId(dep)
|
||||
return `${lead || ''}${chalk.yellow(dep)}`
|
||||
Reference in New Issue
Block a user