mirror of https://github.com/Lissy93/dashy.git
♻️ Refactors item so props is single object
This commit is contained in:
parent
51de80a735
commit
acfb7f267a
|
@ -1,30 +1,32 @@
|
|||
<template ref="container">
|
||||
<div :class="`item-wrapper wrap-size-${itemSize}`" >
|
||||
<div :class="`item-wrapper wrap-size-${size}`" >
|
||||
<a @click="itemClicked"
|
||||
@long-press="openContextMenu"
|
||||
v-longPress="500"
|
||||
@mouseup.right="openContextMenu"
|
||||
@contextmenu.prevent
|
||||
:href="url"
|
||||
@mouseup.right="openContextMenu"
|
||||
v-longPress="true"
|
||||
:href="item.url"
|
||||
:target="anchorTarget"
|
||||
:class="`item ${makeClassList}`"
|
||||
v-tooltip="getTooltipOptions()"
|
||||
rel="noopener noreferrer" tabindex="0"
|
||||
:id="`link-${id}`"
|
||||
:style="`--open-icon:${unicodeOpeningIcon};color:${color};background:${backgroundColor}`"
|
||||
:id="`link-${item.id}`"
|
||||
:style=
|
||||
"`--open-icon:${unicodeOpeningIcon};color:${item.color};background:${item.backgroundColor}`"
|
||||
>
|
||||
<!-- Item Text -->
|
||||
<div :class="`tile-title ${!icon? 'bounce no-icon': ''}`" :id="`tile-${id}`" >
|
||||
<span class="text">{{ title }}</span>
|
||||
<p class="description">{{ description }}</p>
|
||||
<div :class="`tile-title ${!item.icon? 'bounce no-icon': ''}`" :id="`tile-${item.id}`" >
|
||||
<span class="text">{{ item.title }}</span>
|
||||
<p class="description">{{ item.description }}</p>
|
||||
</div>
|
||||
<!-- Item Icon -->
|
||||
<Icon :icon="icon" :url="url" :size="itemSize" :color="color"
|
||||
<Icon :icon="item.icon" :url="item.url" :size="size" :color="item.color"
|
||||
v-bind:style="customStyles" class="bounce" />
|
||||
<!-- Small icon, showing opening method on hover -->
|
||||
<ItemOpenMethodIcon class="opening-method-icon" :isSmall="!icon || itemSize === 'small'"
|
||||
<ItemOpenMethodIcon class="opening-method-icon"
|
||||
:isSmall="!item.icon || size === 'small'"
|
||||
:openingMethod="accumulatedTarget" position="bottom right"
|
||||
:hotkey="hotkey" />
|
||||
:hotkey="item.hotkey" />
|
||||
<!-- Status indicator dot (if enabled) showing weather service is available -->
|
||||
<StatusIndicator
|
||||
class="status-indicator"
|
||||
|
@ -41,15 +43,15 @@
|
|||
v-click-outside="closeContextMenu"
|
||||
:posX="contextPos.posX"
|
||||
:posY="contextPos.posY"
|
||||
:id="`context-menu-${id}`"
|
||||
:id="`context-menu-${item.id}`"
|
||||
@launchItem="launchItem"
|
||||
@openItemSettings="openItemSettings"
|
||||
@openMoveItemMenu="openMoveItemMenu"
|
||||
@openDeleteItem="openDeleteItem"
|
||||
/>
|
||||
<!-- Edit and move item menu modals -->
|
||||
<MoveItemTo v-if="isEditMode" :itemId="id" />
|
||||
<EditItem v-if="editMenuOpen" :itemId="id"
|
||||
<MoveItemTo v-if="isEditMode" :itemId="item.id" />
|
||||
<EditItem v-if="editMenuOpen" :itemId="item.id"
|
||||
@closeEditMenu="closeEditMenu"
|
||||
:isNew="isAddNew" :parentSectionTitle="parentSectionTitle" />
|
||||
</div>
|
||||
|
@ -64,7 +66,7 @@ import MoveItemTo from '@/components/InteractiveEditor/MoveItemTo';
|
|||
import ContextMenu from '@/components/LinkItems/ItemContextMenu';
|
||||
import StoreKeys from '@/utils/StoreMutations';
|
||||
import ItemMixin from '@/mixins/ItemMixin';
|
||||
import { targetValidator } from '@/utils/ConfigHelpers';
|
||||
// import { targetValidator } from '@/utils/ConfigHelpers';
|
||||
import EditModeIcon from '@/assets/interface-icons/interactive-editor-edit-mode.svg';
|
||||
import { modalNames } from '@/utils/defaults';
|
||||
|
||||
|
@ -72,28 +74,7 @@ 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
|
||||
subtitle: String, // Optional sub-text
|
||||
description: String, // Optional tooltip hover text
|
||||
icon: String, // Optional path to icon, within public/img/tile-icons
|
||||
color: String, // Optional text and icon color, specified in hex code
|
||||
backgroundColor: String, // Optional item background color
|
||||
url: String, // URL to the resource, optional but recommended
|
||||
provider: String, // Optional provider name, for external apps
|
||||
hotkey: Number, // Shortcut for quickly launching app
|
||||
target: { // Where resource will open, either 'newtab', 'sametab' or 'modal'
|
||||
type: String,
|
||||
validator: targetValidator,
|
||||
},
|
||||
itemSize: String, // Item size: small | medium | large
|
||||
enableStatusCheck: Boolean, // Should run status checks
|
||||
statusCheckHeaders: Object, // Custom status check headers
|
||||
statusCheckUrl: String, // Custom URL for status check endpoint
|
||||
statusCheckInterval: Number, // Num seconds beteween repeating checks
|
||||
statusCheckAllowInsecure: Boolean, // Status check ignore SSL certs
|
||||
statusCheckAcceptCodes: String, // Allow status checks to pass with a code other than 200
|
||||
statusCheckMaxRedirects: Number, // Specify max number of redirects
|
||||
itemSize: String,
|
||||
parentSectionTitle: String, // Title of parent section (for add new)
|
||||
isAddNew: Boolean, // Only set if 'fake' item used as Add New button
|
||||
},
|
||||
|
@ -109,10 +90,9 @@ export default {
|
|||
computed: {
|
||||
/* Based on item props, adjust class names */
|
||||
makeClassList() {
|
||||
const {
|
||||
icon, itemSize, isAddNew, isEditMode,
|
||||
} = this;
|
||||
return `size-${itemSize} ${!icon ? 'short' : ''} `
|
||||
const { isAddNew, isEditMode, size } = this;
|
||||
const { icon } = this.item;
|
||||
return `size-${size} ${!icon ? 'short' : ''} `
|
||||
+ `${isAddNew ? 'add-new' : ''} ${isEditMode ? 'is-edit-mode' : ''}`;
|
||||
},
|
||||
/* Used by certain themes (material), to show animated CSS icon */
|
||||
|
@ -133,19 +113,19 @@ export default {
|
|||
return {
|
||||
editMenuOpen: false,
|
||||
customStyles: {
|
||||
color: this.color,
|
||||
background: this.backgroundColor,
|
||||
color: this.item.color,
|
||||
background: this.item.backgroundColor,
|
||||
},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
/* Returns configuration object for the tooltip */
|
||||
getTooltipOptions() {
|
||||
if (!this.description && !this.provider) return {}; // If no description, then skip
|
||||
const description = this.description ? this.description : '';
|
||||
const providerText = this.provider ? `<b>Provider</b>: ${this.provider}` : '';
|
||||
if (!this.item.description && !this.item.provider) return {}; // If no description, then skip
|
||||
const description = this.item.description || '';
|
||||
const providerText = this.item.provider ? `<b>Provider</b>: ${this.item.provider}` : '';
|
||||
const lb1 = description && providerText ? '<br>' : '';
|
||||
const hotkeyText = this.hotkey ? `<br>Press '${this.hotkey}' to launch` : '';
|
||||
const hotkeyText = this.item.hotkey ? `<br>Press '${this.item.hotkey}' to launch` : '';
|
||||
const tooltipText = providerText + lb1 + description + hotkeyText;
|
||||
const editText = this.$t('interactive-editor.edit-section.edit-tooltip');
|
||||
return {
|
||||
|
@ -155,7 +135,7 @@ export default {
|
|||
html: true,
|
||||
placement: this.statusResponse ? 'left' : 'auto',
|
||||
delay: { show: 600, hide: 200 },
|
||||
classes: `item-description-tooltip tooltip-is-${this.itemSize}`,
|
||||
classes: `item-description-tooltip tooltip-is-${this.size}`,
|
||||
};
|
||||
},
|
||||
openItemSettings() {
|
||||
|
@ -172,14 +152,14 @@ export default {
|
|||
},
|
||||
/* Open the modal for moving/ copying item to other section */
|
||||
openMoveItemMenu() {
|
||||
this.$modal.show(`${modalNames.MOVE_ITEM_TO}-${this.id}`);
|
||||
this.$modal.show(`${modalNames.MOVE_ITEM_TO}-${this.item.id}`);
|
||||
this.$store.commit(StoreKeys.SET_MODAL_OPEN, true);
|
||||
this.closeContextMenu();
|
||||
},
|
||||
/* Deletes the current item from the state */
|
||||
openDeleteItem() {
|
||||
const parentSection = this.$store.getters.getParentSectionOfItem(this.id);
|
||||
const payload = { itemId: this.id, sectionName: parentSection.name };
|
||||
const parentSection = this.$store.getters.getParentSectionOfItem(this.item.id);
|
||||
const payload = { itemId: this.item.id, sectionName: parentSection.name };
|
||||
this.$store.commit(StoreKeys.REMOVE_ITEM, payload);
|
||||
this.closeContextMenu();
|
||||
},
|
||||
|
|
|
@ -36,26 +36,10 @@
|
|||
</div>
|
||||
<Item
|
||||
v-else
|
||||
:id="item.id"
|
||||
:item="item"
|
||||
:key="item.id"
|
||||
: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"
|
||||
:provider="item.provider"
|
||||
:parentSectionTitle="title"
|
||||
:enableStatusCheck="item.statusCheck !== undefined ? item.statusCheck : enableStatusCheck"
|
||||
:statusCheckInterval="statusCheckInterval"
|
||||
:statusCheckAllowInsecure="item.statusCheckAllowInsecure"
|
||||
:statusCheckAcceptCodes="item.statusCheckAcceptCodes"
|
||||
:statusCheckMaxRedirects="item.statusCheckMaxRedirects"
|
||||
@itemClicked="$emit('itemClicked')"
|
||||
@triggerModal="triggerModal"
|
||||
:isAddNew="false"
|
||||
|
@ -63,12 +47,14 @@
|
|||
</template>
|
||||
<!-- When in edit mode, show additional item, for Add New item -->
|
||||
<Item v-if="isEditMode"
|
||||
:item="{
|
||||
icon: ':heavy_plus_sign:',
|
||||
title: 'Add New Item',
|
||||
description: 'Click to add new item',
|
||||
id: 'add-new',
|
||||
}"
|
||||
:isAddNew="true"
|
||||
:parentSectionTitle="title"
|
||||
icon=":heavy_plus_sign:"
|
||||
id="add-new"
|
||||
title="Add New Item"
|
||||
description="Click to add new item"
|
||||
key="add-new"
|
||||
class="add-new-item"
|
||||
:itemSize="itemSize"
|
||||
|
@ -216,18 +202,18 @@ export default {
|
|||
}
|
||||
return styles;
|
||||
},
|
||||
/* Determines if user has enabled online status checks */
|
||||
enableStatusCheck() {
|
||||
return this.appConfig.statusCheck || false;
|
||||
},
|
||||
/* Determine how often to re-fire status checks */
|
||||
statusCheckInterval() {
|
||||
let interval = this.appConfig.statusCheckInterval;
|
||||
if (!interval) return 0;
|
||||
if (interval > 60) interval = 60;
|
||||
if (interval < 1) interval = 0;
|
||||
return interval;
|
||||
},
|
||||
// /* Determines if user has enabled online status checks */
|
||||
// enableStatusCheck() {
|
||||
// return this.appConfig.statusCheck || false;
|
||||
// },
|
||||
// /* Determine how often to re-fire status checks */
|
||||
// statusCheckInterval() {
|
||||
// let interval = this.appConfig.statusCheckInterval;
|
||||
// if (!interval) return 0;
|
||||
// if (interval > 60) interval = 60;
|
||||
// if (interval < 1) interval = 0;
|
||||
// return interval;
|
||||
// },
|
||||
},
|
||||
methods: {
|
||||
/* Opens the iframe modal */
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
<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"
|
||||
|
@ -34,6 +35,9 @@
|
|||
@navigateToSection="navigateToSection"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="selected && !showAll && !widgets && items.length < 1" class="empty-section">
|
||||
<p>{{ $t('home.no-items-section') }}</p>
|
||||
</div>
|
||||
<IframeModal
|
||||
:ref="`iframeModal-${groupId}`"
|
||||
:name="`iframeModal-${groupId}`"
|
||||
|
@ -131,9 +135,18 @@ export default {
|
|||
.minimal-widget-wrap {
|
||||
padding: 1rem;
|
||||
}
|
||||
.empty-section {
|
||||
padding: 1rem;
|
||||
margin: 0.5rem auto;
|
||||
color: var(--minimal-view-group-color);
|
||||
font-size: 1rem;
|
||||
font-style: italic;
|
||||
opacity: var(--dimming-factor);
|
||||
}
|
||||
&.selected {
|
||||
border: 1px solid var(--minimal-view-group-color);
|
||||
grid-column-start: span var(--col-count, 3);
|
||||
&:not(.show-all) { min-height: 300px; }
|
||||
}
|
||||
&.show-all {
|
||||
border: none;
|
||||
|
|
|
@ -6,12 +6,17 @@ import {
|
|||
openingMethod as defaultOpeningMethod,
|
||||
serviceEndpoints,
|
||||
localStorageKeys,
|
||||
iconSize as defaultSize,
|
||||
} from '@/utils/defaults';
|
||||
|
||||
export default {
|
||||
directives: {
|
||||
longPress,
|
||||
},
|
||||
props: {
|
||||
item: Object,
|
||||
isAddNew: Boolean,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
statusResponse: undefined,
|
||||
|
@ -29,6 +34,25 @@ export default {
|
|||
isEditMode() {
|
||||
return this.$store.state.editMode;
|
||||
},
|
||||
size() {
|
||||
const validSizes = ['small', 'medium', 'large'];
|
||||
if (this.itemSize && validSizes.includes(this.itemSize)) return this.itemSize;
|
||||
return this.appConfig.iconSize || defaultSize;
|
||||
},
|
||||
/* Determines if user has enabled online status checks */
|
||||
enableStatusCheck() {
|
||||
const globalPref = this.appConfig.statusCheck || false;
|
||||
const itemPref = this.item.statusCheck || false;
|
||||
return itemPref || globalPref;
|
||||
},
|
||||
/* Determine how often to re-fire status checks */
|
||||
statusCheckInterval() {
|
||||
let interval = this.item.statusCheckInterval || this.appConfig.statusCheckInterval;
|
||||
if (!interval) return 0;
|
||||
if (interval > 60) interval = 60;
|
||||
if (interval < 1) interval = 0;
|
||||
return interval;
|
||||
},
|
||||
accumulatedTarget() {
|
||||
return this.target || this.appConfig.defaultOpeningMethod || defaultOpeningMethod;
|
||||
},
|
||||
|
@ -53,7 +77,7 @@ export default {
|
|||
return noAnchorNeeded.includes(this.accumulatedTarget) ? nothing : url;
|
||||
},
|
||||
/* Pulls together all user options, returns URL + Get params for ping endpoint */
|
||||
makeApiUrl() {
|
||||
statusCheckApiUrl() {
|
||||
const {
|
||||
url,
|
||||
statusCheckUrl,
|
||||
|
@ -61,7 +85,7 @@ export default {
|
|||
statusCheckAllowInsecure,
|
||||
statusCheckAcceptCodes,
|
||||
statusCheckMaxRedirects,
|
||||
} = this;
|
||||
} = this.item;
|
||||
const encode = (str) => encodeURIComponent(str);
|
||||
this.statusResponse = undefined;
|
||||
// Find base URL, where the API is hosted
|
||||
|
@ -79,9 +103,16 @@ export default {
|
|||
return `${baseUrl}${serviceEndpoints.statusCheck}/${urlToCheck}`
|
||||
+ `${headers}${enableInsecure}${acceptCodes}${maxRedirects}`;
|
||||
},
|
||||
customStyle() {
|
||||
return `--open-icon:${this.unicodeOpeningIcon};`
|
||||
+ `color:${this.item.color};`
|
||||
+ `background:${this.item.backgroundColor}`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
/* Checks if a given service is currently online */
|
||||
checkWebsiteStatus() {
|
||||
const endpoint = this.makeApiUrl();
|
||||
const endpoint = this.statusCheckApiUrl;
|
||||
axios.get(endpoint)
|
||||
.then((response) => {
|
||||
if (response.data) this.statusResponse = response.data;
|
||||
|
@ -93,8 +124,6 @@ export default {
|
|||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
/* Called when an item is clicked, manages the opening of modal & resets the search field */
|
||||
itemClicked(e) {
|
||||
if (this.isEditMode) {
|
||||
|
|
Loading…
Reference in New Issue