implement colour picker for profile icon

This commit is contained in:
liamcottle
2024-12-26 14:50:17 +13:00
parent 8596d4e406
commit 178cfde6c8
5 changed files with 145 additions and 63 deletions

32
package-lock.json generated
View File

@@ -24,7 +24,8 @@
"vis-data": "^7.1.9",
"vis-network": "^9.1.9",
"vite": "^6.0.5",
"vue-router": "^4.5.0"
"vue-router": "^4.5.0",
"vuetify": "^3.7.6"
},
"devDependencies": {
"electron": "^30.0.8",
@@ -5731,6 +5732,35 @@
"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": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@@ -109,6 +109,7 @@
"vis-data": "^7.1.9",
"vis-network": "^9.1.9",
"vite": "^6.0.5",
"vue-router": "^4.5.0"
"vue-router": "^4.5.0",
"vuetify": "^3.7.6"
}
}

View 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>

View File

@@ -20,75 +20,21 @@
<!-- colours -->
<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="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 -->
<div class="p-2">
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">Icon Colour</div>
<div>
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">Icon</div>
<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">
<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>
<ColourPickerDropdown v-model:colour="iconForegroundColour"/>
</div>
</div>
<!-- background colour -->
<div class="p-2">
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">Background Colour</div>
<div>
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">Background</div>
<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">
<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>
<ColourPickerDropdown v-model:colour="iconBackgroundColour"/>
</div>
</div>
@@ -124,9 +70,12 @@ import * as mdi from "@mdi/js";
import MaterialDesignIcon from "../../../../build/exe/lib/src/frontend/components/MaterialDesignIcon.vue";
import LxmfUserIcon from "../LxmfUserIcon.vue";
import DialogUtils from "../../js/DialogUtils";
import ColourPickerDropdown from "../ColourPickerDropdown.vue";
export default {
name: 'ProfilePage',
components: {
ColourPickerDropdown,
LxmfUserIcon,
MaterialDesignIcon,
},

View File

@@ -7,6 +7,16 @@ import "./fonts/RobotoMonoNerdFont/font.css";
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
window.axios = axios;
@@ -85,5 +95,6 @@ const router = createRouter({
createApp(App)
.use(router)
.use(vuetify)
.use(vClickOutside)
.mount('#app');