Organised components into directories

This commit is contained in:
Alicia Sykes
2021-04-13 12:36:31 +01:00
parent 0761e4d5a4
commit 8bdf59a1ee
16 changed files with 17 additions and 305 deletions

View File

@@ -0,0 +1,199 @@
<template>
<section>
<form>
<label for="filter-tiles">Search</label>
<input
id="filter-tiles"
v-model="input"
ref="filter"
placeholder="Start typing to filter tiles..."
v-on:input="userIsTypingSomething"
@keydown.esc="clearFilterInput" />
<i v-if="input.length > 0"
class="el-icon-circle-close clear-search"
title="Clear search"
@click="clearFilterInput"></i>
</form>
<div class="options-container">
<div class="theme-selector">
<ThemeSelector :themes="availableThemes" />
</div>
<div>
<span class="options-label">Layout</span>
<div class="display-options">
<IconDeafault @click="updateDisplayLayout('default')"
:class="`layout-icon ${displayLayout === 'default' ? 'selected' : ''}`" />
<IconHorizontal class="layout-icon" @click="updateDisplayLayout('horizontal')"
:class="`layout-icon ${displayLayout === 'horizontal' ? 'selected' : ''}`" />
<IconVertical class="layout-icon" @click="updateDisplayLayout('vertical')"
:class="`layout-icon ${displayLayout === 'vertical' ? 'selected' : ''}`" />
</div>
</div>
</div>
<KeyboardShortcutInfo />
</section>
</template>
<script>
import KeyboardShortcutInfo from '@/components/Settings/KeyboardShortcutInfo';
import ThemeSelector from '@/components/Settings/ThemeSelector';
import IconDeafault from '@/assets/icons/layout-default.svg';
import IconHorizontal from '@/assets/icons/layout-horizontal.svg';
import IconVertical from '@/assets/icons/layout-vertical.svg';
export default {
name: 'FilterTile',
data() {
return {
input: '',
};
},
props: {
displayLayout: String,
availableThemes: Object,
},
components: {
KeyboardShortcutInfo,
ThemeSelector,
IconDeafault,
IconHorizontal,
IconVertical,
},
methods: {
userIsTypingSomething() {
this.$emit('user-is-searchin', this.input);
},
clearFilterInput() {
this.input = '';
this.userIsTypingSomething();
document.activeElement.blur();
},
updateDisplayLayout(layout) {
this.$emit('change-display-layout', layout);
},
},
mounted() {
window.addEventListener('keyup', (event) => {
const { key, keyCode } = event;
if (/^[a-zA-Z]$/.test(key) && !document.activeElement.id) {
try {
this.input += key;
this.$refs.filter.focus();
this.userIsTypingSomething();
} catch (e) {
// Do nothing
}
} else if (keyCode === 27) {
this.clearFilterInput();
}
});
},
};
</script>
<style scoped lang="scss">
section {
display: flex;
align-items: center;
align-items: stretch;
background: linear-gradient(0deg, var(--background) 0%, var(--background-darker) 100%);
}
form {
border-radius: 0 0 20px 0;
padding: 0 0.2rem 0.2rem 0;
background: var(--background-darker);
label {
display: inline;
color: var(--primary);
margin: 0.5rem;
display: inline;
}
input {
display: inline-block;
width: 200px;
padding: 0.5rem;
margin: 0.5rem;
outline: none;
border: none;
border-radius: 12px;
background: var(--background);
color: var(--primary);
&:focus {
background: var(--background-transparent);
}
}
.clear-search {
position: absolute;
margin: 1em 0 0 -2em;
color: var(--primary);
opacity: 0.5;
border-radius: 50px;
cursor: pointer;
&:hover {
opacity: 1;
background: var(--background-darker);
}
}
}
.options-container {
display: flex;
flex-direction: row;
align-items: flex-end;
justify-content: flex-end;
flex: 1;
padding: 0 1rem;
border-radius: 20px 0 0;
background: var(--background);
span.options-label {
font-size: 0.8rem;
color: var(--primary-transparent);
width: 5.5rem;
text-align: left;
}
.theme-selector {
align-items: center;
display: flex;
height: 100%;
padding: 0 1rem;
}
.display-options {
color: var(--primary-transparent);
svg {
path {
fill: var(--primary-transparent);
}
width: 1rem;
height: 1rem;
margin: 0.2rem;
padding: 0.2rem;
text-align: center;
background: var(--background);
border: 1px solid currentColor;
border-radius: 4px;
opacity: 0.8;
cursor: pointer;
&:hover, &.selected {
background: var(--primary-transparent);
path { fill: var(--background); }
}
}
}
}
@media screen and (max-width: 600px) {
form {
flex: 1;
border-radius: 0;
text-align: center;
padding: 0.25rem 0;
}
.options-container {
display: none;
}
}
</style>

View File

