added locations and about me text
@ -119,3 +119,11 @@ blockquote {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 0;
|
||||
width: 100%;
|
||||
color: $color-neutral-80;
|
||||
background-color: $color-neutral-80;
|
||||
height: 1px !important;
|
||||
}
|
||||
|
||||
@ -24,13 +24,22 @@
|
||||
</no-ssr>
|
||||
</ds-space>
|
||||
<template slot="footer">
|
||||
<span :style="{ opacity: post.shoutedCount ? 1 : .5 }">
|
||||
<ds-icon name="heart-o" /> <small>{{ post.shoutedCount }}</small>
|
||||
</span>
|
||||
|
||||
<span :style="{ opacity: post.commentsCount ? 1 : .5 }">
|
||||
<ds-icon name="comments" /> <small>{{ post.commentsCount }}</small>
|
||||
</span>
|
||||
<div style="display: inline-block; opacity: .5;">
|
||||
<ds-icon
|
||||
v-tooltip="{content: category.name, placement: 'bottom-start', delay: { show: 500 }}"
|
||||
v-for="category in post.categories"
|
||||
:key="category.id"
|
||||
:name="category.icon" />
|
||||
</div>
|
||||
<div style="display: inline-block; float: right">
|
||||
<span :style="{ opacity: post.shoutedCount ? 1 : .5 }">
|
||||
<ds-icon name="bullhorn" /> <small>{{ post.shoutedCount }}</small>
|
||||
</span>
|
||||
|
||||
<span :style="{ opacity: post.commentsCount ? 1 : .5 }">
|
||||
<ds-icon name="comments" /> <small>{{ post.commentsCount }}</small>
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
</ds-card>
|
||||
</a>
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
:disabled="disabled || loading"
|
||||
danger
|
||||
size="x-large"
|
||||
icon="heart"
|
||||
icon="bullhorn"
|
||||
@click="shout" />
|
||||
<ds-space margin-bottom="xx-small" />
|
||||
<ds-text color="soft">
|
||||
|
||||
@ -6,14 +6,11 @@ export default gql(`
|
||||
id
|
||||
name
|
||||
avatar
|
||||
createdAt
|
||||
friendsCount
|
||||
friends {
|
||||
id
|
||||
about
|
||||
location {
|
||||
name
|
||||
slug
|
||||
avatar
|
||||
}
|
||||
createdAt
|
||||
badges {
|
||||
id
|
||||
key
|
||||
@ -63,6 +60,11 @@ export default gql(`
|
||||
deleted
|
||||
image
|
||||
createdAt
|
||||
categories {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
author {
|
||||
User {
|
||||
id
|
||||
|
||||
@ -1,10 +1,5 @@
|
||||
const pkg = require('./package')
|
||||
const envWhitelist = [
|
||||
'NODE_ENV',
|
||||
'BACKEND_URL',
|
||||
'MAINTENANCE'
|
||||
]
|
||||
|
||||
const envWhitelist = ['NODE_ENV', 'BACKEND_URL', 'MAINTENANCE']
|
||||
|
||||
module.exports = {
|
||||
mode: 'universal',
|
||||
@ -102,6 +97,7 @@ module.exports = {
|
||||
*/
|
||||
modules: [
|
||||
'@nuxtjs/apollo',
|
||||
'@nuxtjs/axios',
|
||||
['@nuxtjs/dotenv', { only: envWhitelist }],
|
||||
['nuxt-env', { keys: envWhitelist }]
|
||||
],
|
||||
@ -129,7 +125,7 @@ module.exports = {
|
||||
// },
|
||||
// required
|
||||
clientConfigs: {
|
||||
default: '~/plugins/apollo-config.js',
|
||||
default: '~/plugins/apollo-config.js'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxtjs/apollo": "^4.0.0-rc3",
|
||||
"@nuxtjs/axios": "^5.3.4",
|
||||
"@nuxtjs/dotenv": "^1.3.0",
|
||||
"accounting": "^0.4.1",
|
||||
"cross-env": "^5.2.0",
|
||||
|
||||
@ -47,6 +47,10 @@ export default {
|
||||
name: 'Categories',
|
||||
path: `/admin/categories`
|
||||
},
|
||||
{
|
||||
name: 'Tags',
|
||||
path: `/admin/tags`
|
||||
},
|
||||
{
|
||||
name: 'Settings',
|
||||
path: `/admin/settings`
|
||||
|
||||
@ -1,7 +1,42 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<ds-space margin="small">
|
||||
Categories...
|
||||
</ds-space>
|
||||
<ds-card space="small">
|
||||
<ds-heading tag="h3">Themen / Kategorien</ds-heading>
|
||||
<ds-table
|
||||
:data="Category"
|
||||
:fields="['icon', 'name', 'postCount']"
|
||||
condensed>
|
||||
<template
|
||||
slot="icon"
|
||||
slot-scope="scope">
|
||||
<ds-icon :name="scope.row.icon" />
|
||||
</template>
|
||||
</ds-table>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
Category: []
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
Category: {
|
||||
query: gql(`
|
||||
query {
|
||||
Category(orderBy: postCount_desc) {
|
||||
id
|
||||
name
|
||||
slug
|
||||
icon
|
||||
postCount
|
||||
}
|
||||
}
|
||||
`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
47
pages/admin/tags.vue
Normal file
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<ds-card space="small">
|
||||
<ds-heading tag="h3">Tags</ds-heading>
|
||||
<ds-table
|
||||
:data="Tag"
|
||||
:fields="fields"
|
||||
condensed>
|
||||
<template
|
||||
slot="id"
|
||||
slot-scope="scope">
|
||||
{{ scope.index + 1 }}
|
||||
</template>
|
||||
</ds-table>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
Tag: [],
|
||||
fields: {
|
||||
id: { label: '#' },
|
||||
name: { label: 'Name' },
|
||||
taggedCountUnique: { label: 'Nutzer' },
|
||||
taggedCount: { label: 'Beiträge' }
|
||||
}
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
Tag: {
|
||||
query: gql(`
|
||||
query {
|
||||
Tag(first: 20, orderBy: taggedCountUnique_desc) {
|
||||
id
|
||||
name
|
||||
taggedCount
|
||||
taggedCountUnique
|
||||
}
|
||||
}
|
||||
`)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -106,6 +106,7 @@ export default {
|
||||
categories {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
shoutedCount
|
||||
}
|
||||
|
||||
@ -17,11 +17,18 @@
|
||||
:count="post.shoutedCount"
|
||||
:post-id="post.id" />
|
||||
<!-- Categories -->
|
||||
<div class="tags">
|
||||
<ds-icon
|
||||
v-tooltip="{content: category.name, placement: 'top-start', delay: { show: 300 }}"
|
||||
v-for="category in post.categories"
|
||||
:key="category.id"
|
||||
:name="category.icon"
|
||||
size="large" />
|
||||
<ds-space margin-bottom="small" />
|
||||
<!--<div class="tags">
|
||||
<ds-icon name="compass" /> <ds-tag
|
||||
v-for="category in post.categories"
|
||||
:key="category.id">{{ category.name }}</ds-tag>
|
||||
</div>
|
||||
:key="category.id"><ds-icon :name="category.icon" /> {{ category.name }}</ds-tag>
|
||||
</div>-->
|
||||
<!-- Tags -->
|
||||
<template v-if="post.tags && post.tags.length">
|
||||
<ds-space margin="xx-small"/>
|
||||
@ -140,7 +147,7 @@ export default {
|
||||
name
|
||||
}
|
||||
commentsCount
|
||||
comments(orderBy: _id_desc) {
|
||||
comments(orderBy: createdAt_desc) {
|
||||
id
|
||||
contentExcerpt
|
||||
createdAt
|
||||
@ -166,6 +173,7 @@ export default {
|
||||
categories {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
shoutedCount
|
||||
}
|
||||
|
||||
@ -5,9 +5,15 @@
|
||||
<ds-space/>
|
||||
<h3><ds-icon name="compass" /> Themenkategorien</h3>
|
||||
<div class="tags">
|
||||
<ds-tag
|
||||
<ds-icon
|
||||
v-tooltip="{content: category.name, placement: 'top-start', delay: { show: 300 }}"
|
||||
v-for="category in post.categories"
|
||||
:key="category.id">{{ category.name }}</ds-tag>
|
||||
:key="category.id"
|
||||
:name="category.icon"
|
||||
size="large" />
|
||||
<!--<ds-tag
|
||||
v-for="category in post.categories"
|
||||
:key="category.id"><ds-icon :name="category.icon" /> {{ category.name }}</ds-tag>-->
|
||||
</div>
|
||||
<template v-if="post.tags && post.tags.length">
|
||||
<h3><ds-icon name="tags" /> Schlagwörter</h3>
|
||||
@ -70,6 +76,7 @@ export default {
|
||||
categories {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
relatedContributions(first: 2) {
|
||||
id
|
||||
@ -78,6 +85,11 @@ export default {
|
||||
contentExcerpt
|
||||
shoutedCount
|
||||
commentsCount
|
||||
categories {
|
||||
id
|
||||
name
|
||||
icon
|
||||
}
|
||||
author {
|
||||
User {
|
||||
id
|
||||
|
||||
@ -21,10 +21,17 @@
|
||||
align="center"
|
||||
no-margin>{{ user.name }}</ds-heading>
|
||||
<ds-text
|
||||
v-if="user.location && user.location.length"
|
||||
align="center"
|
||||
color="soft"
|
||||
size="small">
|
||||
Mitglied seid {{ user.createdAt | date('MMMM yyyy') }}
|
||||
<ds-icon name="map-marker" /> {{ user.location[0].name }}
|
||||
</ds-text>
|
||||
<ds-text
|
||||
align="center"
|
||||
color="soft"
|
||||
size="small">
|
||||
Mitglied seit {{ user.createdAt | date('MMMM yyyy') }}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
<ds-space
|
||||
@ -60,6 +67,18 @@
|
||||
:follow-id="user.id"
|
||||
@update="voted = true && fetchUser()" />
|
||||
</ds-space>
|
||||
<template v-if="user.about">
|
||||
<hr>
|
||||
<ds-space
|
||||
margin-top="small"
|
||||
margin-bottom="small">
|
||||
<ds-text
|
||||
color="soft"
|
||||
size="small">
|
||||
{{ user.about }}
|
||||
</ds-text>
|
||||
</ds-space>
|
||||
</template>
|
||||
</ds-card>
|
||||
<ds-space/>
|
||||
<ds-heading
|
||||
|
||||
@ -1,5 +1,203 @@
|
||||
<template>
|
||||
<ds-card>
|
||||
<p>My Data...</p>
|
||||
<ds-card space="small">
|
||||
<ds-input
|
||||
id="name"
|
||||
v-model="form.name"
|
||||
icon="user"
|
||||
label="Dein Name"
|
||||
placeholder="Dein Name"/>
|
||||
<ds-select
|
||||
id="city"
|
||||
:options="cities"
|
||||
v-model="city"
|
||||
icon="map-marker"
|
||||
label="Deine Stadt"
|
||||
placeholder="Deine Stadt"
|
||||
@input="handleCitySelection"
|
||||
@input.native="handleCityInput" />
|
||||
<ds-input
|
||||
id="bio"
|
||||
v-model="form.about"
|
||||
type="textarea"
|
||||
rows="3"
|
||||
label="Erzähl doch ein wenig (in zwei Sätzen) über dich"
|
||||
placeholder="Über mich"/>
|
||||
<template slot="footer">
|
||||
<ds-button
|
||||
style="float: right;"
|
||||
icon="check"
|
||||
primary
|
||||
@click.prevent="submit">Speichern</ds-button>
|
||||
</template>
|
||||
</ds-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
import { mapGetters } from 'vuex'
|
||||
import { CancelToken } from 'axios'
|
||||
import find from 'lodash/find'
|
||||
|
||||
let timeout
|
||||
const mapboxToken =
|
||||
'pk.eyJ1IjoiaHVtYW4tY29ubmVjdGlvbiIsImEiOiJjajl0cnBubGoweTVlM3VwZ2lzNTNud3ZtIn0.KZ8KK9l70omjXbEkkbHGsQ'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
axiosSource: null,
|
||||
cities: [],
|
||||
city: null,
|
||||
form: {
|
||||
name: null,
|
||||
locationId: null,
|
||||
about: null
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
user: 'auth/user'
|
||||
})
|
||||
},
|
||||
watch: {
|
||||
user: {
|
||||
immediate: true,
|
||||
handler: function(user) {
|
||||
this.form = {
|
||||
name: user.name,
|
||||
locationId: user.locationId,
|
||||
about: user.about
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit() {
|
||||
console.log('SUBMIT', { ...this.form })
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: gql`
|
||||
mutation(
|
||||
$id: ID!
|
||||
$name: String
|
||||
$locationId: String
|
||||
$about: String
|
||||
) {
|
||||
UpdateUser(
|
||||
id: $id
|
||||
name: $name
|
||||
locationId: $locationId
|
||||
about: $about
|
||||
) {
|
||||
id
|
||||
name
|
||||
locationId
|
||||
about
|
||||
}
|
||||
}
|
||||
`,
|
||||
// Parameters
|
||||
variables: {
|
||||
id: this.user.id,
|
||||
name: this.form.name,
|
||||
locationId: this.form.locationId,
|
||||
about: this.form.about
|
||||
},
|
||||
// Update the cache with the result
|
||||
// The query will be updated with the optimistic response
|
||||
// and then with the real result of the mutation
|
||||
update: (store, { data: { UpdateUser } }) => {
|
||||
this.$store.dispatch('auth/refresh', UpdateUser)
|
||||
|
||||
// Read the data from our cache for this query.
|
||||
// const data = store.readQuery({ query: TAGS_QUERY })
|
||||
// Add our tag from the mutation to the end
|
||||
// data.tags.push(addTag)
|
||||
// Write our data back to the cache.
|
||||
// store.writeQuery({ query: TAGS_QUERY, data })
|
||||
}
|
||||
// Optimistic UI
|
||||
// Will be treated as a 'fake' result as soon as the request is made
|
||||
// so that the UI can react quickly and the user be happy
|
||||
/* optimisticResponse: {
|
||||
__typename: 'Mutation',
|
||||
addTag: {
|
||||
__typename: 'Tag',
|
||||
id: -1,
|
||||
label: newTag
|
||||
}
|
||||
} */
|
||||
})
|
||||
.then(data => {
|
||||
console.log(data)
|
||||
this.$toast.success('Updated user')
|
||||
})
|
||||
.catch(err => {
|
||||
console.error(err)
|
||||
this.$toast.error(err.message)
|
||||
})
|
||||
},
|
||||
handleCityInput(value) {
|
||||
clearTimeout(timeout)
|
||||
timeout = setTimeout(() => this.requestGeoData(value), 500)
|
||||
},
|
||||
handleCitySelection(value) {
|
||||
console.log('SET CURRENT VALUE', value)
|
||||
const item = find(this.cities, { value: value })
|
||||
console.log('ID:', item.id)
|
||||
this.form.locationId = item.id
|
||||
},
|
||||
handleCityEnter() {
|
||||
console.log('SET CURRENT VALUE')
|
||||
},
|
||||
processCityResults(res) {
|
||||
if (
|
||||
!res ||
|
||||
!res.data ||
|
||||
!res.data.features ||
|
||||
!res.data.features.length
|
||||
) {
|
||||
return []
|
||||
}
|
||||
let output = []
|
||||
res.data.features.forEach(item => {
|
||||
output.push({
|
||||
label: item.place_name,
|
||||
value: item.place_name,
|
||||
id: item.id
|
||||
})
|
||||
})
|
||||
|
||||
return output
|
||||
},
|
||||
requestGeoData(e) {
|
||||
if (this.axiosSource) {
|
||||
// cancel last request
|
||||
this.axiosSource.cancel()
|
||||
}
|
||||
|
||||
const value = e.target ? e.target.value.trim() : ''
|
||||
if (value === '' || value.length < 3) {
|
||||
this.cities = []
|
||||
return
|
||||
}
|
||||
|
||||
this.axiosSource = CancelToken.source()
|
||||
|
||||
this.$axios
|
||||
.get(
|
||||
`https://api.mapbox.com/geocoding/v5/mapbox.places/${value}.json?access_token=${mapboxToken}&types=region,postcode,district,place,country&language=de`,
|
||||
{
|
||||
cancelToken: this.axiosSource.token
|
||||
}
|
||||
)
|
||||
.then(res => {
|
||||
this.cities = this.processCityResults(res)
|
||||
})
|
||||
console.log('TRY TO GET DATA FOR ', value)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -85,7 +85,9 @@ export const actions = {
|
||||
slug: user.slug,
|
||||
email: user.email,
|
||||
avatar: user.avatar,
|
||||
role: user.role
|
||||
role: user.role,
|
||||
locationId: user.locationId,
|
||||
about: user.about
|
||||
})
|
||||
commit('SET_TOKEN', token)
|
||||
}
|
||||
@ -96,6 +98,21 @@ export const actions = {
|
||||
}
|
||||
return getters.isLoggedIn
|
||||
},
|
||||
refresh({ state, commit }, { id, name, locationId, about, avatar }) {
|
||||
if (!state.user.id || id !== state.user.id) {
|
||||
return
|
||||
}
|
||||
commit('SET_USER', {
|
||||
id: state.user.id, // do not change
|
||||
name: name || state.user.name,
|
||||
slug: state.user.slug, // do not change
|
||||
email: state.user.email, // do not change
|
||||
avatar: avatar || state.user.avatar,
|
||||
role: state.user.role,
|
||||
locationId: locationId || state.user.locationId,
|
||||
about: about || state.user.about
|
||||
})
|
||||
},
|
||||
async login({ commit }, { email, password }) {
|
||||
try {
|
||||
commit('SET_PENDING', true)
|
||||
@ -112,6 +129,8 @@ export const actions = {
|
||||
email
|
||||
avatar
|
||||
role
|
||||
locationId
|
||||
about
|
||||
token
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
height: 100%;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
|
||||
box-shadow: inset 0 0 0 1px rgba($color-neutral-0, .1);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,11 @@
|
||||
<table
|
||||
cellpadding="0"
|
||||
cellspacing="0"
|
||||
class="ds-table">
|
||||
class="ds-table"
|
||||
:class="[
|
||||
condensed && 'ds-table-condensed',
|
||||
bordered && 'ds-table-bordered'
|
||||
]">
|
||||
<colgroup>
|
||||
<col
|
||||
v-for="header in headers"
|
||||
@ -24,7 +28,7 @@
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="(row, index) in rows"
|
||||
:key="index">
|
||||
:key="row.key || index">
|
||||
<ds-table-col
|
||||
v-for="col in row"
|
||||
:key="col.key">
|
||||
@ -75,6 +79,20 @@ export default {
|
||||
default() {
|
||||
return null
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Should the table be more condense?
|
||||
*/
|
||||
condensed: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* Should the table have borders?
|
||||
*/
|
||||
bordered: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
@ -11,19 +11,34 @@
|
||||
|
||||
.ds-table-col {
|
||||
@include reset;
|
||||
border-bottom: $border-color-softer solid $border-size-base;
|
||||
vertical-align: top;
|
||||
padding: $space-small $space-xx-small;
|
||||
|
||||
&:last-child {
|
||||
padding-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-table-head-col {
|
||||
@include reset;
|
||||
border-bottom: $border-color-softer solid $border-size-base;
|
||||
padding: $space-small $space-xx-small;
|
||||
text-align: left;
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
}
|
||||
|
||||
// bordered
|
||||
.ds-table-bordered {
|
||||
.ds-table-col,
|
||||
.ds-table-head-col {
|
||||
border-bottom: $border-color-softer dotted $border-size-base;
|
||||
}
|
||||
|
||||
tr:last-child .ds-table-col {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
// condensed
|
||||
.ds-table-condensed {
|
||||
.ds-table-col,
|
||||
.ds-table-head-col {
|
||||
padding-top: $space-x-small;
|
||||
padding-bottom: $space-x-small;
|
||||
}
|
||||
}
|
||||
|
||||
9
styleguide/src/system/components/data-input/FormItem/FormItem.vue
Normal file → Executable file
@ -1,10 +1,9 @@
|
||||
<template>
|
||||
<div
|
||||
<div
|
||||
class="ds-form-item"
|
||||
:class="$parentInput ? $parentInput.stateClasses : ''">
|
||||
<ds-input-label
|
||||
v-if="$parentInput"
|
||||
:label="$parentInput.label"
|
||||
:class="$parentInput.stateClasses">
|
||||
<ds-input-label
|
||||
:label="$parentInput.label"
|
||||
:for="$parentInput.id" />
|
||||
<slot/>
|
||||
<ds-input-error :error="$parentInput.error" />
|
||||
|
||||
0
styleguide/src/system/components/data-input/FormItem/InputError.vue
Normal file → Executable file
0
styleguide/src/system/components/data-input/FormItem/InputLabel.vue
Normal file → Executable file
0
styleguide/src/system/components/data-input/FormItem/style.scss
Normal file → Executable file
3
styleguide/src/system/components/data-input/Input/Input.vue
Normal file → Executable file
@ -17,11 +17,12 @@
|
||||
:type="type"
|
||||
:autofocus="autofocus"
|
||||
:placeholder="placeholder"
|
||||
:tabindex="tabindex"
|
||||
:disabled="disabled"
|
||||
:readonly="readonly"
|
||||
:is="tag"
|
||||
:value.prop="innerValue"
|
||||
@input="input"
|
||||
@input="handleInput"
|
||||
@focus="handleFocus"
|
||||
@blur="handleBlur"
|
||||
:rows="type === 'textarea' ? rows : null"
|
||||
|
||||
0
styleguide/src/system/components/data-input/Input/demo.md
Normal file → Executable file
0
styleguide/src/system/components/data-input/Input/style.scss
Normal file → Executable file
248
styleguide/src/system/components/data-input/Select/Select.vue
Normal file → Executable file
@ -1,33 +1,119 @@
|
||||
<template>
|
||||
<ds-form-item>
|
||||
<div class="ds-select-wrap">
|
||||
<div
|
||||
class="ds-select-wrap"
|
||||
v-click-outside="handleBlur"
|
||||
:tabindex="searchable ? -1 : tabindex"
|
||||
@keydown.self.down.prevent="pointerNext"
|
||||
@keydown.self.up.prevent="pointerPrev"
|
||||
@keypress.enter.prevent.stop.self="selectPointerOption"
|
||||
@keyup.esc="close">
|
||||
<div
|
||||
v-if="icon"
|
||||
class="ds-select-icon">
|
||||
<ds-icon :name="icon"/>
|
||||
</div>
|
||||
<select
|
||||
<div
|
||||
class="ds-select"
|
||||
@click="handleClick"
|
||||
:class="[
|
||||
icon && `ds-select-has-icon`,
|
||||
iconRight && `ds-select-has-icon-right`
|
||||
]"
|
||||
:id="id"
|
||||
:name="model"
|
||||
:autofocus="autofocus"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:readonly="readonly"
|
||||
:value.prop="innerValue"
|
||||
@input="input"
|
||||
@focus="handleFocus"
|
||||
@blur="handleBlur">
|
||||
<option
|
||||
v-for="option in options"
|
||||
:key="option.label || option">
|
||||
{{ option.label || option }}
|
||||
</option>
|
||||
</select>
|
||||
iconRight && `ds-select-has-icon-right`,
|
||||
multiple && `ds-select-multiple`
|
||||
]">
|
||||
<div
|
||||
v-if="multiple"
|
||||
class="ds-selected-options">
|
||||
<div
|
||||
class="ds-selected-option"
|
||||
v-for="(value, index) in innerValue"
|
||||
:key="value">
|
||||
<!-- @slot Slot to provide a custom selected option display -->
|
||||
<slot
|
||||
name="optionitem"
|
||||
:value="value">
|
||||
<ds-chip
|
||||
removable
|
||||
@remove="deselectOption(index)"
|
||||
color="primary">
|
||||
{{ value }}
|
||||
</ds-chip>
|
||||
</slot>
|
||||
</div>
|
||||
<input
|
||||
ref="search"
|
||||
class="ds-select-search"
|
||||
:id="id"
|
||||
:name="model"
|
||||
:autofocus="autofocus"
|
||||
:placeholder="placeholder"
|
||||
:tabindex="tabindex"
|
||||
:disabled="disabled"
|
||||
:readonly="readonly"
|
||||
v-model="searchString"
|
||||
@focus="handleFocus"
|
||||
@keydown.delete.stop="deselectLastOption"
|
||||
@keydown.down.prevent="pointerNext"
|
||||
@keydown.up.prevent="pointerPrev"
|
||||
@keypress.enter.prevent.stop="selectPointerOption"
|
||||
@keyup.esc="close">
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="ds-select-value">
|
||||
<div
|
||||
v-if="placeholder && !innerValue"
|
||||
class="ds-select-placeholder">
|
||||
{{ placeholder }}
|
||||
</div>
|
||||
<!-- @slot Slot to provide a custom value display -->
|
||||
<slot
|
||||
v-else
|
||||
name="value"
|
||||
:value="innerValue">
|
||||
{{ innerValue }}
|
||||
</slot>
|
||||
</div>
|
||||
<input
|
||||
v-if="!multiple"
|
||||
ref="search"
|
||||
class="ds-select-search"
|
||||
:id="id"
|
||||
:name="model"
|
||||
:autofocus="autofocus"
|
||||
:placeholder="placeholder"
|
||||
:tabindex="tabindex"
|
||||
:disabled="disabled"
|
||||
:readonly="readonly"
|
||||
v-model="searchString"
|
||||
@focus="handleFocus"
|
||||
@keydown.delete.stop="deselectLastOption"
|
||||
@keydown.down.prevent="pointerNext"
|
||||
@keydown.up.prevent="pointerPrev"
|
||||
@keypress.enter.prevent.stop="selectPointerOption"
|
||||
@keyup.esc="close">
|
||||
</div>
|
||||
<div class="ds-select-dropdown">
|
||||
<ul class="ds-select-options">
|
||||
<li
|
||||
class="ds-select-option"
|
||||
:class="[
|
||||
isSelected(option) && `ds-select-option-is-selected`,
|
||||
pointer === index && `ds-select-option-hover`
|
||||
]"
|
||||
v-for="(option, index) in filteredOptions"
|
||||
@click="handleSelect(option)"
|
||||
@mouseover="setPointer(index)"
|
||||
:key="option.label || option">
|
||||
<!-- @slot Slot to provide custom option items -->
|
||||
<slot
|
||||
name="option"
|
||||
:option="option">
|
||||
{{ option.label || option }}
|
||||
</slot>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div
|
||||
v-if="iconRight"
|
||||
class="ds-select-icon-right">
|
||||
@ -39,6 +125,11 @@
|
||||
|
||||
<script>
|
||||
import inputMixin from '../shared/input'
|
||||
import multiinputMixin from '../shared/multiinput'
|
||||
import ClickOutside from 'vue-click-outside'
|
||||
import DsFormItem from '@@/components/data-input/FormItem/FormItem'
|
||||
import DsChip from '@@/components/typography/Chip/Chip'
|
||||
import DsIcon from '@@/components/typography/Icon/Icon'
|
||||
|
||||
/**
|
||||
* Used for handling basic user input.
|
||||
@ -46,7 +137,21 @@ import inputMixin from '../shared/input'
|
||||
*/
|
||||
export default {
|
||||
name: 'DsSelect',
|
||||
mixins: [inputMixin],
|
||||
mixins: [inputMixin, multiinputMixin],
|
||||
components: {
|
||||
DsFormItem,
|
||||
DsChip,
|
||||
DsIcon
|
||||
},
|
||||
directives: {
|
||||
ClickOutside
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchString: '',
|
||||
pointer: 0
|
||||
}
|
||||
},
|
||||
props: {
|
||||
/**
|
||||
* The placeholder shown when value is empty.
|
||||
@ -69,13 +174,6 @@ export default {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* Whether the user can select multiple items
|
||||
*/
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* The name of the input's icon.
|
||||
*/
|
||||
@ -88,7 +186,7 @@ export default {
|
||||
*/
|
||||
iconRight: {
|
||||
type: String,
|
||||
default: null
|
||||
default: 'angle-down'
|
||||
},
|
||||
/**
|
||||
* The select options.
|
||||
@ -98,6 +196,98 @@ export default {
|
||||
default() {
|
||||
return []
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Whether the options are searchable
|
||||
*/
|
||||
searchable: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
filteredOptions() {
|
||||
if (!this.searchString) {
|
||||
return this.options
|
||||
}
|
||||
const searchParts = this.searchString.split(' ')
|
||||
|
||||
return this.options.filter(option => {
|
||||
const value = option.value || option
|
||||
return searchParts.every(part => {
|
||||
if (!part) {
|
||||
return true
|
||||
}
|
||||
return value.toLowerCase().includes(part.toLowerCase())
|
||||
})
|
||||
})
|
||||
},
|
||||
pointerMax() {
|
||||
return this.filteredOptions.length - 1
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
pointerMax(max) {
|
||||
if (max < this.pointer) {
|
||||
this.$nextTick(() => {
|
||||
this.pointer = max
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleSelect(options) {
|
||||
this.selectOption(options)
|
||||
this.resetSearch()
|
||||
if (this.multiple) {
|
||||
this.$refs.search.focus()
|
||||
this.handleFocus()
|
||||
} else {
|
||||
this.close()
|
||||
}
|
||||
},
|
||||
resetSearch() {
|
||||
this.searchString = ''
|
||||
},
|
||||
handleClick() {
|
||||
if (!this.focus || this.multiple) {
|
||||
this.$refs.search.focus()
|
||||
this.handleFocus()
|
||||
}
|
||||
},
|
||||
close() {
|
||||
this.$refs.search.blur()
|
||||
this.handleBlur()
|
||||
},
|
||||
deselectLastOption() {
|
||||
if (
|
||||
this.multiple &&
|
||||
this.innerValue &&
|
||||
this.innerValue.length &&
|
||||
!this.searchString.length
|
||||
) {
|
||||
this.deselectOption(this.innerValue.length - 1)
|
||||
}
|
||||
},
|
||||
setPointer(index) {
|
||||
this.pointer = index
|
||||
},
|
||||
pointerPrev() {
|
||||
if (this.pointer === 0) {
|
||||
this.pointer = this.pointerMax
|
||||
} else {
|
||||
this.pointer--
|
||||
}
|
||||
},
|
||||
pointerNext() {
|
||||
if (this.pointer === this.pointerMax) {
|
||||
this.pointer = 0
|
||||
} else {
|
||||
this.pointer++
|
||||
}
|
||||
},
|
||||
selectPointerOption() {
|
||||
this.handleSelect(this.filteredOptions[this.pointer])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,69 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Select.vue matches snapshot 1`] = `
|
||||
<dsformitem-stub>
|
||||
<div
|
||||
class="ds-select-wrap"
|
||||
tabindex="-1"
|
||||
>
|
||||
<!---->
|
||||
|
||||
<div
|
||||
class="ds-select ds-select-has-icon-right"
|
||||
>
|
||||
<div
|
||||
class="ds-select-value"
|
||||
>
|
||||
|
||||
1
|
||||
|
||||
</div>
|
||||
|
||||
<input
|
||||
class="ds-select-search"
|
||||
tabindex="0"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="ds-select-dropdown"
|
||||
>
|
||||
<ul
|
||||
class="ds-select-options"
|
||||
>
|
||||
<li
|
||||
class="ds-select-option ds-select-option-is-selected ds-select-option-hover"
|
||||
>
|
||||
|
||||
1
|
||||
|
||||
</li>
|
||||
<li
|
||||
class="ds-select-option"
|
||||
>
|
||||
|
||||
2
|
||||
|
||||
</li>
|
||||
<li
|
||||
class="ds-select-option"
|
||||
>
|
||||
|
||||
3
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="ds-select-icon-right"
|
||||
>
|
||||
<dsicon-stub
|
||||
arialabel="icon"
|
||||
name="angle-down"
|
||||
tag="span"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</dsformitem-stub>
|
||||
`;
|
||||
154
styleguide/src/system/components/data-input/Select/demo.md
Normal file → Executable file
@ -2,4 +2,158 @@
|
||||
|
||||
```
|
||||
<ds-select :options="['blue', 'red', 'green']" />
|
||||
```
|
||||
|
||||
## Usage with label
|
||||
|
||||
```
|
||||
<ds-select
|
||||
label="Color"
|
||||
:options="['blue', 'red', 'green']" />
|
||||
```
|
||||
|
||||
## Bind to a value
|
||||
|
||||
Use v-model to bind a value to the select input.
|
||||
|
||||
```
|
||||
<template>
|
||||
<div>
|
||||
<ds-select
|
||||
v-model="color"
|
||||
:options="['blue', 'red', 'green']"
|
||||
placeholder="Color ..."></ds-select>
|
||||
<ds-text>Your color: {{ color }}</ds-text>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
color: 'blue'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## Multiselect
|
||||
|
||||
Use the multiple prop to allow the user selecting multiple values.
|
||||
|
||||
```
|
||||
<template>
|
||||
<div>
|
||||
<ds-select
|
||||
v-model="color"
|
||||
:options="['blue', 'red', 'green']"
|
||||
placeholder="Color ..."
|
||||
multiple></ds-select>
|
||||
<ds-text>Your colors: {{ color }}</ds-text>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
color: ['blue', 'red']
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## Options as objects
|
||||
|
||||
Options can be objects with a label and a value property.
|
||||
|
||||
```
|
||||
<template>
|
||||
<div>
|
||||
<ds-select
|
||||
v-model="color"
|
||||
:options="colorOptions"
|
||||
placeholder="Color ..."></ds-select>
|
||||
<ds-text>Your color: {{ color }}</ds-text>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
color: '',
|
||||
colorOptions: [
|
||||
{
|
||||
label: 'blue',
|
||||
value: '#0e17d8'
|
||||
},
|
||||
{
|
||||
label: 'red',
|
||||
value: '#d80e3f'
|
||||
},
|
||||
{
|
||||
label: 'green',
|
||||
value: '#0ed853'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
We use <a href="https://github.com/yiminghe/async-validator" targe="_blank">async-validator schemas</a> for validation.
|
||||
|
||||
If you need to validate more than one field it is better to use the form component.
|
||||
|
||||
```
|
||||
<template>
|
||||
<div>
|
||||
<ds-select
|
||||
v-model="color"
|
||||
:options="['blue', 'red', 'green']"
|
||||
:schema="{type: 'enum', enum: ['green'], message: 'Please choose green :)' }"
|
||||
placeholder="Color ..." />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
color: ''
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
|
||||
## Select sizes
|
||||
|
||||
```
|
||||
<ds-select placeholder="Small ..." size="small"></ds-select>
|
||||
<ds-select placeholder="Base ..."></ds-select>
|
||||
<ds-select placeholder="Large ..." size="large"></ds-select>
|
||||
```
|
||||
|
||||
## Select icons
|
||||
|
||||
Add an icon to help the user identify the select fields usage.
|
||||
|
||||
```
|
||||
<ds-select
|
||||
placeholder="User ..."
|
||||
icon="user"></ds-select>
|
||||
<ds-select
|
||||
placeholder="Day ..."
|
||||
icon="clock"></ds-select>
|
||||
<ds-select
|
||||
placeholder="User ..."
|
||||
size="small"
|
||||
icon="user"></ds-select>
|
||||
<ds-select
|
||||
placeholder="User ..."
|
||||
size="large"
|
||||
icon="user"></ds-select>
|
||||
```
|
||||
309
styleguide/src/system/components/data-input/Select/spec.js
Executable file
@ -0,0 +1,309 @@
|
||||
import { shallowMount } from '@vue/test-utils'
|
||||
import Comp from './Select.vue'
|
||||
|
||||
describe('Select.vue', () => {
|
||||
describe('Events emitting', () => {
|
||||
describe('@input', () => {
|
||||
test('should be called when the value is changed passing the new value', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
value: '3',
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
wrapper.vm.selectOption(wrapper.vm.options[0])
|
||||
expect(wrapper.emitted().input[0]).toEqual(['1'])
|
||||
})
|
||||
test('should be called when an option is clicked passing the options value', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
value: '3',
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
wrapper.find('.ds-select-option').trigger('click')
|
||||
expect(wrapper.emitted().input[0]).toEqual(['1'])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('innerValue', () => {
|
||||
test('should contain a single selected value by default', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
value: '1',
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
expect(wrapper.vm.innerValue).toEqual('1')
|
||||
})
|
||||
test('should contain an array of values when multiple: true', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
value: ['1'],
|
||||
options: ['1', '2', '3'],
|
||||
multiple: true
|
||||
}
|
||||
})
|
||||
expect(wrapper.vm.innerValue).toEqual(['1'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('options', () => {
|
||||
test('should highlight the selected value', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
value: '1',
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
const option = wrapper.find('.ds-select-option')
|
||||
expect(option.classes()).toContain('ds-select-option-is-selected')
|
||||
})
|
||||
test('should highlight all selected values when multiple: true', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
value: ['1', '2'],
|
||||
options: ['1', '2', '3'],
|
||||
multiple: true
|
||||
}
|
||||
})
|
||||
const option = wrapper.findAll('.ds-select-option')
|
||||
expect(option.at(0).classes()).toContain('ds-select-option-is-selected')
|
||||
expect(option.at(1).classes()).toContain('ds-select-option-is-selected')
|
||||
})
|
||||
})
|
||||
|
||||
describe('selectOption', () => {
|
||||
test('should set innerValue to selected value', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
value: '3',
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
wrapper.vm.selectOption(wrapper.vm.options[0])
|
||||
expect(wrapper.vm.innerValue).toEqual('1')
|
||||
})
|
||||
test('should add selected value to innerValue when multiple: true', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
value: ['3'],
|
||||
options: ['1', '2', '3'],
|
||||
multiple: true
|
||||
}
|
||||
})
|
||||
wrapper.vm.selectOption(wrapper.vm.options[0])
|
||||
expect(wrapper.vm.innerValue).toEqual(['3', '1'])
|
||||
})
|
||||
test('should toggle selected value in innerValue when multiple: true', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
value: ['3', '1'],
|
||||
options: ['1', '2', '3'],
|
||||
multiple: true
|
||||
}
|
||||
})
|
||||
wrapper.vm.selectOption(wrapper.vm.options[0])
|
||||
expect(wrapper.vm.innerValue).toEqual(['3'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('search', () => {
|
||||
test('should filter options by search string', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['cat', 'duck', 'dog']
|
||||
}
|
||||
})
|
||||
wrapper.vm.searchString = 'do'
|
||||
expect(wrapper.vm.filteredOptions).toEqual(['dog'])
|
||||
})
|
||||
|
||||
test('should be case insensitive', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['cat', 'duck', 'dog']
|
||||
}
|
||||
})
|
||||
wrapper.vm.searchString = 'DO'
|
||||
expect(wrapper.vm.filteredOptions).toEqual(['dog'])
|
||||
})
|
||||
|
||||
test('should ignore spaces', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['cat', 'duck', 'dog']
|
||||
}
|
||||
})
|
||||
wrapper.vm.searchString = 'd o'
|
||||
expect(wrapper.vm.filteredOptions).toEqual(['dog'])
|
||||
})
|
||||
|
||||
test('should display filtered options', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['cat', 'duck', 'dog']
|
||||
}
|
||||
})
|
||||
wrapper.vm.searchString = 'do'
|
||||
const filteredOptions = wrapper.findAll('.ds-select-option')
|
||||
expect(filteredOptions.length).toEqual(1)
|
||||
})
|
||||
|
||||
test('should work when using search input', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['cat', 'duck', 'dog']
|
||||
}
|
||||
})
|
||||
const searchInput = wrapper.find('.ds-select-search')
|
||||
searchInput.setValue('do')
|
||||
expect(wrapper.vm.filteredOptions).toEqual(['dog'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('pointer', () => {
|
||||
test('should be set by mouse over option', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
const options = wrapper.findAll('.ds-select-option')
|
||||
options.at(2).trigger('mouseover')
|
||||
expect(wrapper.vm.pointer).toEqual(2)
|
||||
})
|
||||
|
||||
test('should be set by pointerNext', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
wrapper.vm.pointerNext()
|
||||
expect(wrapper.vm.pointer).toEqual(1)
|
||||
})
|
||||
|
||||
test('should be set to 0 by pointerNext when on last entry', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
wrapper.vm.pointer = 2
|
||||
wrapper.vm.pointerNext()
|
||||
expect(wrapper.vm.pointer).toEqual(0)
|
||||
})
|
||||
|
||||
test('should be set by pointerPrev', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
wrapper.vm.pointer = 1
|
||||
wrapper.vm.pointerPrev()
|
||||
expect(wrapper.vm.pointer).toEqual(0)
|
||||
})
|
||||
|
||||
test('should be set to last entry by pointerPrev when 0', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
wrapper.vm.pointerPrev()
|
||||
expect(wrapper.vm.pointer).toEqual(2)
|
||||
})
|
||||
|
||||
test('should be set by key down on wrap', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
const wrap = wrapper.find('.ds-select-wrap')
|
||||
wrap.trigger('keydown.down')
|
||||
expect(wrapper.vm.pointer).toEqual(1)
|
||||
})
|
||||
|
||||
test('should be set by key up on wrap', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
const wrap = wrapper.find('.ds-select-wrap')
|
||||
wrap.trigger('keydown.up')
|
||||
expect(wrapper.vm.pointer).toEqual(2)
|
||||
})
|
||||
|
||||
test('should be set by key down on search input', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
const searchInput = wrapper.find('.ds-select-search')
|
||||
searchInput.trigger('keydown.down')
|
||||
expect(wrapper.vm.pointer).toEqual(1)
|
||||
})
|
||||
|
||||
test('should be set by key up on search input', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
const searchInput = wrapper.find('.ds-select-search')
|
||||
searchInput.trigger('keydown.up')
|
||||
expect(wrapper.vm.pointer).toEqual(2)
|
||||
})
|
||||
|
||||
test('should select option by pointer value', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
wrapper.vm.pointer = 1
|
||||
wrapper.vm.selectPointerOption()
|
||||
expect(wrapper.vm.innerValue).toEqual('2')
|
||||
})
|
||||
|
||||
test('should select option by enter key on wrap', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
wrapper.vm.pointer = 1
|
||||
const wrap = wrapper.find('.ds-select-wrap')
|
||||
wrap.trigger('keypress.enter')
|
||||
expect(wrapper.vm.innerValue).toEqual('2')
|
||||
})
|
||||
|
||||
test('should select option by enter key on search input', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
wrapper.vm.pointer = 1
|
||||
const searchInput = wrapper.find('.ds-select-search')
|
||||
searchInput.trigger('keypress.enter')
|
||||
expect(wrapper.vm.innerValue).toEqual('2')
|
||||
})
|
||||
})
|
||||
|
||||
it('matches snapshot', () => {
|
||||
const wrapper = shallowMount(Comp, {
|
||||
propsData: {
|
||||
value: '1',
|
||||
options: ['1', '2', '3']
|
||||
}
|
||||
})
|
||||
expect(wrapper.element).toMatchSnapshot()
|
||||
})
|
||||
})
|
||||
148
styleguide/src/system/components/data-input/Select/style.scss
Normal file → Executable file
@ -1,3 +1,149 @@
|
||||
@import '../shared/input.scss';
|
||||
|
||||
@include input(ds-select);
|
||||
@include input(ds-select);
|
||||
|
||||
.ds-select {
|
||||
user-select: none;
|
||||
.ds-input-has-focus & {
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-select-search, .ds-select-value {
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border: $input-border-size solid transparent;
|
||||
padding: $input-padding-vertical $space-x-small;
|
||||
line-height: $line-height-base;
|
||||
|
||||
.ds-input-size-small & {
|
||||
padding: $input-padding-vertical-small $space-x-small;
|
||||
}
|
||||
|
||||
.ds-input-size-large & {
|
||||
padding: $input-padding-vertical-large $space-x-small;
|
||||
}
|
||||
|
||||
.ds-select-has-icon & {
|
||||
padding-left: $input-height;
|
||||
|
||||
.ds-input-size-small & {
|
||||
padding-left: $input-height-small;
|
||||
}
|
||||
|
||||
.ds-input-size-large & {
|
||||
padding-left: $input-height-large;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-select-has-icon-right & {
|
||||
padding-right: $input-height;
|
||||
|
||||
.ds-input-size-small & {
|
||||
padding-right: $input-height-small;
|
||||
}
|
||||
|
||||
.ds-input-size-large & {
|
||||
padding-right: $input-height-large;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ds-select-search {
|
||||
appearance: none;
|
||||
font-size: inherit;
|
||||
font-family: $font-family-text;
|
||||
width: 100%;
|
||||
background: transparent;
|
||||
color: $text-color-base;
|
||||
outline: none;
|
||||
user-select: text;
|
||||
|
||||
opacity: 0;
|
||||
|
||||
&::placeholder {
|
||||
color: $text-color-disabled;
|
||||
}
|
||||
|
||||
.ds-input-has-focus & {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.ds-select-multiple & {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
width: auto;
|
||||
height: auto;
|
||||
padding: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-select-placeholder, .ds-select-value {
|
||||
pointer-events: none;
|
||||
|
||||
.ds-input-has-focus & {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-select-placeholder {
|
||||
color: $text-color-disabled;
|
||||
}
|
||||
|
||||
.ds-selected-options {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.ds-selected-option {
|
||||
display: inline-flex;
|
||||
margin-right: $space-xx-small;
|
||||
}
|
||||
|
||||
.ds-select-dropdown {
|
||||
position: absolute;
|
||||
z-index: $z-index-dropdown;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: $background-color-base;
|
||||
border: $input-border-size solid $border-color-active;
|
||||
border-top: 0;
|
||||
border-bottom-left-radius: $border-radius-base;
|
||||
border-bottom-right-radius: $border-radius-base;
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: all $duration-short $ease-out;
|
||||
max-height: 240px;
|
||||
overflow: auto;
|
||||
|
||||
.ds-input-has-focus & {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-select-options {
|
||||
@include reset-list;
|
||||
}
|
||||
|
||||
.ds-select-option {
|
||||
padding: $input-padding-vertical $space-x-small;
|
||||
cursor: pointer;
|
||||
transition: all $duration-short $ease-out;
|
||||
|
||||
&.ds-select-option-hover {
|
||||
background-color: $background-color-primary;
|
||||
color: $text-color-primary-inverse;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-select-option-is-selected {
|
||||
background-color: $background-color-soft;
|
||||
color: $text-color-primary;
|
||||
}
|
||||
|
||||
23
styleguide/src/system/components/data-input/shared/input.js
Normal file → Executable file
@ -20,7 +20,7 @@ export default {
|
||||
* The value of the input. Can be passed via v-model.
|
||||
*/
|
||||
value: {
|
||||
type: [String, Object, Number],
|
||||
type: [String, Object, Number, Array],
|
||||
default: null
|
||||
},
|
||||
/**
|
||||
@ -56,7 +56,7 @@ export default {
|
||||
*/
|
||||
schema: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
default: () => null
|
||||
},
|
||||
/**
|
||||
* The input's size.
|
||||
@ -68,6 +68,10 @@ export default {
|
||||
validator: value => {
|
||||
return value.match(/(small|base|large)/)
|
||||
}
|
||||
},
|
||||
tabindex: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@ -107,9 +111,13 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
input(event) {
|
||||
handleInput(event) {
|
||||
this.input(event.target.value)
|
||||
},
|
||||
input(value) {
|
||||
this.innerValue = value
|
||||
if (this.$parentForm) {
|
||||
this.$parentForm.update(this.model, event.target.value)
|
||||
this.$parentForm.update(this.model, value)
|
||||
} else {
|
||||
/**
|
||||
* Fires after user input.
|
||||
@ -117,8 +125,8 @@ export default {
|
||||
*
|
||||
* @event input
|
||||
*/
|
||||
this.$emit('input', event.target.value)
|
||||
this.validate(event.target.value)
|
||||
this.$emit('input', value)
|
||||
this.validate(value)
|
||||
}
|
||||
},
|
||||
handleFormUpdate(data, errors) {
|
||||
@ -126,6 +134,9 @@ export default {
|
||||
this.error = errors ? errors[this.model] : null
|
||||
},
|
||||
validate(value) {
|
||||
if (!this.schema) {
|
||||
return
|
||||
}
|
||||
const validator = new Schema({ input: this.schema })
|
||||
// Prevent validator from printing to console
|
||||
// eslint-disable-next-line
|
||||
|
||||
79
styleguide/src/system/components/data-input/shared/input.scss
Normal file → Executable file
@ -2,63 +2,67 @@
|
||||
.#{$class}-wrap {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
.#{$class} {
|
||||
appearance: none;
|
||||
box-sizing: border-box;
|
||||
font-size: $font-size-base;
|
||||
font-size: $input-font-size-base;
|
||||
line-height: $line-height-base;
|
||||
font-family: $font-family-text;
|
||||
width: 100%;
|
||||
padding: $input-padding-vertical $space-x-small;
|
||||
height: $input-height;
|
||||
|
||||
|
||||
color: $text-color-base;
|
||||
background: $background-color-base;
|
||||
|
||||
border: $input-border-size solid $border-color-soft;
|
||||
|
||||
border: $input-border-size solid $border-color-base;
|
||||
border-radius: $border-radius-base;
|
||||
outline: none;
|
||||
transition: all $duration-short $ease-out;
|
||||
|
||||
|
||||
&::placeholder {
|
||||
color: $text-color-disabled;
|
||||
}
|
||||
|
||||
|
||||
.ds-input-has-focus &,
|
||||
&:focus {
|
||||
border-color: $border-color-active;
|
||||
background: $background-color-base;
|
||||
}
|
||||
|
||||
.#{$class}-is-disabled &,
|
||||
|
||||
.ds-input-is-disabled &,
|
||||
&:disabled {
|
||||
color: $text-color-disabled;
|
||||
opacity: $opacity-disabled;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.#{$class}-has-error & {
|
||||
|
||||
.ds-input-has-error & {
|
||||
border-color: $border-color-danger;
|
||||
}
|
||||
}
|
||||
|
||||
.#{$class}-size-small {
|
||||
|
||||
.ds-input-size-small {
|
||||
font-size: $font-size-small;
|
||||
|
||||
|
||||
.#{$class} {
|
||||
font-size: $input-font-size-small;
|
||||
height: $input-height-small;
|
||||
padding: $input-padding-vertical-small $space-x-small;
|
||||
}
|
||||
}
|
||||
|
||||
.#{$class}-size-large {
|
||||
|
||||
.ds-input-size-large {
|
||||
font-size: $font-size-large;
|
||||
|
||||
|
||||
.#{$class} {
|
||||
font-size: $input-font-size-large;
|
||||
height: $input-height-large;
|
||||
padding: $input-padding-vertical-large $space-x-small;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.#{$class}-icon,
|
||||
.#{$class}-icon-right {
|
||||
position: absolute;
|
||||
@ -71,32 +75,47 @@
|
||||
width: $input-height;
|
||||
color: $text-color-softer;
|
||||
transition: color $duration-short $ease-out;
|
||||
|
||||
.#{$class}-has-focus & {
|
||||
pointer-events: none;
|
||||
|
||||
.ds-input-has-focus & {
|
||||
color: $text-color-base;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-input-size-small & {
|
||||
width: $input-height-small;
|
||||
}
|
||||
|
||||
.ds-input-size-large & {
|
||||
width: $input-height-large;
|
||||
}
|
||||
}
|
||||
|
||||
.#{$class}-icon-right {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
|
||||
.#{$class}-has-icon {
|
||||
padding-left: $input-height;
|
||||
|
||||
.ds-input-size-small & {
|
||||
padding-left: $input-height-small;
|
||||
}
|
||||
|
||||
.#{$class}-size-small &,
|
||||
.#{$class}-size-large & {
|
||||
padding-left: $input-height;
|
||||
.ds-input-size-large & {
|
||||
padding-left: $input-height-large;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.#{$class}-has-icon-right {
|
||||
padding-right: $input-height;
|
||||
|
||||
.#{$class}-size-small &,
|
||||
.#{$class}-size-large & {
|
||||
padding-right: $input-height;
|
||||
.ds-input-size-small & {
|
||||
padding-right: $input-height-small;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-input-size-large & {
|
||||
padding-right: $input-height-large;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
49
styleguide/src/system/components/data-input/shared/multiinput.js
Executable file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @mixin
|
||||
*/
|
||||
export default {
|
||||
props: {
|
||||
/**
|
||||
* Whether the user can select multiple items
|
||||
*/
|
||||
multiple: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
selectOption(option) {
|
||||
const newValue = option.value || option
|
||||
if (this.multiple) {
|
||||
this.selectMultiOption(newValue)
|
||||
} else {
|
||||
this.input(newValue)
|
||||
}
|
||||
},
|
||||
selectMultiOption(value) {
|
||||
if (!this.innerValue) {
|
||||
return this.input([value])
|
||||
}
|
||||
const index = this.innerValue.indexOf(value)
|
||||
if (index < 0) {
|
||||
return this.input([...this.innerValue, value])
|
||||
}
|
||||
this.deselectOption(index)
|
||||
},
|
||||
deselectOption(index) {
|
||||
const newArray = [...this.innerValue]
|
||||
newArray.splice(index, 1)
|
||||
this.input(newArray)
|
||||
},
|
||||
isSelected(option) {
|
||||
if (!this.innerValue) {
|
||||
return false
|
||||
}
|
||||
const value = option.value || option
|
||||
if (this.multiple) {
|
||||
return this.innerValue.includes(value)
|
||||
}
|
||||
return this.innerValue === value
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,9 +14,9 @@
|
||||
v-if="image || $slots.image">
|
||||
<!-- @slot Content of the card's image -->
|
||||
<slot name="image">
|
||||
<img
|
||||
:src="image"
|
||||
v-if="!error"
|
||||
<img
|
||||
:src="image"
|
||||
v-if="!error"
|
||||
@error="onError" >
|
||||
</slot>
|
||||
</div>
|
||||
@ -36,7 +36,14 @@
|
||||
</slot>
|
||||
</header>
|
||||
<div class="ds-card-content">
|
||||
<slot />
|
||||
<template v-if="space">
|
||||
<ds-space :margin="space">
|
||||
<slot />
|
||||
</ds-space>
|
||||
</template>
|
||||
<template v-else>
|
||||
<slot />
|
||||
</template>
|
||||
</div>
|
||||
<footer
|
||||
class="ds-card-footer"
|
||||
@ -125,6 +132,14 @@ export default {
|
||||
hover: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* If you need some spacing you can provide it here like for ds-space
|
||||
* `xxx-small, xx-small, x-small, small, large, x-large, xx-large, xxx-large`
|
||||
*/
|
||||
space: {
|
||||
type: String,
|
||||
default: null
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
||||
@ -21,6 +21,23 @@ Set a header and image for the card and provide some content.
|
||||
</ds-flex>
|
||||
```
|
||||
|
||||
## Space
|
||||
|
||||
Need more or less space top and bottom of the card?
|
||||
Specify with with the `space` prop
|
||||
|
||||
```html
|
||||
<ds-card space="xx-small">
|
||||
xx-small
|
||||
</ds-card>
|
||||
```
|
||||
|
||||
```html
|
||||
<ds-card space="xx-large">
|
||||
xx-large
|
||||
</ds-card>
|
||||
```
|
||||
|
||||
## Cards with footer
|
||||
|
||||
Most commonly the footer will contain some actions connected to the content.
|
||||
|
||||
93
styleguide/src/system/components/typography/Chip/Chip.vue
Executable file
@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<component
|
||||
:is="tag"
|
||||
class="ds-chip"
|
||||
:class="[
|
||||
`ds-chip-size-${size}`,
|
||||
`ds-chip-${color}`,
|
||||
removable && 'ds-chip-removable',
|
||||
round && 'ds-chip-round'
|
||||
]"
|
||||
>
|
||||
<slot />
|
||||
<button
|
||||
v-if="removable"
|
||||
@click="remove"
|
||||
class="ds-chip-close">
|
||||
<ds-icon name="close" />
|
||||
</button>
|
||||
</component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
* Chips are used to represent small blocks of information.
|
||||
* Their most common usage is for displaying contacts or tags.
|
||||
* @version 1.0.0
|
||||
*/
|
||||
export default {
|
||||
name: 'DsChip',
|
||||
props: {
|
||||
/**
|
||||
* The background color used for the chip.
|
||||
* `medium, inverse, primary, success, warning, danger`
|
||||
*/
|
||||
color: {
|
||||
type: String,
|
||||
default: 'medium',
|
||||
validator: value => {
|
||||
return value.match(/(medium|inverse|primary|success|warning|danger)/)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The size used for the text.
|
||||
* `base, large, small`
|
||||
*/
|
||||
size: {
|
||||
type: String,
|
||||
default: 'base',
|
||||
validator: value => {
|
||||
return value.match(/(base|large|small)/)
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Whether the chip should be removeable
|
||||
* `true, false`
|
||||
*/
|
||||
removable: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
/**
|
||||
* Whether the chip should be rounded
|
||||
* `true, false`
|
||||
*/
|
||||
round: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
/**
|
||||
* The html element name used for the text.
|
||||
*/
|
||||
tag: {
|
||||
type: String,
|
||||
default: 'span'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
remove() {
|
||||
/**
|
||||
* Fires after user clicked the remove button.
|
||||
*
|
||||
* @event remove
|
||||
*/
|
||||
this.$emit('remove')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" src="./style.scss">
|
||||
</style>
|
||||
|
||||
<docs src="./demo.md"></docs>
|
||||
62
styleguide/src/system/components/typography/Chip/demo.md
Executable file
@ -0,0 +1,62 @@
|
||||
## Chip colors
|
||||
|
||||
Use different colors to emphasize or provide meaning.
|
||||
|
||||
```
|
||||
<ds-chip>Medium</ds-chip>
|
||||
<ds-chip color="inverse">Inverse</ds-chip>
|
||||
<ds-chip color="primary">Primary</ds-chip>
|
||||
<ds-chip color="success">Success</ds-chip>
|
||||
<ds-chip color="warning">Warning</ds-chip>
|
||||
<ds-chip color="danger">Danger</ds-chip>
|
||||
```
|
||||
|
||||
## Chip sizes
|
||||
|
||||
Use different sizes to create hierarchy (defaults to `base`).
|
||||
|
||||
```
|
||||
<ds-chip size="small">Small</ds-chip>
|
||||
<ds-chip size="base">Base</ds-chip>
|
||||
<ds-chip size="large">Large</ds-chip>
|
||||
```
|
||||
|
||||
## Deletable
|
||||
|
||||
A chip can be deletable.
|
||||
|
||||
```
|
||||
<template>
|
||||
<div>
|
||||
<ds-chip
|
||||
v-for="(tag, index) in tags"
|
||||
@remove="removeTag(index)"
|
||||
removable
|
||||
:key="tag">
|
||||
{{ tag }}
|
||||
</ds-chip>
|
||||
<ds-chip
|
||||
v-for="(tag, index) in tags"
|
||||
@remove="removeTag(index)"
|
||||
removable
|
||||
color="primary"
|
||||
:key="tag">
|
||||
{{ tag }}
|
||||
</ds-chip>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tags: ['Dog', 'Cat', 'Duck']
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
removeTag (index) {
|
||||
this.tags.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
```
|
||||
81
styleguide/src/system/components/typography/Chip/style.scss
Executable file
@ -0,0 +1,81 @@
|
||||
.ds-chip {
|
||||
@include reset;
|
||||
@include stack-space($space-xx-small);
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
font-family: $font-family-text;
|
||||
line-height: $line-height-base;
|
||||
padding: $space-xx-small $space-x-small;
|
||||
border-radius: $border-radius-base;
|
||||
font-weight: $font-weight-bold;
|
||||
color: $text-color-base;
|
||||
background-color: $background-color-softest;
|
||||
|
||||
&.ds-chip-removable {
|
||||
padding-right: $space-x-small + $space-small;
|
||||
}
|
||||
}
|
||||
|
||||
.ds-chip-inverse {
|
||||
color: $text-color-inverse;
|
||||
background-color: $background-color-inverse-softer;
|
||||
}
|
||||
|
||||
.ds-chip-primary {
|
||||
color: $text-color-primary-inverse;
|
||||
background-color: $background-color-primary;
|
||||
}
|
||||
|
||||
.ds-chip-success {
|
||||
color: $text-color-success-inverse;
|
||||
background-color: $background-color-success;
|
||||
}
|
||||
|
||||
.ds-chip-warning {
|
||||
color: $text-color-warning-inverse;
|
||||
background-color: $background-color-warning;
|
||||
}
|
||||
|
||||
.ds-chip-danger {
|
||||
color: $text-color-danger-inverse;
|
||||
background-color: $background-color-danger;
|
||||
}
|
||||
|
||||
.ds-chip-round {
|
||||
border-radius: $border-radius-rounded;
|
||||
}
|
||||
|
||||
.ds-chip-size-base {
|
||||
font-size: $font-size-small;
|
||||
}
|
||||
|
||||
.ds-chip-size-small {
|
||||
font-size: $font-size-x-small;
|
||||
}
|
||||
|
||||
.ds-chip-size-large {
|
||||
font-size: $font-size-base;
|
||||
}
|
||||
|
||||
.ds-chip-close {
|
||||
@include reset-button;
|
||||
position: absolute;
|
||||
right: $space-xx-small;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: $font-size-x-small;
|
||||
width: $space-small;
|
||||
height: $space-small;
|
||||
border-radius: $border-radius-circle;
|
||||
//background-color: $background-color-base;
|
||||
opacity: $opacity-soft;
|
||||
cursor: pointer;
|
||||
transition: all $duration-short $ease-out-sharp;
|
||||
|
||||
&:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,7 @@
|
||||
:is="tag"
|
||||
:aria-label="ariaLabel"
|
||||
class="ds-icon"
|
||||
:class="[size && `ds-icon-size-${size}`]"
|
||||
>
|
||||
<component
|
||||
v-if="svgComponent"
|
||||
@ -40,6 +41,19 @@ export default {
|
||||
tag: {
|
||||
type: String,
|
||||
default: 'span'
|
||||
},
|
||||
/**
|
||||
* Which size should the icon have?
|
||||
* `xx-small, x-small, small, base, large, x-large, xx-large, xxx-large`
|
||||
*/
|
||||
size: {
|
||||
type: String,
|
||||
default: null,
|
||||
validator: value => {
|
||||
return value.match(
|
||||
/(xx-small|x-small|small|base|large|x-large|xx-large|xxx-large)/
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
@ -17,4 +17,29 @@
|
||||
// overflow: visible;
|
||||
// Use this if the icons are build with solids
|
||||
fill: currentColor
|
||||
}
|
||||
}
|
||||
|
||||
.ds-icon-size-xx-small {
|
||||
font-size: $font-size-xx-small
|
||||
}
|
||||
.ds-icon-size-x-small {
|
||||
font-size: $font-size-x-small
|
||||
}
|
||||
.ds-icon-size-small {
|
||||
font-size: $font-size-small
|
||||
}
|
||||
.ds-icon-size-base {
|
||||
font-size: $font-size-base
|
||||
}
|
||||
.ds-icon-size-large {
|
||||
font-size: $font-size-large
|
||||
}
|
||||
.ds-icon-size-x-large {
|
||||
font-size: $font-size-x-large
|
||||
}
|
||||
.ds-icon-size-xx-large {
|
||||
font-size: $font-size-xx-large
|
||||
}
|
||||
.ds-icon-size-xxx-large {
|
||||
font-size: $font-size-xxx-large
|
||||
}
|
||||
|
||||
5
styleguide/src/system/icons/svg/angellist.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>angellist</title>
|
||||
<path d="M12.813 4c0.312 0.021 0.615 0.118 0.875 0.25 0.521 0.265 0.919 0.67 1.281 1.125 0.725 0.91 1.311 2.103 1.813 3.313 0.207 0.498 0.39 0.985 0.563 1.469 0.109-0.401 0.21-0.808 0.344-1.219 0.391-1.201 0.902-2.395 1.594-3.344 0.346-0.474 0.731-0.895 1.25-1.188s1.174-0.421 1.813-0.281c0.628 0.138 1.091 0.677 1.281 1.156s0.24 0.97 0.25 1.5c0.020 1.060-0.168 2.29-0.406 3.5-0.385 1.96-0.863 3.535-1.063 4.188 0.328 0.248 0.624 0.516 0.844 0.813 1.025 1.382 0.75 3.010 0.75 3.375 0 4.219-1.55 6.731-3.406 8s-3.874 1.344-4.75 1.344c-0.805 0-2.922 0.024-4.938-0.906s-3.906-3.011-3.906-6.563c0-1.078 0.261-1.996 0.906-2.625 0.403-0.392 0.929-0.57 1.469-0.625-0.205-0.548-0.361-1.162-0.281-1.844 0.089-0.757 0.563-1.558 1.344-2.063 0.319-0.206 0.672-0.326 1.031-0.344 0.169-0.008 0.336 0.001 0.5 0.031-0.273-0.768-0.577-1.665-0.844-2.625-0.325-1.173-0.597-2.383-0.625-3.469-0.014-0.543 0.037-1.059 0.219-1.563s0.577-1.017 1.156-1.25c0.303-0.122 0.625-0.177 0.938-0.156zM12.656 5.969c-0.013-0.002-0.018 0.026-0.031 0.031 0.004 0.007-0.006 0.024-0.031 0.094-0.051 0.14-0.104 0.453-0.094 0.844 0.020 0.781 0.229 1.879 0.531 2.969 0.497 1.791 1.081 3.25 1.313 3.813 0.442-0.431 1.082-0.719 1.781-0.719h0.063c-0.255-0.9-0.658-2.135-1.25-3.563-0.465-1.121-1.026-2.178-1.531-2.813-0.253-0.317-0.492-0.526-0.625-0.594-0.066-0.034-0.103-0.060-0.125-0.063zM21.656 6.125c-0.047-0-0.102 0.001-0.156 0.031-0.168 0.095-0.391 0.304-0.625 0.625-0.468 0.641-0.925 1.687-1.281 2.781-0.488 1.498-0.754 2.761-0.906 3.594 0.721 0.094 1.355 0.232 1.906 0.406 0.238-0.82 0.595-2.103 0.906-3.688 0.224-1.139 0.39-2.277 0.375-3.063-0.006-0.332-0.054-0.548-0.094-0.688-0.040 0.001-0.078 0-0.125 0zM16.125 15c-0.248 0-0.319 0.061-0.406 0.156s-0.169 0.254-0.188 0.469c-0.015 0.179 0.007 0.355 0.063 0.5 0.046 0.070 0.080 0.147 0.125 0.219 0.020 0.024 0.040 0.042 0.063 0.063 0.062 0.056 0.14 0.102 0.219 0.125 1.258 0.369 2.844 0.844 2.844 0.844 0.399 0.115 0.723 0.546 0.723 0.961 0 0.444-0.352 0.881-0.785 0.977 0 0-0.565 0.117-1.125 0.469-0.348 0.218-0.665 0.461-0.844 0.813-0.109 0.214-0.156 0.468-0.156 0.781 0 0.866 0.241 1.414 0.469 1.75s0.375 0.406 0.375 0.406l-1.094 1.656s-0.515-0.316-0.938-0.938c-0.189-0.278-0.354-0.651-0.5-1.063-0.079 0.184-0.099 0.39-0.219 0.531-0.466 0.55-1.139 0.906-1.906 0.906-0.74 0-1.409-0.369-1.906-0.813s-0.89-0.987-1.281-1.594l1.688-1.094c0.346 0.537 0.672 0.982 0.938 1.219s0.412 0.281 0.563 0.281c0.124 0 0.312-0.113 0.375-0.188-0.216-0.366-0.428-0.696-0.656-1-0.988-1.312-2.049-2.044-2.656-2.188-0.376-0.089-0.483-0.046-0.594 0.063s-0.313 0.471-0.313 1.219c0 2.907 1.245 4.056 2.75 4.75s3.296 0.719 4.094 0.719c0.727 0 2.304-0.097 3.625-1s2.531-2.589 2.531-6.344c0-0.822 0.143-1.5-0.344-2.156s-1.846-1.5-5.531-1.5zM11.5 15.031c-0.34 0.22-0.376 0.367-0.406 0.625s0.025 0.662 0.188 1.063c0.324 0.802 0.938 1.531 0.938 1.531 0.663 0.506 1.276 1.177 1.875 2l0.063-0.031c-0.196-0.257-0.218-0.129-0.063-0.125s0.414-0.041 0.594-0.125 0.279-0.181 0.313-0.25 0.064-0.147-0.063-0.469c-0.536-1.37-1.376-2.666-2.156-3.438-0.39-0.386-0.765-0.63-1-0.719s-0.239-0.090-0.281-0.063z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
5
styleguide/src/system/icons/svg/balance-scale.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>balance-scale</title>
|
||||
<path d="M16 5c1.292 0 2.394 0.844 2.813 2h7.188v2h-1.406l0.281 0.5 4 7 0.125 0.25v0.25c0 2.75-2.25 5-5 5s-5-2.25-5-5v-0.25l0.125-0.25 4-7 0.281-0.5h-4.594c-0.304 0.84-0.973 1.509-1.813 1.813v13.188h4v2h-10v-2h4v-13.188c-0.842-0.304-1.507-0.969-1.813-1.813h-4.594l0.281 0.5 4 7 0.125 0.25v0.25c0 2.75-2.251 5-5 5s-5-2.25-5-5v-0.25l0.125-0.25 4-7 0.281-0.5h-1.406v-2h7.188c0.418-1.156 1.521-2 2.813-2zM16 7c-0.564 0-1 0.436-1 1s0.436 1 1 1 1-0.436 1-1-0.436-1-1-1zM8 12.031l-2.281 3.969h4.563zM24 12.031l-2.281 3.969h4.563zM5.25 18c0.402 1.161 1.444 2 2.75 2s2.348-0.839 2.75-2h-5.5zM21.25 18c0.402 1.161 1.444 2 2.75 2s2.348-0.839 2.75-2h-5.5z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 820 B |
5
styleguide/src/system/icons/svg/bell.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>bell</title>
|
||||
<path d="M15 3c1.105 0 2 0.895 2 2 0 0.085-0.021 0.168-0.031 0.25 3.521 0.924 6.031 4.273 6.031 8.031v8.719c0 0.565 0.435 1 1 1h1v2h-7.188c0.114 0.316 0.188 0.647 0.188 1 0 1.645-1.355 3-3 3s-3-1.355-3-3c0-0.353 0.073-0.684 0.188-1h-7.188v-2h1c0.565 0 1-0.435 1-1v-9c0-3.726 2.574-6.866 6.031-7.75-0.010-0.082-0.031-0.165-0.031-0.25 0-1.105 0.895-2 2-2zM14.563 7c-3.118 0.226-5.563 2.824-5.563 6v9c0 0.353-0.073 0.684-0.188 1h12.375c-0.114-0.316-0.188-0.647-0.188-1v-8.719c0-3.319-2.546-6.183-5.813-6.281-0.064-0.002-0.124-0-0.188 0-0.148 0-0.292-0.011-0.438 0zM15 25c-0.564 0-1 0.436-1 1s0.436 1 1 1 1-0.436 1-1-0.436-1-1-1z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 793 B |
5
styleguide/src/system/icons/svg/bullhorn.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>bullhorn</title>
|
||||
<path d="M28 3.031v9.156c1.156 0.418 2 1.521 2 2.813s-0.844 2.394-2 2.813v9.156l-1.594-1.156s-2.007-1.443-4.875-2.906-6.587-2.906-9.813-2.906h-3.375l1.625 5.719 0.344 1.281h-6.063l-0.219-0.719-2-7-0.031-0.156v-9.125h9.719c3.27 0 6.987-1.412 9.844-2.875s4.844-2.938 4.844-2.938zM26 6.75c-0.82 0.558-1.459 1.064-3.531 2.125-2.929 1.5-6.726 3.050-10.469 3.125v6c3.708 0.073 7.499 1.595 10.438 3.094 2.078 1.060 2.735 1.567 3.563 2.125v-16.469zM4 12v6h6v-6h-6zM4.344 20l1.406 5h1.906l-1.406-5h-1.906z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 668 B |
5
styleguide/src/system/icons/svg/gamepad.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>gamepad</title>
|
||||
<path d="M16 7c6.383 0 11.969 2.063 11.969 2.063l0.594 0.219 0.063 0.594 1.344 10.25c0.365 2.835-1.665 5.479-4.5 5.844-2.639 0.34-5.005-1.44-5.625-3.969h-7.688c-0.619 2.529-2.985 4.309-5.625 3.969-2.835-0.365-4.865-3.009-4.5-5.844l1.344-10.25 0.063-0.594 0.594-0.219s5.586-2.063 11.969-2.063zM16 9c-5.486 0-10.007 1.524-10.75 1.781l-1.219 9.625c-0.227 1.763 0.987 3.335 2.75 3.563s3.368-0.987 3.594-2.75l0.031-0.344 0.125-0.875h10.938l0.125 0.875 0.031 0.344c0.227 1.763 1.832 2.977 3.594 2.75 1.763-0.227 2.977-1.8 2.75-3.563l-1.219-9.625c-0.743-0.258-5.264-1.781-10.75-1.781zM9 12h2v2h2v2h-2v2h-2v-2h-2v-2h2v-2zM22 12c0.552 0 1 0.448 1 1s-0.448 1-1 1-1-0.448-1-1 0.448-1 1-1zM20 14c0.552 0 1 0.448 1 1s-0.448 1-1 1-1-0.448-1-1 0.448-1 1-1zM24 14c0.552 0 1 0.448 1 1s-0.448 1-1 1-1-0.448-1-1 0.448-1 1-1zM22 16c0.552 0 1 0.448 1 1s-0.448 1-1 1-1-0.448-1-1 0.448-1 1-1z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
5
styleguide/src/system/icons/svg/graduation-cap.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>graduation-cap</title>
|
||||
<path d="M16 6.781l0.313 0.094 15.344 5.125-2.844 0.938-2.813 0.938v5.125c0 0.82-0.499 1.5-1.094 1.969s-1.332 0.798-2.219 1.094c-1.773 0.591-4.112 0.938-6.688 0.938s-4.914-0.346-6.688-0.938c-0.887-0.296-1.624-0.625-2.219-1.094s-1.094-1.149-1.094-1.969v-5.125l-2-0.656v8.063c0.597 0.346 1 0.979 1 1.719 0 1.105-0.895 2-2 2s-2-0.895-2-2c0-0.74 0.403-1.373 1-1.719v-8.75l-1.656-0.531 2.844-0.938 12.5-4.188zM16 8.875l-9.375 3.125 9.375 3.125 9.375-3.125zM8 14.563v4.438c0 0.009-0.004 0.126 0.313 0.375s0.883 0.565 1.625 0.813c1.484 0.495 3.667 0.813 6.063 0.813s4.579-0.318 6.063-0.813c0.742-0.247 1.309-0.563 1.625-0.813s0.313-0.366 0.313-0.375v-4.438l-7.688 2.563-0.313 0.094-0.313-0.094z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 865 B |
5
styleguide/src/system/icons/svg/leaf.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>leaf</title>
|
||||
<path d="M25.031 4l0.313 1.094s1.656 5.616 1.656 13.438c0 3.995-0.921 6.637-2.344 8.281s-3.306 2.188-4.844 2.188c-1.728 0-3.206-0.784-4.375-1.594s-2.165-1.731-2.344-1.844l1.063-1.688c0.704 0.445 1.398 1.177 2.406 1.875s2.173 1.25 3.25 1.25c1.083 0 2.301-0.33 3.313-1.5s1.875-3.282 1.875-6.969c0-6.501-1.022-10.659-1.344-11.875-3.442 1.276-7.451 1.856-10.688 3-1.789 0.632-3.284 1.437-4.313 2.563s-1.656 2.577-1.656 4.781c0 1.938 1.058 3.143 2.219 3.969 0.603 0.429 1.187 0.698 1.625 0.875 1.72-2.744 4.356-6.157 8.438-10.531l1.438 1.375c-6.808 7.295-9.428 11.855-10.375 14.625-0.473 1.385-0.53 2.32-0.5 3s0.217 1.058 0.156 1.781l-2-0.188c-0.002 0.020-0.116-0.597-0.156-1.5s0.047-2.151 0.594-3.75c0.303-0.885 0.756-1.918 1.375-3.063-0.512-0.228-1.12-0.551-1.75-1-1.477-1.051-3.063-2.897-3.063-5.594 0-2.605 0.833-4.643 2.188-6.125s3.168-2.402 5.125-3.094c3.913-1.384 8.509-1.908 11.688-3.313z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
5
styleguide/src/system/icons/svg/mouse-pointer.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>mouse-pointer</title>
|
||||
<path d="M9 2.594l1.719 1.688 16.125 16.156-7.094 0.875 1.844 3.625 0.438 0.906-0.875 0.438-4 2.063-0.438-0.906-2.031-4.031-4.031 3.375-1.656 1.375v-25.563zM11 7.438v16.406l4.313-3.625 0.594 1.125 2.156 4.313 1.313-0.688-2.063-4-0.656-1.281 1.406-0.188 4.5-0.531z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 440 B |
5
styleguide/src/system/icons/svg/paint-brush.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>paint-brush</title>
|
||||
<path d="M24.813 4.031c0.837 0 1.648 0.335 2.281 0.969 1.267 1.267 1.267 3.327 0 4.594v0.031l-12.688 12.5-0.5 0.469c-0.124 0.793-0.46 1.572-1.063 2.188l-0.031 0.031c-1.318 1.318-3.898 3.188-7.813 3.188h-1.844l1-1.563c0.967-1.474 1.37-2.804 1.688-4s0.479-2.31 1.313-3.219c0.565-0.616 1.282-0.985 2.031-1.125l0.625-0.594 12.688-12.5c0.633-0.633 1.476-0.969 2.313-0.969zM24.813 6c-0.313 0-0.64 0.14-0.906 0.406l-9.063 8.906 1.813 1.813 9.031-8.938c0.533-0.533 0.533-1.248 0-1.781-0.267-0.267-0.562-0.406-0.875-0.406zM13.406 16.719l-1.5 1.469 1.813 1.813 1.5-1.469zM9.969 20.031c-0.506-0.014-0.997 0.153-1.344 0.531-0.267 0.291-0.511 1.152-0.844 2.406-0.216 0.814-0.55 1.794-1.031 2.844 2.249-0.421 3.787-1.537 4.656-2.406 0.827-0.827 0.808-2.069 0.031-2.781-0.417-0.383-0.963-0.579-1.469-0.594z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 966 B |
5
styleguide/src/system/icons/svg/paw.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>paw</title>
|
||||
<path d="M12.5 5c1.069 0 2.002 0.608 2.594 1.438s0.906 1.903 0.906 3.063-0.314 2.233-0.906 3.063-1.525 1.438-2.594 1.438-2.002-0.608-2.594-1.438-0.906-1.903-0.906-3.063 0.314-2.233 0.906-3.063 1.525-1.438 2.594-1.438zM16 9.5c0-1.159 0.314-2.233 0.906-3.063s1.525-1.438 2.594-1.438 2.002 0.608 2.594 1.438 0.906 1.903 0.906 3.063-0.314 2.233-0.906 3.063-1.525 1.438-2.594 1.438-2.002-0.608-2.594-1.438-0.906-1.903-0.906-3.063zM12.5 7c-0.312 0-0.656 0.156-0.969 0.594s-0.531 1.133-0.531 1.906 0.219 1.469 0.531 1.906 0.657 0.594 0.969 0.594 0.656-0.156 0.969-0.594 0.531-1.133 0.531-1.906-0.219-1.469-0.531-1.906-0.657-0.594-0.969-0.594zM19.5 7c-0.312 0-0.656 0.156-0.969 0.594s-0.531 1.133-0.531 1.906 0.219 1.469 0.531 1.906 0.657 0.594 0.969 0.594 0.656-0.156 0.969-0.594 0.531-1.133 0.531-1.906-0.219-1.469-0.531-1.906-0.657-0.594-0.969-0.594zM7.5 12c1.069 0 2.002 0.608 2.594 1.438s0.906 1.903 0.906 3.063-0.314 2.233-0.906 3.063-1.525 1.438-2.594 1.438-2.002-0.608-2.594-1.438-0.906-1.903-0.906-3.063 0.314-2.233 0.906-3.063 1.525-1.438 2.594-1.438zM24.5 12c1.069 0 2.002 0.608 2.594 1.438s0.906 1.903 0.906 3.063-0.314 2.233-0.906 3.063-1.525 1.438-2.594 1.438-2.002-0.608-2.594-1.438-0.906-1.903-0.906-3.063 0.314-2.233 0.906-3.063 1.525-1.438 2.594-1.438zM7.5 14c-0.312 0-0.656 0.156-0.969 0.594s-0.531 1.133-0.531 1.906 0.219 1.469 0.531 1.906 0.657 0.594 0.969 0.594 0.656-0.156 0.969-0.594 0.531-1.133 0.531-1.906-0.219-1.469-0.531-1.906-0.657-0.594-0.969-0.594zM24.5 14c-0.312 0-0.656 0.156-0.969 0.594s-0.531 1.133-0.531 1.906 0.219 1.469 0.531 1.906 0.657 0.594 0.969 0.594 0.656-0.156 0.969-0.594 0.531-1.133 0.531-1.906-0.219-1.469-0.531-1.906-0.657-0.594-0.969-0.594zM16 16c1.339 0 2.29 0.861 2.75 1.625s0.73 1.417 0.969 1.656c0.142 0.142 1.126 0.562 2.125 1.094 0.5 0.266 1.012 0.582 1.438 1.094s0.719 1.238 0.719 2.031c0 1.921-1.579 3.5-3.5 3.5-0.867 0-1.77-0.279-2.656-0.531s-1.844-0.469-1.844-0.469-0.957 0.216-1.844 0.469-1.79 0.531-2.656 0.531c-1.921 0-3.5-1.579-3.5-3.5 0-0.813 0.291-1.538 0.719-2.063s0.935-0.869 1.438-1.125c1.006-0.513 1.97-0.877 2.125-1.031 0.264-0.264 0.544-0.897 1-1.656s1.385-1.625 2.719-1.625zM16 18c-0.667 0-0.737 0.135-1.031 0.625s-0.514 1.358-1.25 2.094c-0.845 0.845-1.881 0.995-2.625 1.375-0.372 0.19-0.677 0.39-0.844 0.594s-0.25 0.41-0.25 0.813c0 0.841 0.659 1.5 1.5 1.5 0.29 0 1.224-0.221 2.094-0.469s1.59-0.531 2.406-0.531c0.817 0 1.536 0.284 2.406 0.531s1.803 0.469 2.094 0.469c0.841 0 1.5-0.659 1.5-1.5 0-0.353-0.077-0.542-0.25-0.75s-0.464-0.423-0.844-0.625c-0.759-0.404-1.801-0.583-2.625-1.406-0.727-0.727-0.952-1.568-1.25-2.063s-0.37-0.656-1.031-0.656z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
5
styleguide/src/system/icons/svg/recycle.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>recycle</title>
|
||||
<path d="M16 3.969c1.055 0 2.118 0.517 2.75 1.5l3.125 5.063 1.438-0.844v5.313l-4.625-2.594 1.5-0.875-3.125-5c-0.53-0.824-1.553-0.806-2.094 0l-2.813 4.594-1.719-1.031 2.813-4.625c0.632-0.983 1.695-1.5 2.75-1.5zM10.406 12.094v5.313l-1.531-0.938-2.625 4.25v0.031l-0.031 0.031c-0.665 0.968 0.015 2.219 1.281 2.219h5.5v2h-5.5c-2.712 0-4.409-3.084-2.938-5.313 0.012-0.018-0.012-0.045 0-0.063l0.031 0.031 2.563-4.219-1.25-0.75zM25.063 15.656l2.5 4v0.031c1.36 2.312-0.332 5.313-2.969 5.313h-5.594v2l-4.906-3 4.906-3v2h5.594c1.163 0 1.89-1.193 1.25-2.281l-2.5-4z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 724 B |
5
styleguide/src/system/icons/svg/toggle-off.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>toggle-off</title>
|
||||
<path d="M9 7h14c4.959 0 9 4.041 9 9s-4.041 9-9 9h-14c-0.94 0-1.835-0.137-2.688-0.406-0.282-0.088-0.543-0.198-0.813-0.313-2.413-1.023-4.298-3.072-5.094-5.594-0.003-0.009 0.003-0.022 0-0.031-0.264-0.845-0.406-1.727-0.406-2.656 0-0.94 0.137-1.835 0.406-2.688 0.088-0.282 0.198-0.543 0.313-0.813 1.023-2.413 3.072-4.298 5.594-5.094 0.282-0.088 0.582-0.159 0.875-0.219 0.585-0.12 1.193-0.188 1.813-0.188zM9 9c-3.635 0-6.612 2.743-6.969 6.281-0.024 0.236-0.031 0.476-0.031 0.719 0 3.878 3.123 7 7 7s7-3.122 7-7-3.122-7-7-7zM14.625 9c2.051 1.652 3.375 4.171 3.375 7s-1.324 5.348-3.375 7h8.375c3.878 0 7-3.122 7-7s-3.122-7-7-7h-8.375z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 801 B |
5
styleguide/src/system/icons/svg/toggle-on.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>toggle-on</title>
|
||||
<path d="M9 7h14c4.959 0 9 4.041 9 9s-4.041 9-9 9h-14c-4.962 0-9-4.037-9-9s4.038-9 9-9zM23 9c-3.878 0-7 3.122-7 7s3.122 7 7 7 7-3.122 7-7-3.122-7-7-7z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 323 B |
5
styleguide/src/system/icons/svg/tree.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>tree</title>
|
||||
<path d="M16 3.594l0.719 0.688 5.938 5.969 1 0.969-1.281 0.625s-1.015 0.366-2.438 0.688l4.406 4.406 1 0.969-1.25 0.625s-1.079 0.304-1.625 0.5l3.594 3.594 0.969 1-1.219 0.625s-2.462 1.176-6.813 1.594v3.156h-2v-3.031c-0.335 0.011-0.648 0.031-1 0.031s-0.666-0.021-1-0.031v3.031h-2v-3.156c-4.343-0.417-6.781-1.594-6.781-1.594l-1.25-0.625 0.969-1 3.594-3.594c-0.546-0.196-1.625-0.5-1.625-0.5l-1.25-0.625 1-0.969 4.406-4.406c-1.422-0.322-2.438-0.688-2.438-0.688l-1.281-0.625 1-0.969 5.938-5.969zM16 6.438l-4 3.969c0.593 0.199 0.714 0.356 2.188 0.5l1.813 0.188 1.813-0.188c1.474-0.144 1.594-0.301 2.188-0.5zM16 11.438l-1.188 1.156-4.594 4.594c0.465 0.163 0.453 0.219 1.406 0.406l1.844 0.375-1.344 1.313-3.625 3.656c1.287 0.457 3.459 1.063 7.5 1.063 4.077 0 6.258-0.607 7.531-1.063l-3.656-3.656-1.344-1.313 1.844-0.375c0.953-0.188 0.941-0.243 1.406-0.406l-4.594-4.594z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
5
styleguide/src/system/icons/svg/university.svg
Executable file
@ -0,0 +1,5 @@
|
||||
<!-- Generated by IcoMoon.io -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
|
||||
<title>university</title>
|
||||
<path d="M16 3.906l12.375 5.156 0.625 0.281v2.656h-2v11h2v5h-26v-5h2v-11h-2v-2.656l0.625-0.281 12-5zM16 6.094l-9.375 3.906h18.75zM7 12v11h2v-11h-2zM11 12v11h2v-11h-2zM15 12v11h2v-11h-2zM19 12v11h2v-11h-2zM23 12v11h2v-11h-2zM5 25v1h22v-1h-22z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 415 B |
@ -1,23 +1,27 @@
|
||||
/* FORM VARIABLES / MIXINS
|
||||
--------------------------------------------- */
|
||||
|
||||
$input-font-size-base: $font-size-base;
|
||||
$input-border-size: $border-size-base;
|
||||
$input-padding-vertical: $space-x-small;
|
||||
$input-height: calc(
|
||||
#{$font-size-base * $line-height-base} + #{($input-padding-vertical + $input-border-size) * 2}
|
||||
);
|
||||
|
||||
$input-padding-vertical-small: $space-xx-small;
|
||||
$input-font-size-small: $font-size-base;
|
||||
$input-padding-vertical-small: $space-xxx-small;
|
||||
$input-height-small: calc(
|
||||
#{$font-size-small * $line-height-base} + #{($input-padding-vertical-small + $input-border-size) * 2}
|
||||
#{$font-size-base * $line-height-base} + #{($input-padding-vertical-small + $input-border-size) * 2}
|
||||
);
|
||||
|
||||
$input-font-size-large: $font-size-large;
|
||||
$input-padding-vertical-large: $space-x-small;
|
||||
$input-height-large: calc(
|
||||
#{$font-size-large * $line-height-base} + #{($input-padding-vertical-large + $input-border-size) * 2}
|
||||
#{$input-font-size-large * $line-height-base} + #{($input-padding-vertical-large + $input-border-size) * 2}
|
||||
);
|
||||
|
||||
// $input-font-size-large: $font-size-x-large;
|
||||
$input-padding-vertical-x-large: $space-small;
|
||||
$input-height-x-large: calc(
|
||||
#{$font-size-x-large * $line-height-base} + #{($input-padding-vertical-x-large + $input-border-size) * 2}
|
||||
#{$input-font-size-large * $line-height-base} + #{($input-padding-vertical-x-large + $input-border-size) * 2}
|
||||
);
|
||||
|
||||
@ -2,15 +2,11 @@
|
||||
--------------------------------------------- */
|
||||
|
||||
/* AUTO SCALING FOR TYPE WITH MIN/MAX SIZES
|
||||
|
||||
@param {Number} $responsive - Viewport-based size
|
||||
@param {Number} $min - Minimum font size (px)
|
||||
@param {Number} $max - Maximum font size (px) (optional)
|
||||
|
||||
@param {Number} $fallback - Fallback for viewport-based units (optional)
|
||||
|
||||
@example SCSS - 5vw size, 35px min & 150px max size + 50px fallback:
|
||||
|
||||
@include responsive-font(5vw, 35px, 150px, 50px);
|
||||
*/
|
||||
@mixin responsive-font($responsive, $min, $max: false, $fallback: false) {
|
||||
@ -44,6 +40,32 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@mixin reset-list {
|
||||
@include reset;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
@mixin reset-button {
|
||||
@include reset;
|
||||
border: 0;
|
||||
width: auto;
|
||||
overflow: visible;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
font: inherit;
|
||||
line-height: normal;
|
||||
outline: none;
|
||||
font-smoothing: inherit;
|
||||
-webkit-font-smoothing: inherit;
|
||||
-moz-osx-font-smoothing: inherit;
|
||||
-webkit-appearance: none;
|
||||
|
||||
&::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin clearfix {
|
||||
&:before, &:after {
|
||||
display: table;
|
||||
@ -104,4 +126,4 @@
|
||||
border-bottom-left-radius: $size;
|
||||
border-bottom-right-radius: $size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,6 +291,10 @@ props:
|
||||
value: *color-neutral-80
|
||||
category: border-color
|
||||
|
||||
- name: border-color-light
|
||||
value: *color-neutral-90
|
||||
category: border-color
|
||||
|
||||
- name: border-color-active
|
||||
value: *color-primary
|
||||
category: border-color
|
||||
|
||||
@ -17,7 +17,7 @@ props:
|
||||
- name: font-size-base
|
||||
value: "1rem"
|
||||
- name: font-size-body
|
||||
value: "16px"
|
||||
value: "15px"
|
||||
- name: font-size-small
|
||||
value: "0.8rem"
|
||||
- name: font-size-x-small
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
props:
|
||||
- name: z-index-modal
|
||||
value: "9999"
|
||||
- name: z-index-dropdown
|
||||
value: "8888"
|
||||
- name: z-index-page-submenu
|
||||
value: "2500"
|
||||
- name: z-index-page-header
|
||||
|
||||
98
yarn.lock
@ -693,6 +693,15 @@
|
||||
vue-apollo "^3.0.0-beta.25"
|
||||
vue-cli-plugin-apollo "^0.17.0"
|
||||
|
||||
"@nuxtjs/axios@^5.3.4":
|
||||
version "5.3.4"
|
||||
resolved "https://registry.yarnpkg.com/@nuxtjs/axios/-/axios-5.3.4.tgz#f04c16188ec967606e265ae8e4c6ee0fcc22d0af"
|
||||
dependencies:
|
||||
"@nuxtjs/proxy" "^1.3.0"
|
||||
axios "^0.18.0"
|
||||
axios-retry "^3.1.1"
|
||||
consola "^1.4.4"
|
||||
|
||||
"@nuxtjs/babel-preset-app@^0.7.0":
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@nuxtjs/babel-preset-app/-/babel-preset-app-0.7.0.tgz#b208a95e0a053259c29b99a9e4ca9ea2604dbdd2"
|
||||
@ -732,6 +741,13 @@
|
||||
esm "^3.0.79"
|
||||
node-fetch "^2.2.0"
|
||||
|
||||
"@nuxtjs/proxy@^1.3.0":
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@nuxtjs/proxy/-/proxy-1.3.1.tgz#7d76179aff321491f126d6560434579a4dc7a89a"
|
||||
dependencies:
|
||||
consola "^1.4.4"
|
||||
http-proxy-middleware "^0.19.0"
|
||||
|
||||
"@nuxtjs/youch@^4.2.3":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/@nuxtjs/youch/-/youch-4.2.3.tgz#36f8b22df5a0efaa81373109851e1d857aca6bed"
|
||||
@ -1459,6 +1475,19 @@ aws4@^1.6.0, aws4@^1.8.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
|
||||
|
||||
axios-retry@^3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/axios-retry/-/axios-retry-3.1.1.tgz#88d2971f671a9023b21d887c5dcac6c54f332cde"
|
||||
dependencies:
|
||||
is-retry-allowed "^1.1.0"
|
||||
|
||||
axios@^0.18.0:
|
||||
version "0.18.0"
|
||||
resolved "http://registry.npmjs.org/axios/-/axios-0.18.0.tgz#32d53e4851efdc0a11993b6cd000789d70c05102"
|
||||
dependencies:
|
||||
follow-redirects "^1.3.0"
|
||||
is-buffer "^1.1.5"
|
||||
|
||||
babel-code-frame@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
|
||||
@ -1508,21 +1537,6 @@ babel-plugin-transform-vue-jsx@^4.0.1:
|
||||
dependencies:
|
||||
esutils "^2.0.2"
|
||||
|
||||
babel-polyfill@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.26.0.tgz#379937abc67d7895970adc621f284cd966cf2153"
|
||||
dependencies:
|
||||
babel-runtime "^6.26.0"
|
||||
core-js "^2.5.0"
|
||||
regenerator-runtime "^0.10.5"
|
||||
|
||||
babel-runtime@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
|
||||
dependencies:
|
||||
core-js "^2.4.0"
|
||||
regenerator-runtime "^0.11.0"
|
||||
|
||||
babylon@7.0.0-beta.44:
|
||||
version "7.0.0-beta.44"
|
||||
resolved "http://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d"
|
||||
@ -2138,6 +2152,15 @@ consola@^1.4.3:
|
||||
lodash "^4.17.5"
|
||||
std-env "^1.1.0"
|
||||
|
||||
consola@^1.4.4:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/consola/-/consola-1.4.4.tgz#cf5eda375c0e99df8970cc8f5e98be023da24ce0"
|
||||
dependencies:
|
||||
chalk "^2.3.2"
|
||||
figures "^2.0.0"
|
||||
lodash "^4.17.5"
|
||||
std-env "^1.1.0"
|
||||
|
||||
console-browserify@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
|
||||
@ -2195,7 +2218,7 @@ copy-descriptor@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
|
||||
|
||||
core-js@^2.4.0, core-js@^2.5.0, core-js@^2.5.7:
|
||||
core-js@^2.5.7:
|
||||
version "2.5.7"
|
||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.5.7.tgz#f972608ff0cead68b841a16a932d0b183791814e"
|
||||
|
||||
@ -2515,6 +2538,12 @@ debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3:
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@=3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.1.0:
|
||||
version "3.2.5"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.5.tgz#c2418fbfd7a29f4d4f70ff4cea604d4b64c46407"
|
||||
@ -3007,7 +3036,7 @@ event-stream@~3.3.0:
|
||||
stream-combiner "^0.2.2"
|
||||
through "^2.3.8"
|
||||
|
||||
eventemitter3@^3.1.0:
|
||||
eventemitter3@^3.0.0, eventemitter3@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.0.tgz#090b4d6cdbd645ed10bf750d4b5407942d7ba163"
|
||||
|
||||
@ -3289,6 +3318,12 @@ flush-write-stream@^1.0.0:
|
||||
inherits "^2.0.1"
|
||||
readable-stream "^2.0.4"
|
||||
|
||||
follow-redirects@^1.0.0, follow-redirects@^1.3.0:
|
||||
version "1.5.9"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.9.tgz#c9ed9d748b814a39535716e531b9196a845d89c6"
|
||||
dependencies:
|
||||
debug "=3.1.0"
|
||||
|
||||
for-in@^0.1.3:
|
||||
version "0.1.8"
|
||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
|
||||
@ -3736,6 +3771,23 @@ http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
|
||||
setprototypeof "1.1.0"
|
||||
statuses ">= 1.4.0 < 2"
|
||||
|
||||
http-proxy-middleware@^0.19.0:
|
||||
version "0.19.0"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.0.tgz#40992b5901dc44bc7bc3795da81b0b248eca02d8"
|
||||
dependencies:
|
||||
http-proxy "^1.17.0"
|
||||
is-glob "^4.0.0"
|
||||
lodash "^4.17.10"
|
||||
micromatch "^3.1.10"
|
||||
|
||||
http-proxy@^1.17.0:
|
||||
version "1.17.0"
|
||||
resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a"
|
||||
dependencies:
|
||||
eventemitter3 "^3.0.0"
|
||||
follow-redirects "^1.0.0"
|
||||
requires-port "^1.0.0"
|
||||
|
||||
http-signature@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
|
||||
@ -4089,7 +4141,7 @@ is-resolvable@^1.0.0, is-resolvable@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88"
|
||||
|
||||
is-retry-allowed@^1.0.0:
|
||||
is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz#11a060568b67339444033d0125a61a20d564fb34"
|
||||
|
||||
@ -6278,11 +6330,7 @@ regenerate@^1.2.1, regenerate@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
|
||||
|
||||
regenerator-runtime@^0.10.5:
|
||||
version "0.10.5"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658"
|
||||
|
||||
regenerator-runtime@^0.11.0, regenerator-runtime@^0.11.1:
|
||||
regenerator-runtime@^0.11.1:
|
||||
version "0.11.1"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
|
||||
|
||||
@ -6460,6 +6508,10 @@ require-uncached@^1.0.3:
|
||||
caller-path "^0.1.0"
|
||||
resolve-from "^1.0.0"
|
||||
|
||||
requires-port@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
|
||||
|
||||
resolve-from@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
|
||||
|
||||