Add option to generate random themes

masks
Warinyourself 4 years ago
parent 6defc7fa60
commit b2659e635a

@ -1,8 +1,8 @@
import { Component, Vue } from 'vue-property-decorator' import { Component, Vue, Watch } from 'vue-property-decorator'
import Mousetrap from 'mousetrap' import Mousetrap from 'mousetrap'
import { AppModule } from '@/store/app' import { AppModule } from '@/store/app'
import { PageModule } from './store/page' import { PageModule } from './store/page'
import { focusInputPassword } from './utils/helper' import { Debounce, focusInputPassword } from './utils/helper'
import { hotkeys } from '@/utils/hotkeys' import { hotkeys } from '@/utils/hotkeys'
@Component @Component
@ -11,6 +11,17 @@ export default class MainApp extends Vue {
return AppModule.bodyClass return AppModule.bodyClass
} }
get getMainSettings() {
return AppModule.getMainSettings
}
@Debounce(100)
@Watch('getMainSettings', { deep: true })
handleSettingsThemes() {
console.log('Update Settings')
AppModule.syncSettingsWithCache()
}
created() { created() {
AppModule.setUpSettings() AppModule.setUpSettings()
this.initKeybinds() this.initKeybinds()

@ -2,8 +2,6 @@ import { Component, Prop, Vue } from 'vue-property-decorator'
import AppIcon from '@/components/app/AppIcon.vue' import AppIcon from '@/components/app/AppIcon.vue'
import { Route } from 'vue-router' import { Route } from 'vue-router'
import { CreateElement, VNode, VNodeData } from 'vue' import { CreateElement, VNode, VNodeData } from 'vue'
import { RenderContext } from 'vue/types/umd'
import { spawn } from 'child_process'
const prefix = 'app-button' const prefix = 'app-button'
@ -52,9 +50,7 @@ export default class AppButton extends Vue implements AppButtonPropsInterface {
classes[`${prefix}--${property}`] = !!this[property] classes[`${prefix}--${property}`] = !!this[property]
}) })
return { return classes
...classes
}
} }
get isLink() { get isLink() {

@ -5,13 +5,20 @@ import AppIcon from '@/components/app/AppIcon.vue'
components: { AppIcon } components: { AppIcon }
}) })
export default class AppCheckbox extends Vue { export default class AppCheckbox extends Vue {
@Prop({ type: Boolean, default: false }) value!: boolean @Prop({ default: false }) value!: boolean
@Prop({ default: '' }) label!: string @Prop({ default: '' }) label!: string
get isActive() { get isActive() {
return this.value return this.value
} }
get classes() {
return {
checkbox: true,
'checkbox--active': this.value
}
}
get idCheckbox() { get idCheckbox() {
return `input-${(this as any)._uid}` return `input-${(this as any)._uid}`
} }
@ -21,7 +28,7 @@ export default class AppCheckbox extends Vue {
} }
render() { render() {
return <label class={['checkbox', this.value ? 'checkbox--active' : '']}> return <label class={ this.classes }>
<div class="checkbox-control"> <div class="checkbox-control">
<div class="checkbox-control-box"> <div class="checkbox-control-box">
<AppIcon name="checkbox"></AppIcon> <AppIcon name="checkbox"></AppIcon>

@ -23,6 +23,10 @@ export default class SettingsCheckboxes extends Vue {
/> />
} }
generateRandomTheme(value: boolean) {
AppModule.SET_STATE_APP({ key: 'generateRandomThemes', value })
}
render() { render() {
return <div class="grid-two"> return <div class="grid-two">
<h2 class="title"> { this.$t('settings.performance') } </h2> <h2 class="title"> { this.$t('settings.performance') } </h2>
@ -30,6 +34,13 @@ export default class SettingsCheckboxes extends Vue {
{ this.buildCheckbox('show-framerate') } { this.buildCheckbox('show-framerate') }
{ this.buildCheckbox('no-transition') } { this.buildCheckbox('no-transition') }
{ this.buildCheckbox('only-ui') } { this.buildCheckbox('only-ui') }
<AppCheckbox
inline={ true }
label={ this.$t('settings.generate-random-theme') }
value={ AppModule.generateRandomThemes }
onInput={ this.generateRandomTheme }
/>
</div> </div>
} }
} }

@ -5,8 +5,8 @@ import AppIcon from '@/components/app/AppIcon.vue'
import AppButton from '@/components/app/AppButton' import AppButton from '@/components/app/AppButton'
import SettingsUsers from './SettingsUsers' import SettingsUsers from './SettingsUsers'
import SettingsHotkeys from './SettingsHotkeys' import SettingsHotkeys from './SettingsHotkeys'
import SettingsCheckboxes from './SettingsCheckboxes'
import SettingsSelectors from './SettingsSelectors' import SettingsSelectors from './SettingsSelectors'
import SettingsCheckboxes from './SettingsCheckboxes'
@Component({ @Component({
components: { components: {

@ -55,6 +55,7 @@
"performance": "performance", "performance": "performance",
"choice-desktop": "Choice desktop", "choice-desktop": "Choice desktop",
"choice-language": "Choice language", "choice-language": "Choice language",
"generate-random-theme": "Generate random theme",
"keyboard": { "keyboard": {
"title": "Hotkeys", "title": "Hotkeys",
"open-themes": "Open theme", "open-themes": "Open theme",

@ -45,17 +45,20 @@
}, },
"settings": { "settings": {
"title": "Настройки", "title": "Настройки",
"blur": "Прозрачность", "blur": "Размытие",
"users": "Пользователи",
"no-transition": "Отключить анимацию", "no-transition": "Отключить анимацию",
"show-framerate": "Показывать частоту кадров", "show-framerate": "Показывать частоту кадров",
"only-ui": "Показывать только настройки", "only-ui": "Показывать только настройки",
"performance": "производительность", "performance": "производительность",
"generate-random-theme": "Генерировать случайную тему",
"keyboard": { "keyboard": {
"title": "Горячие клавишы", "title": "Горячие клавишы",
"open-themes": "Открыть темы", "open-themes": "Открыть темы",
"open-custom": "Открыть настройки темы", "open-custom": "Открыть настройки темы",
"open-settings": "Открыть общие настройки", "open-settings": "Открыть общие настройки",
"hide-windows": "Закрыть окна", "hide-windows": "Закрыть окна",
"show-password": "Показать пароль",
"randomize-theme": "Выбрать случайные настройки темы", "randomize-theme": "Выбрать случайные настройки темы",
"poweroff": "Выключить", "poweroff": "Выключить",
"restart": "Перезагрузить", "restart": "Перезагрузить",

@ -6,6 +6,7 @@ export interface AppSettings {
username: string; username: string;
desktop: string; desktop: string;
defaultColor: string; defaultColor: string;
generateRandomThemes: boolean;
bodyClass: Record<string, boolean>; bodyClass: Record<string, boolean>;
themes: AppTheme[]; themes: AppTheme[];
} }
@ -304,6 +305,7 @@ export const AppThemes: AppTheme[] = [
}, },
settings: [ settings: [
pxratio(), pxratio(),
hueInput(),
buildInputSlider({ value: 10, max: 15 }), buildInputSlider({ value: 10, max: 15 }),
buildInputSlider({ value: 1, max: 2.8, min: 0.2, name: 'size' }), buildInputSlider({ value: 1, max: 2.8, min: 0.2, name: 'size' }),
randomButton randomButton
@ -318,12 +320,13 @@ export const AppThemes: AppTheme[] = [
type: 'palette', type: 'palette',
label: 'input.slider-amount', label: 'input.slider-amount',
value: 0, value: 0,
// TODO: Add more colors
values: [ values: [
['#fcb2bf', '#cf56a1', '#8b2f97', '#511e78'], ['#fcb2bf', '#cf56a1', '#8b2f97', '#511e78'],
['#e3fdfd', '#cbf1f5', '#a6e3e9', '#71c9ce'],
['#e8f79a', '#49d292', '#3b445b', '#383746'], ['#e8f79a', '#49d292', '#3b445b', '#383746'],
['#f5f5f5', '#fc5185', '#3fc1c9', '#364f6b'] ['#f5f5f5', '#fc5185', '#3fc1c9', '#364f6b'],
['#00A8CC', '#0C7B93', '#27496D', '#142850'],
['#F9F7F7', '#DBE2EF', '#3F72AF', '#112D4E'],
['#ABEDD8', '#46CDCF', '#3D84A8', '#48466D']
] ]
}, },
{ {

@ -20,7 +20,7 @@ import {
defaultTheme defaultTheme
} from '@/models/app' } from '@/models/app'
import { appWindow, LightdmSession, LightdmUsers } from '@/models/lightdm' import { appWindow, LightdmSession, LightdmUsers } from '@/models/lightdm'
import { generateRandomColor, generateRandomSliderValue, parseQueryValue, randomize } from '@/utils/helper' import { generateRandomColor, generateRandomSliderValue, isDifferentRoute, parseQueryValue, randomize, randomizeSettingsTheme } from '@/utils/helper'
export interface AppState extends AppSettings { export interface AppState extends AppSettings {
themes: AppTheme[]; themes: AppTheme[];
@ -43,7 +43,8 @@ class App extends VuexModule implements AppState {
users = appWindow?.lightdm?.users || [] users = appWindow?.lightdm?.users || []
desktops = appWindow?.lightdm?.sessions || [] desktops = appWindow?.lightdm?.sessions || []
showPassword = false
generateRandomThemes = false
themes = AppThemes themes = AppThemes
bodyClass: Record<string, boolean> = { bodyClass: Record<string, boolean> = {
@ -62,7 +63,8 @@ class App extends VuexModule implements AppState {
bodyClass, bodyClass,
currentOs, currentOs,
currentTheme, currentTheme,
defaultColor defaultColor,
generateRandomThemes
} = this } = this
return { return {
@ -72,7 +74,8 @@ class App extends VuexModule implements AppState {
bodyClass, bodyClass,
currentOs, currentOs,
currentTheme, currentTheme,
defaultColor defaultColor,
generateRandomThemes
} }
} }
@ -158,24 +161,8 @@ class App extends VuexModule implements AppState {
@Action @Action
randomizeSettingsTheme() { randomizeSettingsTheme() {
const theme = this.activeTheme const theme = this.activeTheme
const generateValueObject: Record<string, (input: AppInputThemeSlider) => AppInputThemeValue> = { theme.settings = randomizeSettingsTheme(theme)
slider: (input: AppInputThemeSlider) => generateRandomSliderValue(input),
checkbox: () => Math.random() > 0.5,
color: () => generateRandomColor(),
palette: (input: AppInputThemeGeneral) => Math.floor(randomize(0, (input.values?.length || 2) - 1))
}
theme.settings = theme.settings?.map(input => {
const changeValueFunction = generateValueObject[input.type]
if (changeValueFunction) {
input.value = changeValueFunction(input as AppInputThemeSlider)
}
return input
})
this.syncSettingsWithCache()
this.syncStoreWithQuery() this.syncStoreWithQuery()
} }
@ -193,7 +180,6 @@ class App extends VuexModule implements AppState {
this.syncThemeColor() this.syncThemeColor()
this.syncStoreWithQuery() this.syncStoreWithQuery()
this.syncSettingsWithCache()
} }
@Action @Action
@ -210,11 +196,14 @@ class App extends VuexModule implements AppState {
if (input) { if (input) {
this.CHANGE_THEME_INPUT({ input, value }) this.CHANGE_THEME_INPUT({ input, value })
this.syncSettingsWithCache()
} }
} }
@Action
toggleShowPassword() {
this.SET_STATE_APP({ key: 'showPassword', value: !this.showPassword })
}
@Action @Action
syncSettingsWithCache() { syncSettingsWithCache() {
localStorage.setItem('settings', JSON.stringify(this.getMainSettings)) localStorage.setItem('settings', JSON.stringify(this.getMainSettings))
@ -249,29 +238,47 @@ class App extends VuexModule implements AppState {
return query return query
}, {}) }, {})
$router.push({ name: $route.name || '/', query: { ...inputQuery, ...bodyClassQuery, themeName: this.currentTheme } }) const query = { ...inputQuery, ...bodyClassQuery, themeName: this.currentTheme }
const routeTo = { name: $route.name || '/', query }
const mayReplace = isDifferentRoute(routeTo)
if (mayReplace) {
$router.replace(routeTo)
}
} }
@Action @Action
syncThemeWithStore({ settings, query }: { settings: AppSettings; query: Route['query'] }) { syncThemeWithStore({ settings, query }: { settings: AppSettings; query: Route['query'] }) {
const themeName = query.themeName as string || settings.currentTheme let themeName = query.themeName as string || settings.currentTheme
const { generateRandomThemes } = settings
const indexTheme = Math.floor(randomize(0, this.themes.length - 1))
const syncTheme = this.themes.reduce((themes: AppTheme[], theme) => { const syncTheme = this.themes.reduce((themes: AppTheme[], theme, index) => {
const cachedTheme = settings.themes.find(({ name }) => name === theme.name) const cachedTheme = settings.themes.find(({ name }) => name === theme.name)
const isActiveTheme = theme.name === themeName const isActiveTheme = generateRandomThemes ? indexTheme === index : theme.name === themeName
const hasCachedTheme = cachedTheme && cachedTheme?.settings
if (cachedTheme && cachedTheme?.settings) {
theme.settings = theme.settings?.map(input => { if (hasCachedTheme) {
const cachedThemeInput = this.getThemeInput(input.name, cachedTheme) const randomSettings = isActiveTheme && generateRandomThemes
let value = cachedThemeInput?.value ?? input.value console.log({ indexTheme, index, randomSettings })
if (isActiveTheme) { if (randomSettings) {
const queryThemeInput = input.name in query ? parseQueryValue(query[input.name] as string) : null themeName = theme.name
value = queryThemeInput ?? value }
}
theme.settings = randomSettings
return Object.assign(input, { value }) ? randomizeSettingsTheme(theme)
}) : theme.settings?.map(input => {
const cachedThemeInput = this.getThemeInput(input.name, cachedTheme)
let value = cachedThemeInput?.value ?? input.value
if (isActiveTheme) {
const queryThemeInput = input.name in query ? parseQueryValue(query[input.name] as string) : null
value = queryThemeInput ?? value
}
return Object.assign(input, { value })
})
} }
themes.push(theme) themes.push(theme)
@ -302,6 +309,7 @@ class App extends VuexModule implements AppState {
try { try {
const settings: AppSettings = JSON.parse(localStorage.getItem('settings') || '{}') const settings: AppSettings = JSON.parse(localStorage.getItem('settings') || '{}')
this.SET_STATE_APP({ key: 'generateRandomThemes', value: settings.generateRandomThemes || false })
if (settings.themes) { if (settings.themes) {
this.syncThemeWithStore({ settings, query }) this.syncThemeWithStore({ settings, query })
@ -324,9 +332,7 @@ class App extends VuexModule implements AppState {
this.SET_STATE_APP({ key: 'currentOs', value: settings.currentOs || 'arch-linux' }) this.SET_STATE_APP({ key: 'currentOs', value: settings.currentOs || 'arch-linux' })
this.SET_STATE_APP({ key: 'desktop', value: settings.desktop }) this.SET_STATE_APP({ key: 'desktop', value: settings.desktop })
this.SET_STATE_APP({ key: 'username', value: settings.username }) this.SET_STATE_APP({ key: 'username', value: settings.username })
this.syncSettingsWithCache()
} catch (error) { } catch (error) {
this.syncSettingsWithCache()
this.setUpSettings() this.setUpSettings()
} }
} }

@ -2,7 +2,8 @@
font-size 1.5rem font-size 1.5rem
line-height 1.2 line-height 1.2
font-weight 300 font-weight 300
text-transform capitalize &:first-letter
text-transform uppercase
.position-center .position-center
position absolute position absolute

@ -1,8 +1,10 @@
import { AppInputThemeSlider } from '@/models/app' import { AppInputThemeGeneral, AppInputThemeSlider, AppInputThemeValue, AppTheme } from '@/models/app'
import { appWindow } from '@/models/lightdm' import { appWindow } from '@/models/lightdm'
import { AppModule } from '@/store/app' import { AppModule } from '@/store/app'
import { PageModule } from '@/store/page' import { PageModule } from '@/store/page'
import { debounce, DebounceSettings } from 'lodash' import { debounce, DebounceSettings } from 'lodash'
import { RawLocation } from 'vue-router'
import router from '../router'
const isFinalBuild = process.env.VUE_APP_VIEW === 'build' const isFinalBuild = process.env.VUE_APP_VIEW === 'build'
export const modKey = 'ctrl' export const modKey = 'ctrl'
@ -14,6 +16,13 @@ export const languageMap: Record<string, string> = {
es: 'Español' es: 'Español'
} }
export function isDifferentRoute(to: RawLocation) {
const { app: { $route, $router } } = router
const resolve = $router.resolve(to)
return $route.fullPath !== resolve.href
}
export function Debounce(time = 500, options?: DebounceSettings): MethodDecorator { export function Debounce(time = 500, options?: DebounceSettings): MethodDecorator {
const map = new Map<number, any>() const map = new Map<number, any>()
@ -151,3 +160,22 @@ export function stopPropagation(event: Event, callback?: Function) {
export function hasSomeParentClass(element: HTMLElement, tag: string): boolean { export function hasSomeParentClass(element: HTMLElement, tag: string): boolean {
return !!element.closest(tag) return !!element.closest(tag)
} }
export function randomizeSettingsTheme(theme: AppTheme) {
const generateValueObject: Record<string, (input: AppInputThemeSlider) => AppInputThemeValue> = {
slider: (input: AppInputThemeSlider) => generateRandomSliderValue(input),
checkbox: () => Math.random() > 0.5,
color: () => generateRandomColor(),
palette: (input: AppInputThemeGeneral) => Math.floor(randomize(0, (input.values?.length || 2) - 1))
}
return theme.settings?.map(input => {
const changeValueFunction = generateValueObject[input.type]
if (changeValueFunction) {
input.value = changeValueFunction(input as AppInputThemeSlider)
}
return input
})
}

Loading…
Cancel
Save