feat(ui): Preset tab

This commit is contained in:
Guillaume Chau
2018-03-05 23:53:46 +01:00
parent ac50b82d0a
commit 45e3c82f0a
15 changed files with 319 additions and 29 deletions

View 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>

View File

@@ -35,7 +35,7 @@
@click="$emit('console')"
>
<VueIcon icon="subtitles"/>
<span>{{ consoleLog }}</span>
<span v-if="consoleLog">{{ consoleLog }}</span>
</div>
</div>
</template>

View File

@@ -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
}

View File

@@ -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: {

View File

@@ -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]
}

View File

@@ -0,0 +1,6 @@
fragment preset on Preset {
id
name
description
features
}

View File

@@ -0,0 +1,7 @@
#import "./projectCreationFragment.gql"
query projectCreation {
projectCreation {
...projectCreation
}
}

View File

@@ -0,0 +1,7 @@
#import "./presetFragment.gql"
fragment projectCreation on ProjectCreation {
presets {
...preset
}
}

View File

@@ -0,0 +1,7 @@
#import "./projectCreationFragment.gql"
mutation projectInitCreate {
projectInitCreate {
...projecCreation
}
}

View File

@@ -20,3 +20,8 @@ body,
> *
space-between-x(12px)
.cta-text
margin 12px
color lighten($vue-color-dark, 40%)
font-size 18px

View File

@@ -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
}
}
}

View File

@@ -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])})`,

View File

@@ -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)
}

View File

@@ -0,0 +1,13 @@
exports.getPromptModules = () => {
return [
'babel',
'typescript',
'pwa',
'router',
'vuex',
'cssPreprocessors',
'linter',
'unit',
'e2e'
].map(file => require(`../promptModules/${file}`))
}

View 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)}`