From 4e51ca5509f5c924c1a5f27fe789d29ac7fa4af7 Mon Sep 17 00:00:00 2001 From: Madison Grubb Date: Sat, 14 Feb 2026 22:47:05 -0500 Subject: [PATCH] new nav system --- app/app.vue | 2 +- app/assets/css/main.css | 6 + app/components/AddUserModal.vue | 115 ++++++ app/components/AppDropdown.vue | 95 +++++ app/components/AppShell.vue | 89 +++++ app/components/BaseModal.vue | 36 ++ app/components/DeleteUserConfirmModal.vue | 46 +++ app/components/EditUserModal.vue | 95 +++++ app/components/KestrelMap.vue | 16 + app/components/MembersTable.vue | 133 +++++++ app/components/NavDrawer.vue | 113 ++++-- app/components/PoiModal.vue | 281 +++++++------ app/components/UserMenu.vue | 84 ++++ app/composables/useMediaQuery.js | 21 + app/layouts/default.vue | 72 +--- app/pages/account.vue | 88 ++++- app/pages/index.vue | 4 +- app/pages/members.vue | 460 ++-------------------- server/api/me.get.js | 8 +- server/api/me/avatar.delete.js | 14 + server/api/me/avatar.get.js | 23 ++ server/api/me/avatar.put.js | 32 ++ server/middleware/auth.js | 10 +- server/utils/db.js | 20 +- test/e2e/live-streaming.spec.js | 2 +- test/nuxt/NavDrawer.spec.js | 3 +- test/nuxt/default-layout.spec.js | 18 +- 27 files changed, 1198 insertions(+), 688 deletions(-) create mode 100644 app/components/AddUserModal.vue create mode 100644 app/components/AppDropdown.vue create mode 100644 app/components/AppShell.vue create mode 100644 app/components/BaseModal.vue create mode 100644 app/components/DeleteUserConfirmModal.vue create mode 100644 app/components/EditUserModal.vue create mode 100644 app/components/MembersTable.vue create mode 100644 app/components/UserMenu.vue create mode 100644 app/composables/useMediaQuery.js create mode 100644 server/api/me/avatar.delete.js create mode 100644 server/api/me/avatar.get.js create mode 100644 server/api/me/avatar.put.js diff --git a/app/app.vue b/app/app.vue index f8eacfa..4c26c91 100644 --- a/app/app.vue +++ b/app/app.vue @@ -1,5 +1,5 @@ diff --git a/app/assets/css/main.css b/app/assets/css/main.css index 66f7832..56a23fa 100644 --- a/app/assets/css/main.css +++ b/app/assets/css/main.css @@ -26,6 +26,8 @@ .drawer-backdrop-enter-active, .drawer-backdrop-leave-active { transition: opacity 0.2s ease; } .modal-enter-from, .modal-leave-to, .drawer-backdrop-enter-from, .drawer-backdrop-leave-to { opacity: 0; } +.dropdown-enter-active, .dropdown-leave-active { transition: opacity 0.15s ease, transform 0.15s ease; } +.dropdown-enter-from, .dropdown-leave-to { opacity: 0; transform: translateY(-4px); } .modal-enter-active .relative, .modal-leave-active .relative { transition: transform 0.2s ease; } .modal-enter-from .relative, .modal-leave-to .relative { transform: scale(0.96); } @@ -36,6 +38,10 @@ .kestrel-map-container { background: #000 !important; } +.kestrel-map-container .leaflet-container { + border: none !important; + outline: none !important; +} .kestrel-map-container .leaflet-tile-pane, .kestrel-map-container .leaflet-map-pane, .kestrel-map-container .leaflet-tile-container { diff --git a/app/components/AddUserModal.vue b/app/components/AddUserModal.vue new file mode 100644 index 0000000..4b0bf73 --- /dev/null +++ b/app/components/AddUserModal.vue @@ -0,0 +1,115 @@ + + + diff --git a/app/components/AppDropdown.vue b/app/components/AppDropdown.vue new file mode 100644 index 0000000..39c07ca --- /dev/null +++ b/app/components/AppDropdown.vue @@ -0,0 +1,95 @@ + + + diff --git a/app/components/AppShell.vue b/app/components/AppShell.vue new file mode 100644 index 0000000..0c7be21 --- /dev/null +++ b/app/components/AppShell.vue @@ -0,0 +1,89 @@ + + + diff --git a/app/components/BaseModal.vue b/app/components/BaseModal.vue new file mode 100644 index 0000000..23a4b32 --- /dev/null +++ b/app/components/BaseModal.vue @@ -0,0 +1,36 @@ + + + diff --git a/app/components/DeleteUserConfirmModal.vue b/app/components/DeleteUserConfirmModal.vue new file mode 100644 index 0000000..a10ca4c --- /dev/null +++ b/app/components/DeleteUserConfirmModal.vue @@ -0,0 +1,46 @@ + + + diff --git a/app/components/EditUserModal.vue b/app/components/EditUserModal.vue new file mode 100644 index 0000000..149a3d2 --- /dev/null +++ b/app/components/EditUserModal.vue @@ -0,0 +1,95 @@ + + + diff --git a/app/components/KestrelMap.vue b/app/components/KestrelMap.vue index 306b934..a88d352 100644 --- a/app/components/KestrelMap.vue +++ b/app/components/KestrelMap.vue @@ -201,6 +201,7 @@ function createMap(initialCenter) { updateMarkers() updatePoiMarkers() updateLiveMarkers() + nextTick(() => map.invalidateSize()) } function updateMarkers() { @@ -403,6 +404,8 @@ function initMapWithLocation() { ) } +let resizeObserver = null + onMounted(async () => { if (!import.meta.client || typeof document === 'undefined') return const [leaflet, offline] = await Promise.all([ @@ -422,6 +425,15 @@ onMounted(async () => { leafletRef.value = { L, offlineApi: offline } initMapWithLocation() document.addEventListener('click', onDocumentClick) + + nextTick(() => { + if (mapRef.value) { + resizeObserver = new ResizeObserver(() => { + mapContext.value?.map?.invalidateSize() + }) + resizeObserver.observe(mapRef.value) + } + }) }) function onDocumentClick(e) { @@ -430,6 +442,10 @@ function onDocumentClick(e) { onBeforeUnmount(() => { document.removeEventListener('click', onDocumentClick) + if (resizeObserver && mapRef.value) { + resizeObserver.disconnect() + resizeObserver = null + } destroyMap() }) diff --git a/app/components/MembersTable.vue b/app/components/MembersTable.vue new file mode 100644 index 0000000..60756a8 --- /dev/null +++ b/app/components/MembersTable.vue @@ -0,0 +1,133 @@ + + + diff --git a/app/components/NavDrawer.vue b/app/components/NavDrawer.vue index 6e710e8..fbaf8f4 100644 --- a/app/components/NavDrawer.vue +++ b/app/components/NavDrawer.vue @@ -1,8 +1,8 @@ diff --git a/app/composables/useMediaQuery.js b/app/composables/useMediaQuery.js new file mode 100644 index 0000000..e04dad5 --- /dev/null +++ b/app/composables/useMediaQuery.js @@ -0,0 +1,21 @@ +/** + * Reactive viewport media query. SSR-safe: defaults to true (mobile) so sidebar closed on first paint. + * @param {string} query - CSS media query, e.g. '(max-width: 767px)' + * @returns {import('vue').Ref} Ref that is true when the media query matches. + */ +export function useMediaQuery(query) { + const matches = ref(true) + let mql = null + const handler = (e) => { + matches.value = e.matches + } + onMounted(() => { + mql = window.matchMedia(query) + matches.value = mql.matches + mql.addEventListener('change', handler) + }) + onBeforeUnmount(() => { + if (mql) mql.removeEventListener('change', handler) + }) + return matches +} diff --git a/app/layouts/default.vue b/app/layouts/default.vue index 46abfea..24cb403 100644 --- a/app/layouts/default.vue +++ b/app/layouts/default.vue @@ -1,71 +1,7 @@ - - diff --git a/app/pages/account.vue b/app/pages/account.vue index fa755fa..29e49eb 100644 --- a/app/pages/account.vue +++ b/app/pages/account.vue @@ -4,6 +4,51 @@ Account +
+ +
+
+ + + {{ accountInitials }} + +
+
+ + +
+
+
+