Many big improvments to items + sections

This commit is contained in:
Alicia Sykes 2022-04-14 14:34:20 +01:00
parent b1de7bc7e5
commit a6f3c90722
14 changed files with 84 additions and 56 deletions

View File

@ -61,6 +61,7 @@ export default {
text-align: center;
height: fit-content;
margin: 10px;
min-width: 250px;
}
</style>

View File

@ -122,10 +122,6 @@ export default {
data() {
return {
editMenuOpen: false,
customStyles: {
color: this.item.color,
background: this.item.backgroundColor,
},
};
},
methods: {
@ -312,7 +308,8 @@ p.description {
justify-content: flex-end;
align-items: center;
height: 2rem;
padding-top: 4px;
padding-top: 0.25rem;
padding-left: 0.5rem;
div img {
width: 2rem;
}

View File

@ -30,6 +30,7 @@
:itemId="item.id"
:title="item.title"
:subItems="item.subItems"
@triggerModal="triggerModal"
/>
<Item
v-else
@ -56,6 +57,7 @@
:parentSectionTitle="title"
key="add-new"
class="add-new-item"
:sectionWidth="sectionWidth"
:itemSize="itemSize"
/>
</div>

View File

@ -13,7 +13,8 @@
class="sub-item-link item"
>
<!-- Item Icon -->
<Icon :icon="icon" :url="url" size="small" class="sub-icon-img bounce" />
<Icon :icon="item.icon" :url="item.url"
size="small" v-bind:style="customStyles" class="sub-icon-img bounce" />
</a>
<!-- Right-click context menu -->
<ContextMenu
@ -32,20 +33,14 @@
import Icon from '@/components/LinkItems/ItemIcon.vue';
import ContextMenu from '@/components/LinkItems/ItemContextMenu';
import ItemMixin from '@/mixins/ItemMixin';
import { targetValidator } from '@/utils/ConfigHelpers';
// import { targetValidator } from '@/utils/ConfigHelpers';
export default {
name: 'Item',
mixins: [ItemMixin],
props: {
id: String, // The unique ID of a tile (e.g. 001)
title: String, // The main text of tile, required
icon: String, // Optional path to icon, within public/img/tile-icons
url: String, // URL to the resource, optional but recommended
target: { // Where resource will open, either 'newtab', 'sametab' or 'modal'
type: String,
validator: targetValidator,
},
item: Object,
},
components: {
Icon,
@ -69,7 +64,6 @@ export default {
flex-basis: 6rem;
display: flex;
a.sub-item-link {
border: none;
margin: 0.2rem;
.sub-icon-img {
margin: 0;

View File

@ -5,9 +5,8 @@
v-for="(subItem, subIndex) in subItems"
:key="subIndex"
:id="`${itemId}-sub-${subIndex}`"
:url="subItem.url"
:icon="subItem.icon"
:title="subItem.title"
:item="subItem"
@triggerModal="triggerModal"
/>
</div>
</template>
@ -37,6 +36,12 @@ export default {
return 2;
},
},
methods: {
/* Pass open modal emit event up */
triggerModal(url) {
this.$emit('triggerModal', url);
},
},
};
</script>

View File

@ -1,30 +1,27 @@
<template>
<div :class="`minimal-section-inner ${selected ? 'selected' : ''} ${showAll ? 'show-all': ''}`">
<div class="section-items" v-if="items && (selected || showAll)">
<Item
v-for="(item, index) in items"
:item="item"
:id="`${index}_${makeId(item.title)}`"
:key="`${index}_${makeId(item.title)}`"
:url="item.url"
:title="item.title"
:description="item.description"
:icon="item.icon"
:target="item.target"
:color="item.color"
:backgroundColor="item.backgroundColor"
:statusCheckUrl="item.statusCheckUrl"
:statusCheckHeaders="item.statusCheckHeaders"
:itemSize="itemSize"
:hotkey="item.hotkey"
:enableStatusCheck="shouldEnableStatusCheck(item.statusCheck)"
:statusCheckAllowInsecure="item.statusCheckAllowInsecure"
:statusCheckAcceptCodes="item.statusCheckAcceptCodes"
:statusCheckMaxRedirects="item.statusCheckMaxRedirects"
:statusCheckInterval="getStatusCheckInterval()"
@itemClicked="$emit('itemClicked')"
@triggerModal="triggerModal"
/>
<template v-for="(item) in items">
<SubItemGroup
v-if="item.subItems"
:key="item.id"
:itemId="item.id"
:title="item.title"
:subItems="item.subItems"
@triggerModal="triggerModal"
/>
<Item
v-else
:item="item"
:key="item.id"
:itemSize="itemSize"
:parentSectionTitle="title"
@itemClicked="$emit('itemClicked')"
@triggerModal="triggerModal"
:isAddNew="false"
:sectionDisplayData="displayData"
/>
</template>
</div>
<div v-if="widgets && (selected && !showAll)" class="minimal-widget-wrap">
<WidgetBase
@ -50,6 +47,7 @@
import router from '@/router';
import Item from '@/components/LinkItems/Item.vue';
import WidgetBase from '@/components/Widgets/WidgetBase';
import SubItemGroup from '@/components/LinkItems/SubItemGroup.vue';
import IframeModal from '@/components/LinkItems/IframeModal.vue';
export default {
@ -75,6 +73,7 @@ export default {
components: {
Item,
WidgetBase,
SubItemGroup,
IframeModal,
},
methods: {
@ -83,6 +82,7 @@ export default {
},
/* Returns a unique lowercase string, based on name, for section ID */
makeId(str) {
if (!str) return 'unnamed-item';
return str.replace(/\s+/g, '-').replace(/[^a-zA-Z ]/g, '').toLowerCase();
},
/* Opens the iframe modal */
@ -105,7 +105,6 @@ export default {
const parse = (section) => section.replace(' ', '-').toLowerCase().trim();
const sectionIdentifier = parse(this.title);
router.push({ path: `/home/${sectionIdentifier}` });
this.closeContextMenu();
},
},
};

View File

@ -1,5 +1,5 @@
<template>
<div class="nav-outer">
<div class="nav-outer" v-if="links && links.length > 0">
<IconBurger
:class="`burger ${!navVisible ? 'visible' : ''}`"
@click="navVisible = !navVisible"

View File

@ -1,5 +1,5 @@
<template>
<section>
<section v-bind:class="{ 'settings-hidden': !settingsVisible }">
<SearchBar ref="SearchBar"
@user-is-searchin="userIsTypingSomething"
v-if="searchVisible"

View File

@ -520,6 +520,8 @@ export default {
.widget-base {
position: relative;
padding: 0.75rem 0.5rem 0.5rem 0.5rem;
background: var(--widget-base-background);
box-shadow: var(--widget-base-shadow, none);
// Refresh and full-page action buttons
button.action-btn {
height: 1rem;

View File

@ -1,6 +1,7 @@
<template>
<nav class="side-bar">
<div v-for="(section, index) in sections" :key="index" class="side-bar-section">
<!-- Section button -->
<div @click="openSection(index)" class="side-bar-item-container">
<SideBarItem
class="item"
@ -8,6 +9,7 @@
:title="section.name"
/>
</div>
<!-- Section inner -->
<transition name="slide">
<SideBarSection
v-if="isOpen[index]"
@ -16,6 +18,7 @@
/>
</transition>
</div>
<!-- Show links for switching back to Home / Minimal views -->
<div class="switch-view-buttons">
<router-link to="/home">
<IconHome class="view-icon" v-tooltip="$t('alternate-views.default')" />
@ -66,8 +69,12 @@ export default {
if (!this.initUrl) return;
const process = (url) => (url ? url.replace(/[^\w\s]/gi, '').toLowerCase() : undefined);
const compare = (item) => (process(item.url) === process(this.initUrl));
this.sections.forEach((section, secIndex) => {
if (section.items && section.items.findIndex(compare) !== -1) this.openSection(secIndex);
this.sections.forEach((section, secIndx) => {
if (!section.items) return; // Cancel if no items
if (section.items.findIndex(compare) !== -1) this.openSection(secIndx);
section.items.forEach((item) => { // Do the same for sub-items, if set
if (item.subItems && item.subItems.findIndex(compare) !== -1) this.openSection(secIndx);
});
});
},
},

View File

@ -2,6 +2,7 @@
<div class="sub-side-bar">
<div v-for="(item, index) in items" :key="index">
<SideBarItem
v-if="!item.subItems"
class="item"
:icon="item.icon"
:title="item.title"
@ -9,6 +10,18 @@
:target="item.target"
@launch-app="launchApp"
/>
<div v-if="item.subItems" class="sub-item-group">
<SideBarItem
v-for="(subItem, subIndex) in item.subItems"
:key="subIndex"
class="item sub-item"
:icon="subItem.icon"
:title="subItem.title"
:url="subItem.url"
:target="subItem.target"
@launch-app="launchApp"
/>
</div>
</div>
</div>
</template>
@ -46,8 +59,10 @@ div.sub-side-bar {
color: var(--side-bar-color);
text-align: center;
z-index: 3;
.item:not(:last-child) {
border-bottom: 1px dashed var(--side-bar-color);
.sub-item-group {
border: 1px dotted var(--side-bar-color);
border-radius: 4px;
background: #00000033;
}
}

View File

@ -33,7 +33,7 @@ export default {
width: calc(100% - var(--side-bar-width));
.workspace-widget {
max-width: 800px;
margin: 0 auto;
margin: 0.5rem auto 1rem auto;
}
}
</style>

View File

@ -25,6 +25,10 @@ export default {
posX: undefined,
posY: undefined,
},
customStyles: {
color: this.item.color,
background: this.item.backgroundColor,
},
};
},
computed: {
@ -71,7 +75,7 @@ export default {
/* Get href for anchor, if not in edit mode, or opening in modal/ workspace */
hyperLinkHref() {
const nothing = '#';
const url = this.url || nothing;
const url = this.url || this.item.url || nothing;
if (this.isEditMode) return nothing;
const noAnchorNeeded = ['modal', 'workspace', 'clipboard'];
return noAnchorNeeded.includes(this.accumulatedTarget) ? nothing : url;
@ -126,6 +130,7 @@ export default {
},
/* Called when an item is clicked, manages the opening of modal & resets the search field */
itemClicked(e) {
const url = this.url || this.item.url;
if (this.isEditMode) {
// If in edit mode, open settings, and don't launch app
e.preventDefault();
@ -135,16 +140,16 @@ export default {
// For certain opening methods, prevent default and manually navigate
if (e.ctrlKey) {
e.preventDefault();
window.open(this.url, '_blank');
window.open(url, '_blank');
} else if (e.altKey || this.accumulatedTarget === 'modal') {
e.preventDefault();
this.$emit('triggerModal', this.url);
this.$emit('triggerModal', url);
} else if (this.accumulatedTarget === 'workspace') {
e.preventDefault();
router.push({ name: 'workspace', query: { url: this.url } });
router.push({ name: 'workspace', query: { url } });
} else if (this.accumulatedTarget === 'clipboard') {
e.preventDefault();
navigator.clipboard.writeText(this.url);
navigator.clipboard.writeText(url);
this.$toasted.show(this.$t('context-menus.item.copied-toast'));
}
// Emit event to clear search field, etc
@ -157,7 +162,7 @@ export default {
},
/* Open item, using specified method */
launchItem(method, link) {
const url = link || this.url;
const url = link || this.item.url;
this.contextMenuOpen = false;
switch (method) {
case 'newtab':

View File

@ -55,6 +55,7 @@ module.exports = {
'dracula',
'one-dark',
'lissy',
'cherry-blossom',
'nord-frost',
'nord',
'oblivion',