diff --git a/CHANGELOG.md b/CHANGELOG.md index cff1a41..be9f55f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # easyNWK Version History +## version 2.5.0, released ... 2024 + +* (feature) optionally set emoji for ego and each alter +* (usability) version slider always on as soon as more than 1 version +* (usability) filename of PDF with date in YYYY-MM-dd + ## version 2.4.0, released 28 Aug 2024 * (feature) opening and importing .nwk files created with easyNWK 1.5 diff --git a/package-lock.json b/package-lock.json index 3139e62..d21a99f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "easynwk", - "version": "2.4.0", + "version": "2.5.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "easynwk", - "version": "2.4.0", + "version": "2.5.0", "dependencies": { "@fortawesome/fontawesome-svg-core": "^1.2.35", "@fortawesome/free-solid-svg-icons": "^5.15.3", @@ -17,6 +17,7 @@ "d3": "^7.0.0", "vue": "^3.2.13", "vue-router": "^4.0.3", + "vue3-emoji-picker": "^1.1.8", "vuex": "^4.0.0" }, "devDependencies": { @@ -1990,6 +1991,15 @@ "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", "dev": true }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@sideway/address": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", @@ -7886,6 +7896,11 @@ "postcss": "^8.1.0" } }, + "node_modules/idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" + }, "node_modules/ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -12274,6 +12289,19 @@ "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "dev": true }, + "node_modules/vue3-emoji-picker": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/vue3-emoji-picker/-/vue3-emoji-picker-1.1.8.tgz", + "integrity": "sha512-k9tVHeQEBVLzVCLYAkFaI1nib3FJFQwdPhWD5khJkhks3ktg3g12z5wPGOSDpIuSLNtelRGvq1qdmZuJu5khfA==", + "dependencies": { + "@popperjs/core": "^2.11.0", + "idb": "^7.1.0", + "vue": "^3.2.23" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/vuex": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz", @@ -14405,6 +14433,11 @@ "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==", "dev": true }, + "@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==" + }, "@sideway/address": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", @@ -18825,6 +18858,11 @@ "dev": true, "requires": {} }, + "idb": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz", + "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==" + }, "ieee754": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", @@ -22031,6 +22069,16 @@ "integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==", "dev": true }, + "vue3-emoji-picker": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/vue3-emoji-picker/-/vue3-emoji-picker-1.1.8.tgz", + "integrity": "sha512-k9tVHeQEBVLzVCLYAkFaI1nib3FJFQwdPhWD5khJkhks3ktg3g12z5wPGOSDpIuSLNtelRGvq1qdmZuJu5khfA==", + "requires": { + "@popperjs/core": "^2.11.0", + "idb": "^7.1.0", + "vue": "^3.2.23" + } + }, "vuex": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/vuex/-/vuex-4.0.2.tgz", diff --git a/package.json b/package.json index ac2dc8e..9fb92ac 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "easynwk", - "version": "2.4.0", + "version": "2.5.0", "private": true, "author": "Alexander Rind (https://github.com/alex-rind/)", "repository": "https://github.com/fhstp/easynwk-web/", @@ -20,6 +20,7 @@ "d3": "^7.0.0", "vue": "^3.2.13", "vue-router": "^4.0.3", + "vue3-emoji-picker": "^1.1.8", "vuex": "^4.0.0" }, "devDependencies": { diff --git a/src/assets/variables.scss b/src/assets/variables.scss index b672a12..249677f 100644 --- a/src/assets/variables.scss +++ b/src/assets/variables.scss @@ -1,7 +1,7 @@ // Set your brand colors $nwkorange: hsl(32, 100%, 50%); $fhstpblue: #005096; -$nwkhorizon: #238b45; +$nwkhorizon: #1f793c; // Palette URL: http://paletton.com/#uid=30D0k0kw0w0ghLAnzAyxVmsHYdj */ diff --git a/src/components/AlteriEditForm.vue b/src/components/AlteriEditForm.vue index 65f37e2..983e21d 100644 --- a/src/components/AlteriEditForm.vue +++ b/src/components/AlteriEditForm.vue @@ -62,6 +62,66 @@ +
+
+ +
+
+
+
+
+
+ {{ + selectedEmoji == null || selectedEmoji.length < 1 + ? t("noemoji") + : selectedEmoji + }} +
+
+
+
+
+ +
+
+ +
+
+ +
+
+
@@ -229,6 +289,8 @@ import { SYMBOL_DECEASED } from "@/assets/utils"; import { TAB_BASE } from "@/store/sessionModule"; import de from "@/de"; import en from "@/en"; +import EmojiPicker from "vue3-emoji-picker"; +import "vue3-emoji-picker/css"; type InputType = HTMLInputElement | HTMLTextAreaElement; @@ -258,12 +320,17 @@ export default defineComponent({ // toogled after each click on the map (resets keyboard cursor) mapclicked: Boolean, }, + components: { + EmojiPicker, + }, + setup(props) { const store = useStore(); const addingNewAlter = ref(!(props.alter?.name.length > 0)); - const selectedRoleLabel = ref(props.alter?.role); + + const showEmojiPicker = ref(false); // name field is special because it must not be empty // the data item is only used for validity check & never stored @@ -282,6 +349,32 @@ export default defineComponent({ return props.alter?.distance <= 0; }); + const selectedEmoji = ref(props.alter?.emoji || ""); + + + function onSelectEmoji(emoji: any) { + selectedEmoji.value = emoji.i; + showEmojiPicker.value = false; + commitEditEmoji(emoji.i); + } + + const commitEditEmoji = (emoji: string) => { + const payload = { + index: store.state.session.editIndex, + changes: { emoji: emoji }, + }; + store.commit("editAlter", payload); + }; + + function removeEmoji() { + selectedEmoji.value = ""; + commitEditEmoji(""); + } + + function toggleEmojiPicker() { + showEmojiPicker.value = !showEmojiPicker.value; + } + // getter & setter for select dropdown function accessor(field: keyof Alter) { return computed({ @@ -437,14 +530,20 @@ export default defineComponent({ alterDeceased: accessor("deceased"), alterEdgeType: accessor("edgeType"), isConnectable: computed(() => isConnectable(props.alter as Alter)), + emoji: computed(() => store.state.view.emoji), commitEdit, focusRole, + onSelectEmoji, + removeEmoji, + toggleEmojiPicker, blurRole, genderOptions, roleOptions, engRoleOptions, editAlterFinished, cancelAddAlter, + selectedEmoji, + showEmojiPicker, altername, domButton, SYMBOL_DECEASED, @@ -475,7 +574,7 @@ input::-webkit-calendar-picker-indicator { @import "~bulma/sass/base/_all.sass"; .autovalue { - color: $grey-light; + color: #656565; } .autovalue:focus { @@ -485,4 +584,15 @@ input::-webkit-calendar-picker-indicator { select > option { color: $text-strong; } + +.dropdown-menu { + display: none; + position: sticky; + z-index: 10; + width: 20em; +} + +.dropdown.is-active .dropdown-menu { + display: block; +} diff --git a/src/components/AlteriPanelEntry.vue b/src/components/AlteriPanelEntry.vue index 7a7ca10..ddb64f3 100644 --- a/src/components/AlteriPanelEntry.vue +++ b/src/components/AlteriPanelEntry.vue @@ -203,8 +203,7 @@ export default defineComponent({ padding: 3px 0px; } -@import "~bulma/sass/base/_all.sass"; .autovalue { - color: $grey-light; + color: #656565; } diff --git a/src/components/EgoEditForm.vue b/src/components/EgoEditForm.vue index 9d3fc70..e920ac6 100644 --- a/src/components/EgoEditForm.vue +++ b/src/components/EgoEditForm.vue @@ -26,6 +26,65 @@
+
+
+ +
+
+
+
+
+
+ {{ + selectedEmoji == null || selectedEmoji.length < 1 + ? t("noemoji") + : selectedEmoji + }} +
+
+
+
+
+ +
+
+ +
+
+ +
+
+
@@ -95,6 +154,8 @@ import { Ego } from "@/data/Ego"; import { Gender } from "@/data/Gender"; import de from "@/de"; import en from "@/en"; +import EmojiPicker from "vue3-emoji-picker"; +import "vue3-emoji-picker/css"; type InputType = HTMLInputElement | HTMLTextAreaElement; @@ -105,6 +166,9 @@ export default defineComponent({ return this[document.documentElement.lang][prop]; }, }, + components: { + EmojiPicker, + }, setup(props, { emit }) { const store = useStore(); @@ -112,6 +176,9 @@ export default defineComponent({ // the data item is only used for validity check & never stored const egoName = ref(store.state.nwk.ego.name); + const selectedEmoji = ref(store.state.nwk.ego.emoji || ""); + const showEmojiPicker = ref(false); + const egoNameInStore = computed(() => { return store.state.nwk.ego.name; }); @@ -144,6 +211,26 @@ export default defineComponent({ } }; + const commitEditEmoji = (emoji: string) => { + const payload = { emoji: emoji }; + store.commit("editEgo", payload); + }; + + function onSelectEmoji(emoji: any) { + selectedEmoji.value = emoji.i; + showEmojiPicker.value = false; + commitEditEmoji(emoji.i); + } + + function removeEmoji() { + selectedEmoji.value = ""; + commitEditEmoji(""); + } + + function toggleEmojiPicker() { + showEmojiPicker.value = !showEmojiPicker.value; + } + // apparently v-for needs this to be a data item const genderOptions = ref(Gender); @@ -177,6 +264,12 @@ export default defineComponent({ genderOptions, editEgoFinished, egofield, + selectedEmoji, + onSelectEmoji, + removeEmoji, + showEmojiPicker, + toggleEmojiPicker, + emoji: computed(() => store.state.view.emoji), }; }, }); @@ -186,4 +279,15 @@ export default defineComponent({ .panel-block { display: block; } + +.dropdown-menu { + display: none; + position: absolute; + z-index: 10; + width: 20em; +} + +.dropdown.is-active .dropdown-menu { + display: block; +} diff --git a/src/components/EgoHeader.vue b/src/components/EgoHeader.vue index e490130..d590b07 100644 --- a/src/components/EgoHeader.vue +++ b/src/components/EgoHeader.vue @@ -51,6 +51,7 @@ export default defineComponent({ #ego { display: flex; align-items: center; + color: black } #ego > :last-child { diff --git a/src/components/NetworkMap.vue b/src/components/NetworkMap.vue index 3eda983..716e25f 100644 --- a/src/components/NetworkMap.vue +++ b/src/components/NetworkMap.vue @@ -134,22 +134,47 @@ width="4" height="4" transform="translate(-2,-2)" + v-if="!emoji || !egoEmoji" /> + + {{ egoEmoji }} + - + @@ -742,6 +767,7 @@ export default defineComponent({ egoShape: computed(() => shapeByGender(true, store.state.nwk.ego.currentGender) ), + egoEmoji: computed(() => store.state.nwk.ego.emoji), isEditMode, isConnectMode, clickAlter, @@ -755,6 +781,7 @@ export default defineComponent({ getRoleShort, alteriNames: computed(() => store.state.view.alteriNames), connections: computed(() => store.state.view.connections), + emoji: computed(() => store.state.view.emoji), brushBtns, isClusterConnectPossible, isClusterFullyConnected, diff --git a/src/components/ViewOptionsPanel.vue b/src/components/ViewOptionsPanel.vue index abe9e9f..a0ccf2a 100644 --- a/src/components/ViewOptionsPanel.vue +++ b/src/components/ViewOptionsPanel.vue @@ -62,6 +62,12 @@ {{ t("connectionson") }}
+
+ +
@@ -138,6 +144,7 @@ export default defineComponent({ togglePseudonyms: () => store.commit("pseudonym/toggle"), horizons: accessFlag("horizons"), connections: accessFlag("connections"), + emoji: accessFlag("emoji"), alteriNames: accessFlag("alteriNames"), isOpen, showAge: accessFlag("ageInNwk"), diff --git a/src/data/Alter.ts b/src/data/Alter.ts index 7342c13..6497223 100644 --- a/src/data/Alter.ts +++ b/src/data/Alter.ts @@ -23,6 +23,7 @@ export interface Alter { /** distance from center normalized to 100 for the outer horizont. */ distance: number; + emoji: string; } export function initAlter(): Alter { @@ -41,6 +42,7 @@ export function initAlter(): Alter { edgeTypeByUser: -1, angle: 0, distance: 0, + emoji: "", }; } diff --git a/src/data/Ego.ts b/src/data/Ego.ts index 2b2fcdf..2fe4b2d 100644 --- a/src/data/Ego.ts +++ b/src/data/Ego.ts @@ -5,6 +5,7 @@ export interface Ego { age: string; currentGender: string; note: string; + emoji: string; } export function initEgo(): Ego { @@ -13,6 +14,7 @@ export function initEgo(): Ego { currentGender: defaultGender, age: "", note: "", + emoji: "", }; } diff --git a/src/data/ViewOptions.ts b/src/data/ViewOptions.ts index 21f757e..f13fdeb 100644 --- a/src/data/ViewOptions.ts +++ b/src/data/ViewOptions.ts @@ -1,6 +1,7 @@ export interface ViewOptionsFlags { horizons: boolean; connections: boolean; + emoji: boolean; alteriNames: boolean; ageInNwk: boolean; roleInNwk: boolean; @@ -15,6 +16,7 @@ export function initDefaultViewOptions(): ViewOptions { // pseudonyms: true, horizons: false, connections: true, + emoji: false, alteriNames: true, ageInNwk: false, roleInNwk: false, diff --git a/src/de.ts b/src/de.ts index 0602f7f..e6cabf0 100644 --- a/src/de.ts +++ b/src/de.ts @@ -78,6 +78,7 @@ export default { anonymiseon: "Anonymisieren", horizonson: "Horizonte", connectionson: "Verbindungen", + emojion: "Emojis", namesofcontactson: "Beschriftung der Kontakte", ageofcontactson: "zusätzlich: Alter (Jahre)", roleofcontactson: "zusätzlich: Rolle der Kontakte", @@ -133,6 +134,7 @@ export default { role: "Rolle", human: "Mensch", humanno: "Mensch: Nein", + selectedEmoji: "Gewähltes Emoji: ", agetitle: "Optional,soziales Alter der Kontaktperson", deceased: "verstorben", deceasedyes: "Verstroben: Ja", @@ -204,6 +206,9 @@ export default { date: "Datum", deleteversion: "Karte löschen", titleplaceholder: "Titel der aktuellen Version", + noemoji: "Noch kein Emoji gewählt", + selectemoji: "Emoji auswählen", + removeemoji: "Emoji entfernen", }, }; }, diff --git a/src/en.ts b/src/en.ts index 749ca49..67c4802 100644 --- a/src/en.ts +++ b/src/en.ts @@ -77,6 +77,7 @@ export default { anonymiseon: "Anonymise", horizonson: "Horizons", connectionson: "Connections", + emojion: "Emojis", namesofcontactson: "Labels for contacts", ageofcontactson: "Age of contacts", roleofcontactson: "Role of contacts", @@ -132,6 +133,7 @@ export default { role: "Role", human: "Human", humanno: "Human: No", + selectedEmoji: "Chosen emoji: ", agetitle: "Optional, social age of the contact", deceased: "deceased", deceasedyes: "Deceased: Yes", @@ -202,6 +204,9 @@ export default { date: "Date", deleteversion: "Delete map", titleplaceholder: "Title of the current version", + noemoji: "No emoji chosen yet", + selectemoji: "Select emoji", + removeemoji: "Remove emoji", }, }; }, diff --git a/src/shims-vue.d.ts b/src/shims-vue.d.ts index 3804a43..347cd58 100644 --- a/src/shims-vue.d.ts +++ b/src/shims-vue.d.ts @@ -1,6 +1,7 @@ /* eslint-disable */ -declare module '*.vue' { - import type { DefineComponent } from 'vue' - const component: DefineComponent<{}, {}, any> - export default component +declare module "*.vue" { + import type { DefineComponent } from "vue"; + const component: DefineComponent<{}, {}, any>; + export default component; } +declare module "vue3-emoji-picker";