logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe git clone https://anongit.hacktivis.me/git/pleroma-fe.git/
commit: 144d426864402606029157d8d0ac02c0e7e1912a
parent a8092de63808ff1445636f07e11f3602774f1438
Author: Henry Jameson <me@hjkos.com>
Date:   Tue, 24 Sep 2024 03:07:27 +0300

some initial work on theme editor

Diffstat:

Msrc/components/settings_modal/helpers/setting.js24++++++++++++++++++++----
Msrc/components/settings_modal/helpers/string_setting.vue1+
Msrc/components/settings_modal/settings_modal.scss8++++----
Msrc/components/settings_modal/settings_modal_user_content.js4++++
Msrc/components/settings_modal/settings_modal_user_content.vue7+++++++
Asrc/components/settings_modal/tabs/style_tab/style_tab.js40++++++++++++++++++++++++++++++++++++++++
Asrc/components/settings_modal/tabs/style_tab/style_tab.scss59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/components/settings_modal/tabs/style_tab/style_tab.vue138+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/i18n/en.json10++++++++++
9 files changed, 283 insertions(+), 8 deletions(-)

diff --git a/src/components/settings_modal/helpers/setting.js b/src/components/settings_modal/helpers/setting.js @@ -10,9 +10,13 @@ export default { ProfileSettingIndicator }, props: { + modelValue: { + type: String, + default: null + }, path: { type: [String, Array], - required: true + required: false }, disabled: { type: Boolean, @@ -68,7 +72,7 @@ export default { } }, created () { - if (this.realDraftMode && this.realSource !== 'admin') { + if (this.realDraftMode && (this.realSource !== 'admin' || this.path == null)) { this.draft = this.state } }, @@ -76,14 +80,14 @@ export default { draft: { // TODO allow passing shared draft object? get () { - if (this.realSource === 'admin') { + if (this.realSource === 'admin' || this.path == null) { return get(this.$store.state.adminSettings.draft, this.canonPath) } else { return this.localDraft } }, set (value) { - if (this.realSource === 'admin') { + if (this.realSource === 'admin' || this.path == null) { this.$store.commit('updateAdminDraft', { path: this.canonPath, value }) } else { this.localDraft = value @@ -91,6 +95,9 @@ export default { } }, state () { + if (this.path == null) { + return this.modelValue + } const value = get(this.configSource, this.canonPath) if (value === undefined) { return this.defaultState @@ -145,6 +152,9 @@ export default { return this.backendDescription?.suggestions }, shouldBeDisabled () { + if (this.path == null) { + return this.disabled + } const parentValue = this.parentPath !== undefined ? get(this.configSource, this.parentPath) : null return this.disabled || (parentValue !== null ? (this.parentInvert ? parentValue : !parentValue) : false) }, @@ -159,6 +169,9 @@ export default { } }, configSink () { + if (this.path == null) { + return (k, v) => this.$emit('modelValue:update', v) + } switch (this.realSource) { case 'profile': return (k, v) => this.$store.dispatch('setProfileOption', { name: k, value: v }) @@ -184,6 +197,7 @@ export default { return this.realSource === 'profile' }, isChanged () { + if (this.path == null) return false switch (this.realSource) { case 'profile': case 'admin': @@ -193,9 +207,11 @@ export default { } }, canonPath () { + if (this.path == null) return null return Array.isArray(this.path) ? this.path : this.path.split('.') }, isDirty () { + if (this.path == null) return false if (this.realSource === 'admin' && this.canonPath.length > 3) { return false // should not show draft buttons for "grouped" values } else { diff --git a/src/components/settings_modal/helpers/string_setting.vue b/src/components/settings_modal/helpers/string_setting.vue @@ -15,6 +15,7 @@ </template> <slot v-else /> </label> + {{ ' ' }} <input :id="path" class="input string-input" diff --git a/src/components/settings_modal/settings_modal.scss b/src/components/settings_modal/settings_modal.scss @@ -10,6 +10,10 @@ list-style-type: none; padding-left: 2em; + .btn:not(.dropdown-button) { + padding: 0 2em; + } + li { margin-bottom: 0.5em; } @@ -54,10 +58,6 @@ .btn { min-height: 2em; } - - .btn:not(.dropdown-button) { - padding: 0 2em; - } } } diff --git a/src/components/settings_modal/settings_modal_user_content.js b/src/components/settings_modal/settings_modal_user_content.js @@ -10,6 +10,7 @@ import GeneralTab from './tabs/general_tab.vue' import AppearanceTab from './tabs/appearance_tab.vue' import VersionTab from './tabs/version_tab.vue' import ThemeTab from './tabs/theme_tab/theme_tab.vue' +import StyleTab from './tabs/style_tab/style_tab.vue' import { library } from '@fortawesome/fontawesome-svg-core' import { @@ -17,6 +18,7 @@ import { faUser, faFilter, faPaintBrush, + faPalette, faBell, faDownload, faEyeSlash, @@ -29,6 +31,7 @@ library.add( faUser, faFilter, faPaintBrush, + faPalette, faBell, faDownload, faEyeSlash, @@ -48,6 +51,7 @@ const SettingsModalContent = { ProfileTab, GeneralTab, AppearanceTab, + StyleTab, VersionTab, ThemeTab }, diff --git a/src/components/settings_modal/settings_modal_user_content.vue b/src/components/settings_modal/settings_modal_user_content.vue @@ -21,6 +21,13 @@ <AppearanceTab /> </div> <div + :label="$t('settings.style.themes3.editor.title')" + icon="palette" + data-tab-name="style" + > + <StyleTab /> + </div> + <div :label="$t('settings.theme')" icon="paint-brush" data-tab-name="theme" diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.js b/src/components/settings_modal/tabs/style_tab/style_tab.js @@ -0,0 +1,40 @@ +// import { +// rgb2hex, +// hex2rgb, +// getContrastRatioLayers, +// relativeLuminance +// } from 'src/services/color_convert/color_convert.js' + +// import { +// getThemes +// } from 'src/services/style_setter/style_setter.js' + +// import { +// newImporter, +// newExporter +// } from 'src/services/export_import/export_import.js' + +// import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js' +// import { init } from 'src/services/theme_data/theme_data_3.service.js' +// import { +// getCssRules, +// getScopedVersion +// } from 'src/services/theme_data/css_utils.js' + +// import ColorInput from 'src/components/color_input/color_input.vue' +// import RangeInput from 'src/components/range_input/range_input.vue' +// import OpacityInput from 'src/components/opacity_input/opacity_input.vue' +// import ShadowControl from 'src/components/shadow_control/shadow_control.vue' +// import FontControl from 'src/components/font_control/font_control.vue' +// import ContrastRatio from 'src/components/contrast_ratio/contrast_ratio.vue' +// import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx' +// import Checkbox from 'src/components/checkbox/checkbox.vue' +/* eslint-disable no-unused-vars */ + +import Select from 'src/components/select/select.vue' +import Preview from './theme_preview.vue' + +import { defineOptions, ref } from 'vue' +const componentsContext = require.context('src', true, /\.style.js(on)?$/) +const componentNames = componentsContext.keys() +const componentName = ref(componentNames[0]) diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.scss b/src/components/settings_modal/tabs/style_tab/style_tab.scss @@ -0,0 +1,59 @@ +.StyleTab { + .setting-item { + padding-bottom: 0; + + .btn { + padding: 0 0.5em; + } + + &:not(:first-child) { + margin-top: 0.5em; + } + + &:not(:last-child) { + margin-bottom: 0.5em; + } + + &.heading { + display: grid; + align-items: baseline; + grid-template-columns: 1fr auto auto auto; + grid-gap: 0.5em; + + h2 { + flex: 1 0 auto; + } + } + + &.metadata { + display: flex; + + .setting-item { + flex: 2 0 auto; + } + + li { + text-align: right; + } + } + } + + .component-editor { + display: grid; + grid-template-columns: 10em, 1fr, 2fr; + grid-template-rows: auto 1fr; + grid-template-areas: + "variant" "preview" "controls", + "state" "preview" "controls"; + + .state-selector { + grid-area: state; + } + + .variant-selector { + grid-area: variant; + display: flex; + flex-direction: column; + } + } +} diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.vue b/src/components/settings_modal/tabs/style_tab/style_tab.vue @@ -0,0 +1,138 @@ +<script setup> +import { ref, computed } from 'vue' + +import Select from 'src/components/select/select.vue' +import Checkbox from 'src/components/checkbox/checkbox.vue' +import StringSetting from '../../helpers/string_setting.vue' +// import Preview from '../theme_tab/theme_preview.vue' + +import { library } from '@fortawesome/fontawesome-svg-core' +import { faFloppyDisk, faFolderOpen, faFile } from '@fortawesome/free-solid-svg-icons' + +library.add( + faFile, + faFloppyDisk, + faFolderOpen +) + +const name = ref('') +const author = ref('') +const license = ref('') +const website = ref('') + +// Getting existing components +const componentsContext = require.context('src', true, /\.style.js(on)?$/) +const componentKeys = componentsContext.keys() + +const componentsMap = new Map( + componentKeys + .map( + key => [key, componentsContext(key).default] + ) +) +// const componentValues = componentsMap.values() + +// Initializing selected component and its computed descendants +const selectedComponentKey = ref(componentKeys[0]) +const selectedComponentValue = computed(() => componentsMap.get(selectedComponentKey.value)) + +// const selectedComponentName = computed(() => selectedComponent.value.name) +const selectedComponentVariants = computed(() => { + return new Set([...(Object.keys(selectedComponentValue.value.variants || {})), 'normal']) +}) +const selectedComponentStates = computed(() => { + return new Set([...(Object.keys(selectedComponentValue.value.states || {})), 'normal']) +}) + +</script> + +<template> + <div class="StyleTab"> + <div class="setting-item heading"> + <h2>{{ $t('settings.style.themes3.editor.title') }}</h2> + <button + class="btn button-default" + @click="clearTheme" + > + <FAIcon icon="file" /> + {{ $t('settings.style.themes3.editor.new_style') }} + </button> + <button + class="btn button-default" + @click="importStyle" + > + <FAIcon icon="folder-open" /> + {{ $t('settings.style.themes3.editor.load_style') }} + </button> + <button + class="btn button-default" + @click="exportTheme" + > + <FAIcon icon="floppy-disk" /> + {{ $t('settings.style.themes3.editor.save_style') }} + </button> + </div> + <div class="setting-item metadata"> + <ul class="setting-list"> + <li> + <StringSetting v-model="name"> + {{ $t('settings.style.themes3.editor.style_name') }} + </StringSetting> + </li> + <li> + <StringSetting v-model="author"> + {{ $t('settings.style.themes3.editor.style_author') }} + </StringSetting> + </li> + <li> + <StringSetting v-model="license"> + {{ $t('settings.style.themes3.editor.style_license') }} + </StringSetting> + </li> + <li> + <StringSetting v-model="website"> + {{ $t('settings.style.themes3.editor.style_website') }} + </StringSetting> + </li> + </ul> + </div> + <div class="setting-item"> + <Select v-model="selectedComponentKey"> + <option + v-for="key in componentKeys" + :key="'component-' + key" + :value="key" + > + {{ componentsMap.get(key).name }} + </option> + </Select> + <div class="component-editor"> + <Select + v-model="selectedComponentVariant" + class="variant-selector" + > + <option + v-for="variant in selectedComponentVariants" + :key="'component-variant-' + variant" + > + {{ variant }} + </option> + </Select> + <ul class="state-selector"> + <li + v-for="state in selectedComponentStates" + :key="'component-variant-' + state" + > + <Checkbox + v-model="selectedComponentStates" + > + {{ state }} + </Checkbox> + </li> + </ul> + </div> + </div> + </div> +</template> + +<style src="./style_tab.scss" lang="scss"></style> diff --git a/src/i18n/en.json b/src/i18n/en.json @@ -753,6 +753,16 @@ "update_preview": "Update preview", "themes3": { "define": "Override", + "editor": { + "title": "Style", + "new_style": "New", + "load_style": "Open", + "save_style": "Save", + "style_name": "Stylesheet name", + "style_author": "Made by", + "style_license": "License", + "style_website": "Website" + }, "hacks": { "underlay_overrides": "Change underlay", "underlay_override_mode_none": "Theme default",