diff --git a/CHANGELOG.md b/CHANGELOG.md index e009b9de..3460dca5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +# [1.0.0-rc.1] + +- Added Bookmarks functionality +- Added update popup + # [1.0.0-beta.6] - You can now save, export and share filters presets diff --git a/package.json b/package.json index 97cfd307..b88b79de 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vatsim-radar", - "version": "1.0.0-beta.6", + "version": "1.0.0-rc.1", "private": true, "type": "module", "scripts": { diff --git a/src/assets/update/aircraft.png b/src/assets/update/aircraft.png deleted file mode 100644 index f5cf397f..00000000 Binary files a/src/assets/update/aircraft.png and /dev/null differ diff --git a/src/assets/update/bookmarks.png b/src/assets/update/bookmarks.png new file mode 100644 index 00000000..90ea8d47 Binary files /dev/null and b/src/assets/update/bookmarks.png differ diff --git a/src/assets/update/client.jpg b/src/assets/update/client.jpg deleted file mode 100644 index 482697b2..00000000 Binary files a/src/assets/update/client.jpg and /dev/null differ diff --git a/src/assets/update/events.jpg b/src/assets/update/events.jpg deleted file mode 100644 index 2cbbbc73..00000000 Binary files a/src/assets/update/events.jpg and /dev/null differ diff --git a/src/assets/update/filters.png b/src/assets/update/filters.png new file mode 100644 index 00000000..0ddb455a Binary files /dev/null and b/src/assets/update/filters.png differ diff --git a/src/assets/update/friends.png b/src/assets/update/friends.png new file mode 100644 index 00000000..9e1688ef Binary files /dev/null and b/src/assets/update/friends.png differ diff --git a/src/assets/update/layouts.png b/src/assets/update/layouts.png new file mode 100644 index 00000000..48808d72 Binary files /dev/null and b/src/assets/update/layouts.png differ diff --git a/src/assets/update/presentation.png b/src/assets/update/presentation.png new file mode 100644 index 00000000..a07704c3 Binary files /dev/null and b/src/assets/update/presentation.png differ diff --git a/src/assets/update/search.png b/src/assets/update/search.png deleted file mode 100644 index b505e07b..00000000 Binary files a/src/assets/update/search.png and /dev/null differ diff --git a/src/assets/update/settings.png b/src/assets/update/settings.png deleted file mode 100644 index 148f320d..00000000 Binary files a/src/assets/update/settings.png and /dev/null differ diff --git a/src/assets/update/vatglasses.png b/src/assets/update/vatglasses.png new file mode 100644 index 00000000..12a38d65 Binary files /dev/null and b/src/assets/update/vatglasses.png differ diff --git a/src/components/common/vatsim/CommonBookmarkData.vue b/src/components/common/vatsim/CommonBookmarkData.vue new file mode 100644 index 00000000..bf5b977b --- /dev/null +++ b/src/components/common/vatsim/CommonBookmarkData.vue @@ -0,0 +1,225 @@ + + + + + diff --git a/src/components/map/MapMobileWindow.vue b/src/components/map/MapMobileWindow.vue index 3eac0b15..0b46f925 100644 --- a/src/components/map/MapMobileWindow.vue +++ b/src/components/map/MapMobileWindow.vue @@ -30,7 +30,7 @@ Favorite
- Save Current Settings + + Save Current Settings +
@@ -22,7 +24,7 @@ />
+ +
@@ -78,6 +85,7 @@ />
@@ -116,6 +124,7 @@ Share @@ -137,6 +146,12 @@
+ +
any; data: (settings: { preset: UserCustomPreset['json']; id?: number }) => any }>(); + const config = useRuntimeConfig(); export type UserCustomPreset = Omit & { [key: string]: any }; diff --git a/src/components/map/filters/MapFiltersTraffic.vue b/src/components/map/filters/MapFiltersTraffic.vue index abaed38f..21fad280 100644 --- a/src/components/map/filters/MapFiltersTraffic.vue +++ b/src/components/map/filters/MapFiltersTraffic.vue @@ -18,30 +18,68 @@ @@ -180,6 +191,7 @@ import { getVATSIMMemberStats } from '~/composables/data'; import CommonBubble from '~/components/common/basic/CommonBubble.vue'; import CommonSpoiler from '~/components/common/vatsim/CommonSpoiler.vue'; import CommonFavoriteList from '~/components/common/vatsim/CommonFavoriteList.vue'; +import ShareIcon from '@/assets/icons/kit/share.svg?component'; const props = defineProps({ overlay: { @@ -194,6 +206,8 @@ const mapStore = useMapStore(); const dataStore = useDataStore(); const map = inject>('map')!; const tab = ref('info'); +const config = useRuntimeConfig(); +const copy = useCopyText(); const atc = computed(() => { return findAtcByCallsign(props.overlay?.data.callsign); diff --git a/src/components/views/ViewFavorite.vue b/src/components/views/ViewFavorite.vue new file mode 100644 index 00000000..dbd59fb9 --- /dev/null +++ b/src/components/views/ViewFavorite.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/src/components/views/ViewMapFooter.vue b/src/components/views/ViewMapFooter.vue index b8547054..c4f2ea82 100644 --- a/src/components/views/ViewMapFooter.vue +++ b/src/components/views/ViewMapFooter.vue @@ -35,7 +35,7 @@
@@ -223,7 +223,7 @@ import MapFeaturedAirports from '~/components/map/MapFeaturedAirports.vue'; import CommonAirac from '~/components/common/vatsim/CommonAirac.vue'; import MapSettingsVatGlassesLevel from '~/components/map/filters/settings/MapSettingsVatGlassesLevel.vue'; import CommonBubble from '~/components/common/basic/CommonBubble.vue'; -import ViewUserList from '~/components/views/ViewUserList.vue'; +import ViewFavorite from '~/components/views/ViewFavorite.vue'; const store = useStore(); const dataStore = useDataStore(); diff --git a/src/components/views/ViewUpdatePopup.vue b/src/components/views/ViewUpdatePopup.vue index 7f520d01..d0e751db 100644 --- a/src/components/views/ViewUpdatePopup.vue +++ b/src/components/views/ViewUpdatePopup.vue @@ -32,7 +32,8 @@

- It's packed with a bunch of features. To get a video version, please visit our Showcase stream.`, + image: images['../../assets/update/presentation.png'], + imageRatio: '1920 / 1080', + description: `This update marks an important milestone for VATSIM Radar. Of course, no one considered it a beta anymore, but we still didn't have features people could get used to in other map services. Well, we do now.`, + list: [ + 'Airports Layouts: taximap for Navigraph Ultimate members', + 'Filters: VATSpy and FL24-inspired filters with an ability to share them with anyone', + 'Bookmarks: Bookmark any location or airport - and assign a key to quickly open it', + 'Friends: track users and view what are they doing, from flying to SUPing', + 'VATGlasses: a long-awaited integration developed by community member Felix', + ], + }, + { + title: 'Airports Layouts', + image: images['../../assets/update/layouts.png'], + description: 'VATSIM Radar expands it’s partnership with Navigraph, and now all Navigraph Unlimited subscribers can view Airports Layouts!', list: [ - 'Map Settings with never seen before customization', - 'Basic Events page', - 'Search', - 'Mobile version', - 'Desktop/Mobile PWA clients', + 'View airport map in many large airports with holding points, intersections, taxiways, and more', + 'Enjoy updated gates data for those airports - a great improvement especially for USA airports!', + 'Fallback to old system and disabled layers if needed in Map Settings', ], }, { - title: 'Map Settings', - image: images['../../assets/update/settings.png'], - description: 'Enjoy Map Settings - customize a bunch of stuff:', + title: 'Filters', + description: 'VATSpy and FlightRadar24-inspired filters with all the settings you may need. At least, we hope so...', + image: images['../../assets/update/filters.png'], list: [ - 'Enable Traffic Heatmap, emergency aircraft highlight', - 'Modify airport counters', - 'Hide almost anything on map - including personal info, ground traffic and "random" airports', - 'Customize how tracks are shown - including their color', - 'Speaking of - customize color and transparency of almost anything on map', - 'Save all of this as presets - and share those presets with friends!', + 'Filters pilots and ATC by callsigns, rating, and a friend list', + 'Filter departure/arrival airports for flights - or import them directly from ongoing events!', + 'Save your filters if you are logged in', + 'Share you filters with friends - even if they are not authorized!', ], }, { - title: 'Search', - image: images['../../assets/update/search.png'], + title: 'VATGlasses', + image: images['../../assets/update/vatglasses.png'], list: [ - 'Search for flights, atc, airports', - 'Search by CIDs, callsigns, and other things', - 'Customize how many search results are displayed', - 'Open overlays by clicking on anything you found', + 'Detailed sectors with vertical splits - very useful for Europe flights', + 'Developed by Felix', + 'Auto-enabled if you are logged in and in active flight', + 'Level is controllable in a footer', ], }, { - title: 'Clients + Mobile version', - image: images['../../assets/update/client.jpg'], + title: 'Friends', + image: images['../../assets/update/friends.png'], list: [ - 'Added mobile/tablet optimization', - 'Added "Install App" into "about" dropdown menu', - 'Added official PWA support', + 'Track your friends and view what are they doing', + 'Make friends lists with different names and colors', + 'Focus on your friend in one click', ], }, { - title: 'Events page', - image: images['../../assets/update/events.jpg'], + title: 'Bookmarks', + image: images['../../assets/update/bookmarks.png'], list: [ - 'Enjoy basic events page', - 'Prefile recommended routes on VATSIM/SimBrief', - 'View events airports on map', - 'More to come', + 'Bookmark airport or your current location', + 'Quickly access bookmarks via footer/header shortcut or keyboard binding', + 'Share any bookmark with anyone', ], }, { @@ -169,19 +179,25 @@ const update: Update = { description: 'Come visit our Discord for full changelog: https://vatsim-radar.com/discord', image: images['../../assets/update/quality.png'], list: [ - 'New aircraft icons from DotWallop: A20N, A338, A339, P28*, P51, PA24, U2, SR22, GLEX, BE60 (+ imporved model matching)', - 'Improved Approach TRACON label rendering (by Felix)', - 'Reduced data consumption', - 'Copy button for controllers frequencies', - 'Your current position on map/controller dashboard is now remembered in GET parameters for you to save last position/settings', - 'Added "Share" window into filters dropdown - usable for PWAs, and also you can copy link which includes overlay from here', + 'New aircraft icons from DotWallop: will add later', + 'New VATSpy-like layer', + 'Search can now be opened using CTRL+F', + 'Airline display into pilot popup', 'Many other changes, fixes and improvements', ], }, ], - active: false, + active: true, }; +if (!store.user?.hasCharts) { + update.features[1].list!.push('Subscription Options'); +} + +if (!store.user?.hasFms && store.user) { + update.features[1].list!.push(' Connect Navigraph'); +} + const shownFeatureIndex = ref(0); const shownFeature = computed(() => update.features[shownFeatureIndex.value]); @@ -241,7 +257,11 @@ const close = () => { width: 100vw; max-width: 650px; - height: var(--height); + min-height: var(--height); + + :deep(.navigraph) { + color: #d54a46; + } @include mobileOnly { width: 80dvw; @@ -260,6 +280,10 @@ const close = () => { border: 2px solid $darkgray800; border-radius: 8px; background: no-repeat top / cover; + + &--has-ratio { + height: auto; + } } &_text { @@ -328,5 +352,7 @@ const close = () => { } } } + + } diff --git a/src/components/views/header/ViewHeader.vue b/src/components/views/header/ViewHeader.vue index c6314a52..20adf943 100644 --- a/src/components/views/header/ViewHeader.vue +++ b/src/components/views/header/ViewHeader.vue @@ -107,7 +107,7 @@ - + {{ store.friends.length }} diff --git a/src/composables/fetchers/index.ts b/src/composables/fetchers/index.ts index ba0de214..505f5fa3 100644 --- a/src/composables/fetchers/index.ts +++ b/src/composables/fetchers/index.ts @@ -1,6 +1,8 @@ import { useStore } from '~/store'; import { toRaw } from 'vue'; import { isFetchError } from '~/utils/shared'; +import type { UserBookmark } from '~/utils/backend/handlers/bookmarks'; +import type { Map } from 'ol'; export async function sendUserPreset>(name: string, json: T, prefix: string, retryMethod: () => Promise) { const store = useStore(); @@ -21,3 +23,18 @@ export async function sendUserPreset>(name: string throw e; } } + +export const showBookmark = async (bookmark: UserBookmark, map: Map | null) => { + const zoom = bookmark.zoom ?? 14; + const dataStore = useDataStore(); + + if (bookmark.icao) { + showAirportOnMap(dataStore.vatspy.value!.data.keyAirports.icao[bookmark.icao]!, map, zoom); + } + else if (bookmark.coords) { + map?.getView()?.animate({ + center: bookmark.coords, + zoom: zoom, + }); + } +}; diff --git a/src/pages/index.vue b/src/pages/index.vue index 0309fc56..f13d25cd 100644 --- a/src/pages/index.vue +++ b/src/pages/index.vue @@ -162,6 +162,8 @@ import { setUserLocalSettings } from '~/composables/fetchers/map-settings'; import CommonInputText from '~/components/common/basic/CommonInputText.vue'; import CommonButton from '~/components/common/basic/CommonButton.vue'; import type { UserFilterPreset } from '~/utils/backend/handlers/filters'; +import type { UserBookmarkPreset } from '~/utils/backend/handlers/bookmarks'; +import { showBookmark } from '~/composables/fetchers'; const emit = defineEmits({ map(map: Ref) { @@ -180,6 +182,7 @@ const router = useRouter(); const route = useRoute(); const isDiscord = ref(route.query.discord === '1'); const filterId = ref(route.query.filter && +route.query.filter); +const bookmarkId = ref(route.query.bookmark && +route.query.bookmark); const isMobile = useIsMobile(); const isMobileOrTablet = useIsMobileOrTablet(); const config = useRuntimeConfig(); @@ -215,7 +218,7 @@ async function checkAndAddOwnAircraft() { return; } - const shouldTrack = initialOwnCheck || (!route.query.center && !route.query.pilot && !route.query.controller && !route.query.atc && !route.query.airport); + const shouldTrack = initialOwnCheck || (!route.query.center && !route.query.pilot && !route.query.controller && !route.query.atc && !route.query.airport && !route.query.bookmark); if (isPilotOnGround(aircraft)) { overlay = await mapStore.addPilotOverlay(store.user.cid, shouldTrack); @@ -443,6 +446,16 @@ const overlaysHeight = computed(() => { return mapStore.overlays.reduce((acc, { _maxHeight }) => acc + (_maxHeight ?? 0), 0) + (overlaysGap * (mapStore.overlays.length - 1)); }); +useLazyAsyncData('bookmarks', async () => { + if (store.user) { + await store.fetchBookmarks(); + } + + return true; +}, { + server: false, +}); + useHead(() => ({ link: [ { @@ -708,9 +721,44 @@ await setupDataFetch({ } } + if (bookmarkId.value) { + const bookmark = await $fetch(`/api/user/bookmarks/${ bookmarkId.value }`).catch(() => {}); + if (bookmark) { + showBookmark(bookmark.json, map.value); + } + } + success = true; }, }); + +onMounted(() => { + function handleKeys(event: KeyboardEvent) { + if (!event.ctrlKey && !event.altKey && !event.shiftKey && !event.metaKey) return; + + const bookmark = store.bookmarks.find(x => { + const binding = x.json.binding; + if (!binding?.keys) return false; + + return binding.code === event.code && binding.keys?.ctrl === event.ctrlKey && binding.keys.alt === event.altKey && binding.keys.meta === event.metaKey && binding.keys.shift === event.shiftKey; + }); + + if (!bookmark) return; + + event.preventDefault(); + showBookmark(bookmark.json, map.value); + } + + document.addEventListener('keydown', handleKeys, { + capture: true, + }); + + onBeforeUnmount(() => { + document.removeEventListener('keydown', handleKeys, { + capture: true, + }); + }); +});