Skip to content

Commit

Permalink
feat(Notes): Add an in-between menu for note creation
Browse files Browse the repository at this point in the history
  • Loading branch information
Kruptein authored Jan 21, 2024
1 parent cdfddf1 commit 35322b8
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 59 deletions.
5 changes: 3 additions & 2 deletions client/src/game/systems/notes/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ export type ClientNote = DistributiveOmit<ApiNote, "tags"> & {
};

export enum NoteManagerMode {
List,
AttachShape,
Create,
Edit,
List,
Map,
AttachShape,
}
180 changes: 180 additions & 0 deletions client/src/game/ui/notes/NoteCreate.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
<script setup lang="ts">
import { onDeactivated, ref } from "vue";
import type { ApiNote } from "../../../apiTypes";
import { uuidv4 } from "../../../core/utils";
import { coreStore } from "../../../store/core";
import { noteSystem } from "../../systems/notes";
import { noteState } from "../../systems/notes/state";
import { NoteManagerMode } from "../../systems/notes/types";
import { locationSettingsState } from "../../systems/settings/location/state";
const emit = defineEmits<(e: "mode", mode: NoteManagerMode) => void>();
const title = ref("");
const isLocal = ref(true);
onDeactivated(() => {
title.value = "";
isLocal.value = true;
});
async function createNote(): Promise<void> {
const uuid = uuidv4();
const note: ApiNote = {
uuid,
creator: coreStore.state.username,
title: title.value || "New note...",
text: "",
showOnHover: false,
showIconOnShape: false,
isRoomNote: isLocal.value,
location: isLocal.value ? locationSettingsState.reactive.activeLocation : null,
tags: [],
access: [],
shapes: [],
};
await noteSystem.newNote(note, true);
if (noteState.raw.shapeFilter) noteSystem.attachShape(uuid, noteState.raw.shapeFilter, true);
noteState.mutableReactive.currentNote = note.uuid;
emit("mode", NoteManagerMode.Edit);
}
</script>

<template>
<header>
<span id="return" title="Back to list" @click="$emit('mode', NoteManagerMode.List)">↩</span>
Create a new note
</header>
<div id="create-note">
<label for="new-note-title">Title:</label>
<input id="new-note-title" v-model="title" type="text" placeholder="New note..." autofocus />
<label for="new-note-type">Type:</label>
<div @click="isLocal = true">
<input type="radio" name="new-note-type" value="local" :checked="isLocal" />
<div>
<div>Local note</div>
<div>
A note that is relevant to the current campaign only. This is the most common kind of type and
should be used for most cases.
</div>
</div>
</div>
<div @click="isLocal = false">
<input type="radio" name="new-note-type" value="global" :checked="!isLocal" />
<div>
<div>Global note</div>
<div>
A note that will be visible in all campaigns. This is a special type that can be used to note down
information on common things like monster stats thare are used in multiple campaigns.
</div>
</div>
</div>
<button @click="createNote">Create note</button>
</div>
</template>

