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 }}
+
-
+
+
+
+ {{ mark.d.emoji }}
+
+
+
+
+
+
@@ -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";