@@ -0,0 +1,122 @@
<template>
<transition name="slide-fade">
<div class="kb-sc-info" v-if="!shouldHide">
<h5>There are keyboard shortcuts! 🙌</h5>
<div class="close" title="Hide forever [Esc]" @click="hideWelcomeHelper()">x</div>
<p title="Press [Esc] to hide this tip forever. See there's even a shortcut for that! 🚀">
Just start typing to filter. Then use the tab key to cycle through results,
and press enter to launch the selected item. You can hit Esc at anytime to
clear the search. Easy 🥳
</p>
</div>
</transition>
</template>
<script>
export default {
name: 'KeyboardShortcutInfo',
data() {
return {
shouldHide: true, // False = show/ true = hide. Intuitive, eh?
};
},
methods: {
/**
* If the session storage item exists, true will be returned
* Otherwise, if not then false is returned.
* Note the !! just converts 'false' to false, as strings resolve to true
*/
shouldHideWelcomeMessage() {
return !!localStorage.hideWelcomeHelpers;
},
/**
* Update session storage, so that it won't be shown again
* Trigger the hide function, and remove the event listerner
*/
hideWelcomeHelper() {
this.shouldHide = true;
localStorage.setItem('hideWelcomeHelpers', true);
window.removeEventListener('keyup');
},
},
/**
* Once mounted, if it's the users first time here, then we wait 3 seconds,
* and show the helpfull little keyboard shortcut dialog.
* Then we listen for the Esc key to be pressed, and hide the dialog.
*/
mounted() {
const shouldHide = this.shouldHideWelcomeMessage();
if (!shouldHide) {
window.setTimeout(() => { this.shouldHide = shouldHide; }, 3000);
window.addEventListener('keyup', (ev) => {
// User pressed the escape key. Trigger permanent dismissal of dialog
if (ev.keyCode === 27) this.hideWelcomeHelper();
});
} else { // Meh, component not needed.
// No point wasting valuable bytes of your 32GB Ram, lets kill it
this.$destroy();
}
},
};
</script>
<style scoped lang="scss">
.kb-sc-info {
position: fixed;
width: 30em;
bottom: 0;
right: 10px;
margin: 0.5em;
padding: 0.1em 0.3em;
z-index: 10;
border-radius: 12px;
border: 1px solid var(--background-darker);
-webkit-box-shadow: 2px 1px 5px #130f23;
box-shadow: 2px 1px 5px #130f23;
border: 1px solid var(--primary);
color: var(--primary);
background: var(--background-darker);
cursor: default;
opacity: 0.94;
@media screen and (max-width: 600px) {
display: none;
}
h5 { /* The dialog title */
position: absolute;
top: -35px;
left: 20px;
border: 1px solid var(--primary);
color: var(--primary);
background: var(--background-darker);
padding: 4px;
border-radius: 5px;
}
.close { /* The little exit icon, in top-right */
float: right;
border-radius: 20px;
width: 1em;
padding: 0 0 6px 6px;
height: 1em;
background: var(--transparent-50);
margin-top: 3px;
border: 1px solid transparent;
cursor: pointer;
&:hover {
border: 1px solid var(--primary);
opacity: 0.6;
}
}
}
/* Animations, animations everywhere */
.slide-fade-enter-active {
transition: all 1s ease;
}
.slide-fade-leave-active {
transition: all .8s cubic-bezier(.93,.01,.89,.5);
}
.slide-fade-enter, .slide-fade-leave-to {
transform: translateY(35em);
opacity: 0;
}
</style>

View File

@@ -0,0 +1,92 @@
<template>
<div class="theme-selector-section" v-if="themes" >
<span class="theme-label">Themes</span>
<v-select
:options="themeNames"
v-model="selectedTheme"
class="theme-dropdown"
:tabindex="100"
/>
</div>
</template>
<script>
import ThemeHelper from '@/utils/ThemeHelper';
export default {
name: 'ThemeSelector',
props: {
themes: Object,
},
watch: {
selectedTheme(newTheme) {
this.themeHelper.theme = newTheme;
},
},
data() {
return {
selectedTheme: 'Default',
themeHelper: new ThemeHelper(),
loading: true,
};
},
computed: {
themeNames: function themeNames() { return Object.keys(this.themes); },
},
created() {
const added = Object.keys(this.themes).map(
name => this.themeHelper.add(name, this.themes[name]),
);
Promise.all(added).then(() => {
this.loading = false;
this.themeHelper.theme = 'Deafault';
});
},
};
</script>
<style lang="scss">
@import 'vue-select/src/scss/vue-select.scss';
.theme-dropdown {
div.vs__dropdown-toggle {
border-color: var(--primary);
min-width: 10rem;
height: 2rem;
}
span.vs__selected, li.vs__dropdown-option {
color: var(--primary);
}
svg.vs__open-indicator {
fill: var(--primary);
}
ul.vs__dropdown-menu {
width: auto;
background: var(--background);
}
li.vs__dropdown-option--highlight {
background: var(--primary);
color: var(--background);
}
button.vs__clear {
display: none;
}
}
.theme-selector-section {
display: flex;
flex-direction: column;
opacity: 0.8;
span.theme-label {
font-size: 0.8rem;
color: var(--primary);
margin: 1px 0 2px 0;
}
&:hover {
opacity: 1;
}
}
</style>