implement colour picker for profile icon
This commit is contained in:
32
package-lock.json
generated
32
package-lock.json
generated
@@ -24,7 +24,8 @@
|
|||||||
"vis-data": "^7.1.9",
|
"vis-data": "^7.1.9",
|
||||||
"vis-network": "^9.1.9",
|
"vis-network": "^9.1.9",
|
||||||
"vite": "^6.0.5",
|
"vite": "^6.0.5",
|
||||||
"vue-router": "^4.5.0"
|
"vue-router": "^4.5.0",
|
||||||
|
"vuetify": "^3.7.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron": "^30.0.8",
|
"electron": "^30.0.8",
|
||||||
@@ -5731,6 +5732,35 @@
|
|||||||
"vue": "^3.2.0"
|
"vue": "^3.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vuetify": {
|
||||||
|
"version": "3.7.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.7.6.tgz",
|
||||||
|
"integrity": "sha512-lol0Va5HtMIqZfjccSD5DLv5v31R/asJXzc6s7ULy51PHr1DjXxWylZejhq0kVpMGW64MiV1FmA/p8eYQfOWfQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20 || >=14.13"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/johnleider"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": ">=4.7",
|
||||||
|
"vite-plugin-vuetify": ">=1.0.0",
|
||||||
|
"vue": "^3.3.0",
|
||||||
|
"webpack-plugin-vuetify": ">=2.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"typescript": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"vite-plugin-vuetify": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"webpack-plugin-vuetify": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|||||||
@@ -109,6 +109,7 @@
|
|||||||
"vis-data": "^7.1.9",
|
"vis-data": "^7.1.9",
|
||||||
"vis-network": "^9.1.9",
|
"vis-network": "^9.1.9",
|
||||||
"vite": "^6.0.5",
|
"vite": "^6.0.5",
|
||||||
"vue-router": "^4.5.0"
|
"vue-router": "^4.5.0",
|
||||||
|
"vuetify": "^3.7.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
91
src/frontend/components/ColourPickerDropdown.vue
Normal file
91
src/frontend/components/ColourPickerDropdown.vue
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
<template>
|
||||||
|
<div v-click-outside="{ handler: onClickOutsideMenu, capture: true }" class="cursor-default relative inline-block text-left">
|
||||||
|
|
||||||
|
<!-- menu button -->
|
||||||
|
<div ref="dropdown-button" @click.stop="toggleMenu">
|
||||||
|
<slot>
|
||||||
|
<div class="size-8 border border-gray-50 rounded shadow cursor-pointer" :style="{ 'background-color': colour }"></div>
|
||||||
|
</slot>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- drop down menu -->
|
||||||
|
<Transition
|
||||||
|
enter-active-class="transition ease-out duration-100"
|
||||||
|
enter-from-class="transform opacity-0 scale-95"
|
||||||
|
enter-to-class="transform opacity-100 scale-100"
|
||||||
|
leave-active-class="transition ease-in duration-75"
|
||||||
|
leave-from-class="transform opacity-100 scale-100"
|
||||||
|
leave-to-class="transform opacity-0 scale-95">
|
||||||
|
<div v-if="isShowingMenu" class="absolute left-0 z-10 ml-4">
|
||||||
|
<v-color-picker v-model="colourPickerValue" :modes="['hex']" hide-inputs hide-sliders show-swatches></v-color-picker>
|
||||||
|
</div>
|
||||||
|
</Transition>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import DropDownMenu from "./DropDownMenu.vue";
|
||||||
|
import IconButton from "./IconButton.vue";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'ColourPickerDropdown',
|
||||||
|
components: {
|
||||||
|
IconButton,
|
||||||
|
DropDownMenu,
|
||||||
|
},
|
||||||
|
emits: [
|
||||||
|
'update:colour',
|
||||||
|
],
|
||||||
|
props: {
|
||||||
|
colour: String,
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
isShowingMenu: false,
|
||||||
|
colourPickerValue: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
toggleMenu() {
|
||||||
|
if(this.isShowingMenu){
|
||||||
|
this.hideMenu();
|
||||||
|
} else {
|
||||||
|
this.showMenu();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showMenu() {
|
||||||
|
this.isShowingMenu = true;
|
||||||
|
},
|
||||||
|
hideMenu() {
|
||||||
|
this.isShowingMenu = false;
|
||||||
|
},
|
||||||
|
onClickOutsideMenu(event) {
|
||||||
|
if(this.isShowingMenu){
|
||||||
|
event.preventDefault();
|
||||||
|
this.hideMenu();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
watch:{
|
||||||
|
colour() {
|
||||||
|
// update internal colour picker value when parent changes value of v-model:colour
|
||||||
|
this.colourPickerValue = this.colour;
|
||||||
|
},
|
||||||
|
colourPickerValue() {
|
||||||
|
|
||||||
|
// get current colour picker value
|
||||||
|
var value = this.colourPickerValue;
|
||||||
|
|
||||||
|
// remove alpha channel from hex colour if present
|
||||||
|
if(value.length === 9){
|
||||||
|
value = value.substring(0, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fire v-model:colour update event
|
||||||
|
this.$emit("update:colour", value);
|
||||||
|
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -20,75 +20,21 @@
|
|||||||
<!-- colours -->
|
<!-- colours -->
|
||||||
<div class="bg-white dark:bg-zinc-800 rounded shadow">
|
<div class="bg-white dark:bg-zinc-800 rounded shadow">
|
||||||
<div class="flex border-b border-gray-300 dark:border-zinc-700 text-gray-700 dark:text-gray-200 p-2 font-semibold">Select your Colours</div>
|
<div class="flex border-b border-gray-300 dark:border-zinc-700 text-gray-700 dark:text-gray-200 p-2 font-semibold">Select your Colours</div>
|
||||||
<div class="divide-y divide-gray-300 dark:divide-zinc-700 text-gray-900 dark:text-gray-100">
|
<div class="flex p-2 space-x-2">
|
||||||
|
|
||||||
<!-- icon colour -->
|
<!-- icon colour -->
|
||||||
<div class="p-2">
|
<div>
|
||||||
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">Icon Colour</div>
|
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">Icon</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<select v-model="iconForegroundColour" class="bg-gray-50 dark:bg-zinc-700 border border-gray-300 dark:border-zinc-600 text-gray-900 dark:text-gray-100 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 dark:focus:ring-blue-600 dark:focus:border-blue-600 block w-full p-2.5">
|
<ColourPickerDropdown v-model:colour="iconForegroundColour"/>
|
||||||
<option value="#000000">Black</option>
|
|
||||||
<option value="#FFFFFF">White</option>
|
|
||||||
<option disabled></option>
|
|
||||||
<option value="#64748b">Slate</option>
|
|
||||||
<option value="#6b7280">Gray</option>
|
|
||||||
<option value="#71717a">Zinc</option>
|
|
||||||
<option value="#737373">Neutral</option>
|
|
||||||
<option value="#78716c">Stone</option>
|
|
||||||
<option disabled></option>
|
|
||||||
<option value="#ef4444">Red</option>
|
|
||||||
<option value="#f97316">Orange</option>
|
|
||||||
<option value="#f59e0b">Amber</option>
|
|
||||||
<option value="#eab308">Yellow</option>
|
|
||||||
<option value="#84cc16">Lime</option>
|
|
||||||
<option value="#22c55e">Green</option>
|
|
||||||
<option value="#10b981">Emerald</option>
|
|
||||||
<option value="#14b8a6">Teal</option>
|
|
||||||
<option value="#06b6d4">Cyan</option>
|
|
||||||
<option value="#0ea5e9">Sky</option>
|
|
||||||
<option value="#3b82f6">Blue</option>
|
|
||||||
<option value="#6366f1">Indigo</option>
|
|
||||||
<option value="#8b5cf6">Violet</option>
|
|
||||||
<option value="#a855f7">Purple</option>
|
|
||||||
<option value="#d946ef">Fuschia</option>
|
|
||||||
<option value="#ec4899">Pink</option>
|
|
||||||
<option value="#f43f5e">Rose</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- background colour -->
|
<!-- background colour -->
|
||||||
<div class="p-2">
|
<div>
|
||||||
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">Background Colour</div>
|
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">Background</div>
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<select v-model="iconBackgroundColour" class="bg-gray-50 dark:bg-zinc-700 border border-gray-300 dark:border-zinc-600 text-gray-900 dark:text-gray-100 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 dark:focus:ring-blue-600 dark:focus:border-blue-600 block w-full p-2.5">
|
<ColourPickerDropdown v-model:colour="iconBackgroundColour"/>
|
||||||
<option value="#000000">Black</option>
|
|
||||||
<option value="#FFFFFF">White</option>
|
|
||||||
<option disabled></option>
|
|
||||||
<option value="#64748b">Slate</option>
|
|
||||||
<option value="#6b7280">Gray</option>
|
|
||||||
<option value="#71717a">Zinc</option>
|
|
||||||
<option value="#737373">Neutral</option>
|
|
||||||
<option value="#78716c">Stone</option>
|
|
||||||
<option disabled></option>
|
|
||||||
<option value="#ef4444">Red</option>
|
|
||||||
<option value="#f97316">Orange</option>
|
|
||||||
<option value="#f59e0b">Amber</option>
|
|
||||||
<option value="#eab308">Yellow</option>
|
|
||||||
<option value="#84cc16">Lime</option>
|
|
||||||
<option value="#22c55e">Green</option>
|
|
||||||
<option value="#10b981">Emerald</option>
|
|
||||||
<option value="#14b8a6">Teal</option>
|
|
||||||
<option value="#06b6d4">Cyan</option>
|
|
||||||
<option value="#0ea5e9">Sky</option>
|
|
||||||
<option value="#3b82f6">Blue</option>
|
|
||||||
<option value="#6366f1">Indigo</option>
|
|
||||||
<option value="#8b5cf6">Violet</option>
|
|
||||||
<option value="#a855f7">Purple</option>
|
|
||||||
<option value="#d946ef">Fuschia</option>
|
|
||||||
<option value="#ec4899">Pink</option>
|
|
||||||
<option value="#f43f5e">Rose</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -124,9 +70,12 @@ import * as mdi from "@mdi/js";
|
|||||||
import MaterialDesignIcon from "../../../../build/exe/lib/src/frontend/components/MaterialDesignIcon.vue";
|
import MaterialDesignIcon from "../../../../build/exe/lib/src/frontend/components/MaterialDesignIcon.vue";
|
||||||
import LxmfUserIcon from "../LxmfUserIcon.vue";
|
import LxmfUserIcon from "../LxmfUserIcon.vue";
|
||||||
import DialogUtils from "../../js/DialogUtils";
|
import DialogUtils from "../../js/DialogUtils";
|
||||||
|
import ColourPickerDropdown from "../ColourPickerDropdown.vue";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ProfilePage',
|
name: 'ProfilePage',
|
||||||
components: {
|
components: {
|
||||||
|
ColourPickerDropdown,
|
||||||
LxmfUserIcon,
|
LxmfUserIcon,
|
||||||
MaterialDesignIcon,
|
MaterialDesignIcon,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,6 +7,16 @@ import "./fonts/RobotoMonoNerdFont/font.css";
|
|||||||
|
|
||||||
import App from './components/App.vue';
|
import App from './components/App.vue';
|
||||||
|
|
||||||
|
// init vuetify
|
||||||
|
import 'vuetify/styles';
|
||||||
|
import { createVuetify } from 'vuetify';
|
||||||
|
import * as components from 'vuetify/components';
|
||||||
|
import * as directives from 'vuetify/directives';
|
||||||
|
const vuetify = createVuetify({
|
||||||
|
components,
|
||||||
|
directives,
|
||||||
|
})
|
||||||
|
|
||||||
// provide axios globally
|
// provide axios globally
|
||||||
window.axios = axios;
|
window.axios = axios;
|
||||||
|
|
||||||
@@ -85,5 +95,6 @@ const router = createRouter({
|
|||||||
|
|
||||||
createApp(App)
|
createApp(App)
|
||||||
.use(router)
|
.use(router)
|
||||||
|
.use(vuetify)
|
||||||
.use(vClickOutside)
|
.use(vClickOutside)
|
||||||
.mount('#app');
|
.mount('#app');
|
||||||
|
|||||||
Reference in New Issue
Block a user