Merge branch 'master' of github.com:Lissy93/dashy into FEATURE/minimal-view

This commit is contained in:
Alicia Sykes
2021-07-25 15:02:17 +01:00
40 changed files with 1768 additions and 352 deletions

View File

@@ -1,55 +1,55 @@
<template>
<div class="cloud-backup-restore-wrapper">
<div class="section intro">
<h2>Cloud Backup & Restore</h2>
<h2>{{ $t('cloud-sync.title') }}</h2>
<p class="intro">
Cloud backup and restore is an optional feature, that enables you to upload your
config to the internet, and then restore it on any other device or instance of Dashy.
{{ $t('cloud-sync.intro-l1') }}
<br><br>
All data is fully end-to-end encrypted with AES, using your password as the key.
{{ $t('cloud-sync.intro-l2') }}
<br>
For more info, please see the
{{ $t('cloud-sync.intro-l3') }}
<a href="https://github.com/Lissy93/dashy/blob/master/docs/backup-restore.md">docs</a>
</p>
</div>
<div class="section backup-section">
<h3 v-if="backupId">Update Backup</h3>
<h3 v-else>Make a Backup</h3>
<h3 v-if="backupId">{{ $t('cloud-sync.backup-title-setup') }}</h3>
<h3 v-else>{{ $t('cloud-sync.backup-title-setup') }}</h3>
<Input
v-model="backupPassword"
name="backup-password"
:label="backupId ? 'Enter your Password' : 'Choose a Password'"
:label="backupId
? $t('cloud-sync.password-label-update') : $t('cloud-sync.password-label-setup')"
layout="vertical"
type="password"
/>
<Button :click="checkPass">
<template v-slot:text>{{backupId ? 'Update Backup' : 'Backup'}}</template>
<template v-slot:text>
{{backupId
? $t('cloud-sync.backup-button-update') : $t('cloud-sync.backup-button-setup')}}
</template>
<template v-slot:icon><IconBackup /></template>
</Button>
<div class="results-view" v-if="backupId">
<span class="backup-id-label">Your Backup ID: </span>
<span class="backup-id-label">{{ $t('cloud-sync.backup-id-label') }}: </span>
<pre class="backup-id-value">{{ backupId }}</pre>
<span class="backup-id-note">
This is used to restore from backups later.
So keep it, along with your password somewhere safe.
</span>
<span class="backup-id-note">{{ $t('cloud-sync.backup-id-note') }}</span>
</div>
</div>
<div class="section restore-section">
<h3>Restore a Backup</h3>
<h3>{{ $t('cloud-sync.restore-title') }}</h3>
<Input
v-model="restoreCode"
name="restore-code"
label="Restore ID"
:label="$t('cloud-sync.restore-id-label')"
/>
<Input
v-model="restorePassword"
name="restore-password"
label="Password"
:label="$t('cloud-sync.restore-password-label')"
type="password"
/>
<Button :click="restoreBackup">
<template v-slot:text>Restore</template>
<template v-slot:text>{{ $t('cloud-sync.restore-button') }}</template>
<template v-slot:icon><IconRestore /></template>
</Button>
</div>
@@ -101,7 +101,7 @@ export default {
} else if (savedHash === this.makeHash(this.backupPassword)) {
this.makeUpdate();
} else {
this.showErrorMsg('Incorrect password. Please enter your current password.');
this.showErrorMsg(this.$t('cloud-sync.backup-error-password'));
}
},
makeBackup() {
@@ -113,7 +113,7 @@ export default {
this.updateUiAfterBackup(response.data.backupId, false);
}
}).catch(() => {
this.showErrorMsg('Unable to process request');
this.showErrorMsg(this.$t('cloud-sync.backup-error-unknown'));
});
},
makeUpdate() {
@@ -125,7 +125,7 @@ export default {
this.updateUiAfterBackup(response.data.backupId, true);
}
}).catch(() => {
this.showErrorMsg('Unable to process request');
this.showErrorMsg(this.$t('cloud-sync.backup-error-unknown'));
});
},
restoreFromBackup(config, backupId) {
@@ -136,12 +136,14 @@ export default {
localStorage.setItem(localStorageKeys.THEME, config.appConfig.theme);
}
this.setBackupIdLocally(backupId, this.restorePassword);
this.showSuccessMsg('Config Restored Succesfully');
this.showSuccessMsg(this.$t('cloud-sync.restore-success-msg'));
setTimeout(() => { location.reload(); }, 1500); // eslint-disable-line no-restricted-globals
},
updateUiAfterBackup(backupId, isUpdate = false) {
this.setBackupIdLocally(backupId, this.backupPassword);
this.showSuccessMsg(`${isUpdate ? 'Update' : 'Backup'} Completed Succesfully`);
this.showSuccessMsg(
`${isUpdate ? 'Update' : 'Backup'} ${this.$t('cloud-sync.backup-success-msg')}`,
);
this.backupPassword = '';
},
showErrorMsg(errorMsg) {

View File

@@ -1,67 +1,74 @@
<template>
<Tabs :navAuto="true" name="Add Item" ref="tabView">
<TabItem name="Config" class="main-tab">
<TabItem :name="$t('config.main-tab')" class="main-tab">
<div class="main-options-container">
<h2>Configuration Options</h2>
<a class="hyperlink-wrapper" @click="downloadConfigFile('conf.yml', yaml)">
<button class="config-button center">
<DownloadIcon class="button-icon"/>
Download Config
<DownloadIcon class="button-icon"/>
{{ $t('config.download-config-button') }}
</button>
</a>
<button class="config-button center" @click="() => navigateToTab(2)">
<EditIcon class="button-icon"/>
Edit Config
{{ $t('config.edit-config-button') }}
</button>
<button class="config-button center" @click="() => navigateToTab(3)">
<CustomCssIcon class="button-icon"/>
Edit Custom CSS
{{ $t('config.edit-css-button') }}
</button>
<button class="config-button center" @click="openCloudSync()">
<CloudIcon class="button-icon"/>
{{backupId ? 'Edit Cloud Sync' : 'Enable Cloud Sync'}}
{{backupId ? $t('config.edit-cloud-sync-button') : $t('config.cloud-sync-button') }}
</button>
<button class="config-button center" @click="openLanguageSwitchModal()">
<LanguageIcon class="button-icon"/>
{{ $t('config.change-language-button') }}
</button>
<button class="config-button center" @click="openRebuildAppModal()">
<RebuildIcon class="button-icon"/>
Rebuild Application
{{ $t('config.rebuild-app-button') }}
</button>
<button class="config-button center" @click="resetLocalSettings()">
<DeleteIcon class="button-icon"/>
Reset Local Settings
{{ $t('config.reset-settings-button') }}
</button>
<button class="config-button center" @click="openAboutModal()">
<IconAbout class="button-icon" />
App Info
{{ $t('config.app-info-button') }}
</button>
<p class="small-screen-note" style="display: none;">
You are using a very small screen, and some screens in this menu may not be optimal
</p>
<p class="app-version">Dashy version {{ appVersion }}</p>
<p class="app-version">{{ $t('config.app-version-note') }} {{ appVersion }}</p>
<p class="language">{{ getLanguage() }}</p>
<div class="config-note">
<span>
It is recommend to make a backup of your conf.yml file before making changes.
</span>
<span>{{ $t('config.backup-note') }}</span>
</div>
</div>
<!-- Rebuild App Modal -->
<RebuildApp />
</TabItem>
<TabItem name="View Config" class="code-container">
<TabItem :name="$t('config.view-config-tab')" class="code-container">
<pre id="conf-yaml">{{yaml}}</pre>
<div class="yaml-action-buttons">
<h2>Actions</h2>
<h2>{{ $t('config.actions-label') }}</h2>
<a class="yaml-button download" @click="downloadConfigFile('conf.yml', yaml)">
Download Config
{{ $t('config.download-config-button') }}
</a>
<a class="yaml-button copy" @click="copyConfigToClipboard()">
{{ $t('config.copy-config-label') }}
</a>
<a class="yaml-button reset" @click="resetLocalSettings()">
{{ $t('config.reset-config-label') }}
</a>
<a class="yaml-button copy" @click="copyConfigToClipboard()">Copy Config</a>
<a class="yaml-button reset" @click="resetLocalSettings()">Reset Config</a>
</div>
</TabItem>
<TabItem name="Edit Config">
<TabItem :name="$t('config.edit-config-tab')">
<JsonEditor :config="config" />
</TabItem>
<TabItem name="Custom Styles">
<CustomCssEditor :config="config" initialCss="hello" />
<TabItem :name="$t('config.custom-css-tab')">
<CustomCssEditor :config="config" />
</TabItem>
</Tabs>
</template>
@@ -74,6 +81,7 @@ import 'highlight.js/styles/mono-blue.css';
import JsonToYaml from '@/utils/JsonToYaml';
import { localStorageKeys, modalNames } from '@/utils/defaults';
import { getUsersLanguage } from '@/utils/ConfigHelpers';
import JsonEditor from '@/components/Configuration/JsonEditor';
import CustomCssEditor from '@/components/Configuration/CustomCss';
import RebuildApp from '@/components/Configuration/RebuildApp';
@@ -84,6 +92,7 @@ import EditIcon from '@/assets/interface-icons/config-edit-json.svg';
import CustomCssIcon from '@/assets/interface-icons/config-custom-css.svg';
import CloudIcon from '@/assets/interface-icons/cloud-backup-restore.svg';
import RebuildIcon from '@/assets/interface-icons/application-rebuild.svg';
import LanguageIcon from '@/assets/interface-icons/config-language.svg';
import IconAbout from '@/assets/interface-icons/application-about.svg';
export default {
@@ -115,6 +124,7 @@ export default {
EditIcon,
CloudIcon,
CustomCssIcon,
LanguageIcon,
RebuildIcon,
IconAbout,
},
@@ -133,20 +143,21 @@ export default {
openCloudSync() {
this.$modal.show(modalNames.CLOUD_BACKUP);
},
openLanguageSwitchModal() {
this.$modal.show(modalNames.LANG_SWITCHER);
},
copyConfigToClipboard() {
navigator.clipboard.writeText(this.jsonParser(this.config));
// event.target.textContent = 'Copied to clipboard';
this.$toasted.show(this.$t('config.data-copied-msg'));
},
/* Checks that the user is sure, then resets site-wide local storage, and reloads page */
resetLocalSettings() {
const msg = 'This will remove all user settings from local storage, '
+ 'but won\'t effect your \'conf.yml\' file. '
+ 'It is recommend to make a backup of your modified YAML settings first.\n\n'
+ 'Are you sure you want to proceed?';
const msg = `${this.$t('config.reset-config-msg-l1')
}${this.$t('config.reset-config-msg-l2')}\n\n${this.$t('config.reset-config-msg-l3')}`;
const isTheUserSure = confirm(msg); // eslint-disable-line no-alert, no-restricted-globals
if (isTheUserSure) {
localStorage.clear();
this.$toasted.show('Data cleared succesfully');
this.$toasted.show(this.$t('config.data-cleared-msg'));
setTimeout(() => {
location.reload(true); // eslint-disable-line no-restricted-globals
}, 1900);
@@ -162,11 +173,19 @@ export default {
element.click();
document.body.removeChild(element);
},
/* Highlights the YAML config in View config tab */
initiateStntaxHighlighter() {
hljs.registerLanguage('yaml', yaml);
const highlighted = hljs.highlight(this.jsonParser(this.config), { language: 'yaml' }).value;
document.getElementById('conf-yaml').innerHTML = highlighted;
},
getLanguage() {
const lang = getUsersLanguage();
return lang ? `${lang.flag} ${lang.name}` : '';
},
},
mounted() {
hljs.registerLanguage('yaml', yaml);
const highlighted = hljs.highlight(this.jsonParser(this.config), { language: 'yaml' }).value;
document.getElementById('conf-yaml').innerHTML = highlighted;
this.initiateStntaxHighlighter();
},
};
</script>
@@ -213,10 +232,11 @@ a.config-button, button.config-button {
}
}
p.app-version {
p.app-version, p.language {
margin: 0.5rem auto;
font-size: 1rem;
color: var(--transparent-white-50);
cursor: default;
}
div.code-container {

View File

@@ -1,11 +1,10 @@
<template>
<div class="css-editor-outer">
<prism-editor class="my-editor" v-model="customCss" :highlight="highlighter" line-numbers />
<button class="save-button" @click="save()">Save Changes</button>
<button class="save-button" @click="save()">{{ $t('config.css-save-btn') }}</button>
<p class="quick-note">
<b>Note</b>: You will need to refresh the page for your changes to take effect.
Styles overides are only stored locally, so it is reccomended to make a copy of your CSS.
To remove all custom styles, delete the contents and hit Save Changes
<b>{{ $t('config.css-note-label') }}:</b>
{{ $t('config.css-note-l1') }} {{ $t('config.css-note-l2') }} {{ $t('config.css-note-l3') }}
</p>
<CustomThemeMaker :themeToEdit="currentTheme" class="color-config" />
</div>

View File

@@ -8,19 +8,25 @@
/>
<!-- Options raido, and save button -->
<div class="save-options">
<span class="save-option-title">Save Location:</span>
<span class="save-option-title">{{ $t('config-editor.save-location-label') }}:</span>
<div class="option">
<input type="radio" id="local" value="local"
v-model="saveMode" class="radio-option" :disabled="!allowWriteToDisk" />
<label for="local" class="save-option-label">Apply Locally</label>
<label for="local" class="save-option-label">
{{ $t('config-editor.location-local-label') }}
</label>
</div>
<div class="option">
<input type="radio" id="file" value="file" v-model="saveMode" class="radio-option"
:disabled="!allowWriteToDisk" />
<label for="file" class="save-option-label">Write Changes to Config File</label>
<label for="file" class="save-option-label">
{{ $t('config-editor.location-disk-label') }}
</label>
</div>
</div>
<button :class="`save-button ${!isValid ? 'err' : ''}`" @click="save()">Save Changes</button>
<button :class="`save-button ${!isValid ? 'err' : ''}`" @click="save()">
{{ $t('config-editor.save-button') }}
</button>
<!-- List validation warnings -->
<p class="errors">
<ul>
@@ -28,24 +34,23 @@
{{error.msg}}
</li>
<li v-if="errorMessages.length < 1" class="type-valid">
Config is Valid
{{ $t('config-editor.valid-label') }}
</li>
</ul>
</p>
<!-- Information notes -->
<p v-if="saveSuccess !== undefined"
:class="`response-output status-${saveSuccess ? 'success' : 'fail'}`">
{{saveSuccess ? 'Task Complete' : 'Task Failed'}}
{{saveSuccess
? $t('config-editor.status-success-msg') : $t('config-editor.status-fail-msg') }}
</p>
<p class="response-output">{{ responseText }}</p>
<p v-if="saveSuccess" class="response-output">
The app should rebuild automatically.
This may take up to a minute.
You will need to refresh the page for changes to take effect.
</p>
<p class="note">
It is recommend to backup your existing confiruration before making any changes.
{{ $t('config-editor.success-note-l1') }}
{{ $t('config-editor.success-note-l2') }}
{{ $t('config-editor.success-note-l3') }}
</p>
<p class="note">{{ $t('config.backup-note') }}</p>
</div>
</template>
@@ -103,7 +108,7 @@ export default {
} else if (this.saveMode === 'file') {
this.writeConfigToDisk();
} else {
this.$toasted.show('Please select a Save Mode: Local or File');
this.$toasted.show(this.$t('config-editor.error-msg-save-mode'));
}
},
writeConfigToDisk() {
@@ -121,9 +126,9 @@ export default {
this.responseText = response.data.message;
if (this.saveSuccess) {
this.carefullyClearLocalStorage();
this.showToast('Config file written to disk succesfully', true);
this.showToast(this.$t('config-editor.success-msg-disk'), true);
} else {
this.showToast('An error occurred saving config', false);
this.showToast(this.$t('config-editor.error-msg-cannot-save'), false);
}
})
.catch((error) => {
@@ -146,7 +151,7 @@ export default {
if (data.appConfig.theme) {
localStorage.setItem(localStorageKeys.THEME, data.appConfig.theme);
}
this.showToast('Changes saved succesfully', true);
this.showToast(this.$t('config-editor.success-msg-local'), true);
},
carefullyClearLocalStorage() {
localStorage.removeItem(localStorageKeys.PAGE_INFO);
@@ -160,7 +165,8 @@ export default {
case 'validation':
errorMessages.push({
type: 'validation',
msg: `Validatation Warning: ${error.error.keyword} ${error.error.message}`,
msg: `${this.$t('config-editor.warning-msg-validation')}: `
+ `${error.error.keyword} ${error.error.message}`,
});
break;
case 'error':
@@ -172,7 +178,7 @@ export default {
default:
errorMessages.push({
type: 'editor',
msg: 'Error in JSON',
msg: this.$t('config-editor.error-msg-bad-json'),
});
break;
}

View File

@@ -2,35 +2,41 @@
<modal :name="modalName" :resizable="true" width="50%" height="60%" classes="dashy-modal">
<div class="rebuild-app-container">
<!-- Title, intro and start button -->
<h3 class="rebuild-app-title">Rebuild Application</h3>
<h3 class="rebuild-app-title">{{ $t('app-rebuild.title') }}</h3>
<p>
A rebuild is required for changes written to the conf.yml file to take effect.
This should happen automatically, but if it hasn't, you can manually trigger it here.<br>
This is not required for modifications stored locally.
{{ $t('app-rebuild.rebuild-note-l1') }}
{{ $t('app-rebuild.rebuild-note-l2') }}<br>
{{ $t('app-rebuild.rebuild-note-l3') }}
</p>
<Button :click="startBuild" :disabled="loading || !allowRebuild" :disallow="!allowRebuild">
<template v-slot:text>{{ loading ? 'Building...' : 'Start Build' }}</template>
<template v-slot:text>
{{ loading ? $t('app-rebuild.rebuilding-status-1') : $t('app-rebuild.rebuild-button') }}
</template>
<template v-slot:icon><RebuildIcon /></template>
</Button>
<div v-if="!allowRebuild">
<p class="disallow-rebuild-msg">You do no have permission to trigger this action</p>
<p class="disallow-rebuild-msg">{{ $t('app-rebuild.error-permission') }}</p>
</div>
<!-- Loading animation and text (shown while build is happening) -->
<div v-if="loading" class="loader-info">
<LoadingAnimation class="loader" />
<p class="loading-message">This may take a few minutes...</p>
<p class="loading-message">{{ $t('app-rebuild.rebuilding-status-2') }}...</p>
</div>
<!-- Build response, and next actions (shown after build is done) -->
<div class="rebuild-response" v-if="success !== undefined">
<p v-if="success" class="response-status success">✅ Build completed succesfully</p>
<p v-else class="response-status failure">❌ Build operation failed</p>
<p v-if="success" class="response-status success">
{{ $t('app-rebuild.success-msg') }}
</p>
<p v-else class="response-status failure">
{{ $t('app-rebuild.fail-msg') }}
</p>
<pre class="output"><code>{{ output || error }}</code></pre>
<p class="rebuild-message">{{ message }}</p>
<p v-if="success" class="rebuild-message">
A page reload is now required for changes to take effect
{{ $t('app-rebuild.reload-note') }}
</p>
<Button :click="refreshPage" v-if="success">
<template v-slot:text>Reload Page</template>
<template v-slot:text>{{ $t('app-rebuild.reload-button') }}</template>
<template v-slot:icon><ReloadIcon /></template>
</Button>
</div>
@@ -65,6 +71,7 @@ export default {
allowRebuild: true,
}),
methods: {
/* Calls to the rebuild endpoint, to kickoff the app build */
startBuild() {
const baseUrl = process.env.VUE_APP_DOMAIN || window.location.origin;
const endpoint = `${baseUrl}/config-manager/rebuild`;
@@ -77,6 +84,7 @@ export default {
this.finished({ success: false, error });
});
},
/* Called when rebuild is complete, updates UI with either success or fail message */
finished(responseData) {
this.loading = false;
if (responseData) {
@@ -89,7 +97,8 @@ export default {
this.error = error;
}
this.$toasted.show(
(this.success ? ' Build Completed Succesfully' : ' Build Failed'),
(this.success
? `${this.$t('app-rebuild.success-msg')}` : `${this.$t('app-rebuild.fail-msg')}`),
{ className: `toast-${this.success ? 'success' : 'error'}` },
);
},

View File

@@ -1,10 +1,10 @@
<template>
<div class="config-options">
<!-- Button and label -->
<span>Config</span>
<span>{{ $t('settings.config-launcher-label') }}</span>
<div class="config-buttons">
<IconSpanner @click="showEditor()" tabindex="-2"
v-tooltip="tooltip('Update configuration locally')" />
v-tooltip="tooltip('Update configuration')" />
<IconCloud @click="showCloudModal()" tabindex="-2"
v-tooltip="tooltip('Backup / restore cloud config')" />
</div>
@@ -20,6 +20,13 @@
@closed="$emit('modalChanged', false)" classes="dashy-modal">
<CloudBackupRestore :config="combineConfig()" />
</modal>
<!-- Modal for manually changing locale -->
<modal :name="modalNames.LANG_SWITCHER" classes="dashy-modal"
:resizable="true" width="30%" height="25%">
<LanguageSwitcher />
</modal>
</div>
</template>
@@ -29,6 +36,7 @@ import IconSpanner from '@/assets/interface-icons/config-editor.svg';
import IconCloud from '@/assets/interface-icons/cloud-backup-restore.svg';
import ConfigContainer from '@/components/Configuration/ConfigContainer';
import CloudBackupRestore from '@/components/Configuration/CloudBackupRestore';
import LanguageSwitcher from '@/components/Settings/LanguageSwitcher';
import { topLevelConfKeys, localStorageKeys, modalNames } from '@/utils/defaults';
export default {
@@ -43,6 +51,7 @@ export default {
IconCloud,
ConfigContainer,
CloudBackupRestore,
LanguageSwitcher,
},
props: {
sections: Array,

View File

@@ -1,6 +1,6 @@
<template>
<div :class="`theme-configurator-wrapper ${showingAllVars ? 'showing-all' : ''}`">
<h3 class="configurator-title">Theme Configurator</h3>
<h3 class="configurator-title">{{ $t('theme-maker.title') }}</h3>
<div class="color-row-container">
<div class="color-row" v-for="colorName in Object.keys(customColors)" :key="colorName">
<label :for="`color-input-${colorName}`" class="color-name">
@@ -33,17 +33,21 @@
</div> <!-- End of color list -->
</div>
<p @click="exportToClipboard" class="action-text-btn">
Export Custom Variables
{{ $t('theme-maker.export-button') }}
</p>
<p @click="resetAndSave" class="action-text-btn show-all-vars-btn">
Reset Styles for '{{ themeToEdit }}'
{{ $t('theme-maker.reset-button') }} '{{ themeToEdit }}'
</p>
<p @click="findAllVariableNames" class="action-text-btn">
Show All Variables
{{ $t('theme-maker.show-all-button') }}
</p>
<div class="action-buttons">
<Button :click="saveChanges"><SaveIcon />Save</Button>
<Button :click="resetUnsavedColors"><CancelIcon />Cancel</Button>
<Button :click="saveChanges">
<SaveIcon /> {{ $t('theme-maker.save-button') }}
</Button>
<Button :click="resetUnsavedColors">
<CancelIcon /> {{ $t('theme-maker.cancel-button') }}
</Button>
</div>
</div>
</template>
@@ -89,7 +93,7 @@ export default {
const priorSettings = JSON.parse(localStorage[localStorageKeys.CUSTOM_COLORS] || '{}');
priorSettings[this.themeToEdit] = this.customColors;
localStorage.setItem(localStorageKeys.CUSTOM_COLORS, JSON.stringify(priorSettings));
this.$toasted.show('Theme Updates Succesfully');
this.$toasted.show(this.$t('theme-maker.saved-toast', { theme: this.themeToEdit }));
this.$emit('closeThemeConfigurator');
},
/* Itterates over available variables, removing them from the DOM */
@@ -107,7 +111,7 @@ export default {
delete priorSettings[this.themeToEdit];
localStorage.setItem(localStorageKeys.CUSTOM_COLORS, JSON.stringify(priorSettings));
this.resetUnsavedColors();
this.$toasted.show(`Custom Colors for ${this.themeToEdit} Removed`);
this.$toasted.show(this.$t('theme-maker.reset-toast', { theme: this.themeToEdit }));
},
/* Generates CSS for the currently applied variables, and copys to users clipboard */
exportToClipboard() {
@@ -117,7 +121,7 @@ export default {
clipboardText += (`--${customVar}: ${this.customColors[customVar]};\n`);
});
navigator.clipboard.writeText(clipboardText);
this.$toasted.show(`Theme data for ${themeName} copied to clipboard`);
this.$toasted.show(this.$t('theme-maker.copied-toast', { theme: themeName }));
},
/* Returns a JSON object, with the variable name as key, and color as value */
makeInitialData(variableArray) {

View File

@@ -1,13 +1,25 @@
<template>
<div>
<span class="options-label">Icon Size</span>
<span class="options-label">{{ $t('settings.item-size-label') }}</span>
<div class="display-options">
<IconSmall @click="updateIconSize('small')" v-tooltip="tooltip('Small')"
:class="`layout-icon ${iconSize === 'small' ? 'selected' : ''}`" tabindex="-2" />
<IconMedium @click="updateIconSize('medium')" v-tooltip="tooltip('Medium')"
:class="`layout-icon ${iconSize === 'medium' ? 'selected' : ''}`" tabindex="-2" />
<IconLarge @click="updateIconSize('large')" v-tooltip="tooltip('Large')"
:class="`layout-icon ${iconSize === 'large' ? 'selected' : ''}`" tabindex="-2" />
<IconSmall
@click="updateIconSize('small')"
v-tooltip="tooltip($t('settings.item-size-small'))"
:class="`layout-icon ${iconSize === 'small' ? 'selected' : ''}`"
tabindex="-2"
/>
<IconMedium
@click="updateIconSize('medium')"
v-tooltip="tooltip($t('settings.item-size-medium'))"
:class="`layout-icon ${iconSize === 'medium' ? 'selected' : ''}`"
tabindex="-2"
/>
<IconLarge
@click="updateIconSize('large')"
v-tooltip="tooltip($t('settings.item-size-large'))"
:class="`layout-icon ${iconSize === 'large' ? 'selected' : ''}`"
tabindex="-2"
/>
</div>
</div>
</template>

View File

@@ -0,0 +1,110 @@
<template>
<div class="language-switcher">
<h3 class="title">{{ $t('language-switcher.title') }}</h3>
<p class="intro">{{ $t('language-switcher.dropdown-label') }}:</p>
<v-select
v-model="language"
:selectOnTab="true"
:options="availibleLanguages"
class="language-dropdown"
label="name"
:input="setLangLocally()"
/>
<Button class="save-button" :click="saveLanguage" :disallow="!language">
{{ $t('language-switcher.save-button') }}
<SaveConfigIcon />
</Button>
<p v-if="language">{{ language.flag }} {{ language.name }}</p>
<p v-if="$i18n.availableLocales.length <= 1" class="sad-times">
There are not currently any additional languages supported,
but stay tuned as more are on their way!
</p>
</div>
</template>
<script>
import Button from '@/components/FormElements/Button';
import { languages } from '@/utils/languages';
import SaveConfigIcon from '@/assets/interface-icons/save-config.svg';
import { localStorageKeys, modalNames } from '@/utils/defaults';
export default {
name: 'LanguageSwitcher',
inject: ['config'],
components: {
Button,
SaveConfigIcon,
},
data() {
return {
availibleLanguages: languages,
language: '',
modalName: modalNames.LANG_SWITCHER,
};
},
methods: {
/* Save language to local storage, show success msg and close modal */
saveLanguage() {
const selectedLanguage = this.language;
if (this.checkLocale(selectedLanguage)) {
localStorage.setItem(localStorageKeys.LANGUAGE, selectedLanguage.code);
this.setLangLocally();
const successMsg = `${selectedLanguage.flag} `
+ `${this.$t('language-switcher.success-msg')} ${selectedLanguage.name}`;
this.$toasted.show(successMsg, { className: 'toast-success' });
this.$modal.hide(this.modalName);
} else {
this.$toasted.show('Unable to update language', { className: 'toast-error' });
}
},
/* Check language is supported, before saving */
checkLocale(selectedLanguage) {
if (!selectedLanguage || !selectedLanguage.code) return false;
const i18nLocales = this.$i18n.availableLocales;
return i18nLocales.includes(selectedLanguage.code);
},
/* Apply language locally */
setLangLocally() {
if (this.language && this.language.code) {
this.$i18n.locale = this.language.code;
}
},
},
};
</script>
<style scoped lang="scss">
.language-switcher {
height: 100%;
margin: 0;
padding: 1rem;
background: var(--config-settings-background);
color: var(--config-settings-color);
h3.title {
text-align: center;
}
p.intro {
margin: 0;
}
button.save-button {
margin: 0 auto;
width: 100%;
}
p.sad-times {
color: var(--warning);
text-align: center;
}
.language-dropdown {
margin: 1rem auto;
div.vs__dropdown-toggle {
padding: 0.2rem 0;
}
}
}
</style>

View File

@@ -1,13 +1,25 @@
<template>
<div>
<span class="options-label">Layout</span>
<span class="options-label">{{ $t('settings.layout-label') }}</span>
<div class="display-options">
<IconDeafault @click="updateDisplayLayout('auto')" v-tooltip="tooltip('Auto')"
:class="`layout-icon ${displayLayout === 'auto' ? 'selected' : ''}`" tabindex="-2" />
<IconHorizontal @click="updateDisplayLayout('horizontal')" v-tooltip="tooltip('Horizontal')"
:class="`layout-icon ${displayLayout === 'horizontal' ? 'selected' : ''}`" tabindex="-2" />
<IconVertical @click="updateDisplayLayout('vertical')" v-tooltip="tooltip('Vertical')"
:class="`layout-icon ${displayLayout === 'vertical' ? 'selected' : ''}`" tabindex="-2" />
<IconDeafault
@click="updateDisplayLayout('auto')"
v-tooltip="tooltip($t('settings.layout-auto'))"
:class="`layout-icon ${displayLayout === 'auto' ? 'selected' : ''}`"
tabindex="-2"
/>
<IconHorizontal
@click="updateDisplayLayout('horizontal')"
v-tooltip="tooltip($t('settings.layout-horizontal'))"
:class="`layout-icon ${displayLayout === 'horizontal' ? 'selected' : ''}`"
tabindex="-2"
/>
<IconVertical
@click="updateDisplayLayout('vertical')"
v-tooltip="tooltip($t('settings.layout-vertical'))"
:class="`layout-icon ${displayLayout === 'vertical' ? 'selected' : ''}`"
tabindex="-2"
/>
</div>
</div>
</template>

View File

@@ -1,16 +1,16 @@
<template>
<form>
<label for="filter-tiles">Search</label>
<label for="filter-tiles">{{ $t('search.search-label') }}</label>
<input
id="filter-tiles"
v-model="input"
ref="filter"
placeholder="Start typing to filter..."
:placeholder="$t('search.search-placeholder')"
v-on:input="userIsTypingSomething"
@keydown.esc="clearFilterInput" />
<i v-if="input.length > 0"
class="clear-search"
title="Clear search"
:title="$t('search.clear-search-tooltip')"
@click="clearFilterInput">x</i>
</form>
</template>

View File

@@ -1,7 +1,7 @@
<template>
<div class="theme-selector-section" v-click-outside="closeThemeConfigurator">
<div>
<span class="theme-label">Theme</span>
<span class="theme-label">{{ $t('settings.theme-label') }}</span>
<v-select
:options="themeNames"
v-model="selectedTheme"