<style scoped lang="scss">
header {
display: flex;
font-size: 1.75em;
align-items: center;
#return {
margin-right: 1rem;
&:hover {
cursor: pointer;
font-weight: bold;
}
}
#title {
flex-grow: 1;
margin-right: 1rem;
border: none;
border-bottom: solid 1px black;
font-weight: bold;
font-size: inherit;
padding: 0.5rem;
&.edit:hover {
cursor: text;
}
}
}
#create-note {
display: grid;
grid-template-columns: auto 1fr;
align-items: center;
column-gap: 1rem;
row-gap: 1rem;
margin-top: 1rem;
> label {
font-weight: bold;
}
> input {
border-radius: 1rem;
padding: 0.5rem 1rem;
border-style: solid;
}
> div {
grid-column: 1/-1;
display: flex;
padding: 1rem;
border: solid 1px black;
&:hover {
cursor: pointer;
}
&:first-of-type {
border-top-left-radius: 1rem;
border-top-right-radius: 1rem;
margin-bottom: -1rem; // offset row-gap
border-bottom: none;
}
&:last-of-type {
border-bottom-left-radius: 1rem;
border-bottom-right-radius: 1rem;
}
> div {
display: flex;
flex-direction: column;
margin-left: 1rem;
> div:first-of-type {
font-weight: bold;
}
}
}
button {
background-color: lightblue;
border: solid 2px lightblue;
border-width: 1px;
border-radius: 1rem;
padding: 0.5rem 0.75rem;
grid-column: 1/-1;
width: 10rem;
&:hover {
cursor: pointer;
background-color: rgba(173, 216, 230, 0.5);
}
}
}
</style>
66 changes: 10 additions & 56 deletions client/src/game/ui/notes/NoteList.vue
Original file line number Diff line number Diff line change
@@ -1,22 +1,20 @@
<script setup lang="ts">
import { type DeepReadonly, computed, reactive, ref } from "vue";
import type { ApiNote } from "../../../apiTypes";
import { arrToToggleGroup } from "../../../core/components/toggleGroup";
import ToggleGroup from "../../../core/components/ToggleGroup.vue";
import { filter, map } from "../../../core/iter";
import { mostReadable, uuidv4 } from "../../../core/utils";
import { mostReadable } from "../../../core/utils";
import { coreStore } from "../../../store/core";
import { locationStore } from "../../../store/location";
import { type LocalId, getLocalId } from "../../id";
import { noteSystem } from "../../systems/notes";
import { noteState } from "../../systems/notes/state";
import type { ClientNote } from "../../systems/notes/types";
import { NoteManagerMode, type ClientNote } from "../../systems/notes/types";
import { popoutNote } from "../../systems/notes/ui";
import { propertiesState } from "../../systems/properties/state";
import { locationSettingsState } from "../../systems/settings/location/state";
const emit = defineEmits<(e: "edit-note" | "create-note") => void>();
const emit = defineEmits<(e: "mode", mode: NoteManagerMode) => void>();
const noteTypes = ["global", "local"] as const;
const selectedNoteTypes = ref<(typeof noteTypes)[number]>("local");
Expand Down Expand Up @@ -108,29 +106,9 @@ const visibleNotes = computed(() => {
};
});
async function createNote(isLocal: boolean): Promise<void> {
const uuid = uuidv4();
const note: ApiNote = {
uuid,
creator: coreStore.state.username,
title: "New note...",
text: "",
showOnHover: false,
showIconOnShape: false,
isRoomNote: isLocal,
location: isLocal ? locationSettingsState.reactive.activeLocation : null,
tags: [],
access: [],
shapes: [],
};
await noteSystem.newNote(note, true);
if (noteState.raw.shapeFilter) noteSystem.attachShape(uuid, noteState.raw.shapeFilter, true);
editNote(note.uuid);
}
function editNote(noteId: string): void {
noteState.mutableReactive.currentNote = noteId;
emit("edit-note");
emit("mode", NoteManagerMode.Edit);
}
function clearShapeFilter(): void {
Expand Down Expand Up @@ -287,12 +265,8 @@ function clearShapeFilter(): void {
</template>
<footer>
<div style="flex-grow: 1"></div>
<div id="new-note-selector">
<div>New note {{ shapeProps ? `for ${shapeProps.name}` : "" }}:</div>
<div id="selector-options">
<div @click="createNote(false)">Global</div>
<div @click="createNote(true)">Local</div>
</div>
<div id="new-note-selector" @click="$emit('mode', NoteManagerMode.Create)">
New note{{ shapeProps ? `for ${shapeProps.name}` : "" }}
</div>
</footer>
</template>
Expand Down Expand Up @@ -469,35 +443,15 @@ footer {
margin-top: 2rem;
#new-note-selector {
display: flex;
align-items: center;
background-color: lightblue;
border: solid 2px lightblue;
border-radius: 1rem;
overflow: hidden;
> div:first-child {
padding: 0.5rem 0.75rem;
margin-left: 0.5rem;
}
> div:last-child {
display: flex;
border-radius: 1rem;
border: solid 1px white;
background-color: white;
border-color: rgba(173, 216, 230, 0.5);
> div {
padding: 0.5rem 0.75rem;
padding: 0.5rem 0.75rem;
&:hover {
cursor: pointer;
background-color: rgba(173, 216, 230, 0.5);
}
}
&:hover {
cursor: pointer;
background-color: rgba(173, 216, 230, 0.5);
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion client/src/game/ui/notes/NoteManager.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { NoteManagerMode } from "../../systems/notes/types";
import { closeNoteManager } from "../../systems/notes/ui";
import NoteTool from "../tools/NoteTool.vue";
import NoteCreate from "./NoteCreate.vue";
import NoteEdit from "./NoteEdit.vue";
import NoteList from "./NoteList.vue";
Expand Down Expand Up @@ -34,7 +35,8 @@ function close(): void {
<div id="notes" @click="$emit('focus')">
<font-awesome-icon id="close-notes" :icon="['far', 'window-close']" @click="close" />
<KeepAlive>
<NoteList v-if="mode === NoteManagerMode.List" @edit-note="setMode(NoteManagerMode.Edit)" />
<NoteList v-if="mode === NoteManagerMode.List" @mode="setMode($event)" />
<NoteCreate v-else-if="mode === NoteManagerMode.Create" @mode="setMode($event)" />
<NoteEdit v-else-if="mode === NoteManagerMode.Edit" @mode="setMode($event)" />
</KeepAlive>
</div>
Expand Down

0 comments on commit 35322b8

Please sign in to comment.