* use new df map

* close button top-right, link to same position in new map, use localStorage for modal dismissal

* update map image, iframe detection ignores new map modal

* update embed instructions

* pretty banner

* privacy policy update - routing

* launch the map language

* header stuff

* change donate link

* remove new map notice bc 301 on cf

* use user agent for alpr_counts

* news -> footnote4a

* remove blog scraper
This commit is contained in:
Will Freeman
2026-04-26 22:13:16 -06:00
committed by GitHub
parent ae861e8e7b
commit e8fcf30e5b
22 changed files with 392 additions and 948 deletions
+8 -4
View File
@@ -35,9 +35,9 @@ onMounted(() => {
const items = [
{ title: 'Home', icon: 'mdi-home', to: '/' },
{ title: 'Map', icon: 'mdi-map', to: '/map' },
{ title: 'Map', icon: 'mdi-map', href: 'https://maps.deflock.org' },
{ title: 'Learn', icon: 'mdi-school', to: '/what-is-an-alpr' },
{ title: 'News', icon: 'mdi-newspaper', to: '/blog' },
{ title: 'News', icon: 'mdi-newspaper', href: 'https://footnote4a.org/', target: '_blank' },
]
const contributeItems = [
@@ -95,10 +95,12 @@ watch(() => theme.global.name.value, (newTheme) => {
<div class="d-none d-md-flex ml-8 flex-grow-1">
<!-- Main navigation items -->
<div class="d-flex align-center">
<v-btn
v-for="item in items.slice(1)"
<v-btn
v-for="item in items.slice(1)"
:key="item.title"
:to="item.to"
:href="item.href"
:target="item.target"
variant="text"
class="mx-1"
:prepend-icon="item.icon"
@@ -196,6 +198,8 @@ watch(() => theme.global.name.value, (newTheme) => {
:key="item.title"
link
:to="item.to"
:href="item.href"
:target="item.target"
role="option"
>
<v-icon start>{{ item.icon }}</v-icon>
-63
View File
@@ -1,63 +0,0 @@
<template>
<v-dialog v-model="show" max-width="900">
<v-card>
<v-card-title class="text-center py-4 font-weight-bold">
<h3 class="headline">Welcome to DeFlock</h3>
</v-card-title>
<p class="mx-8 text-center">
DeFlock is powered by <b>crowdsourced data</b> from the OpenStreetMap community.
</p>
<v-divider class="mx-4 mt-4" />
<v-list class="text-center">
<v-list-item class="my-4">
<v-icon size="x-large" color="primary" class="mb-2">mdi-progress-pencil</v-icon>
<v-list-item-title class="font-weight-bold">The map is incomplete!</v-list-item-title>
<v-list-item-subtitle>
New locations are always being added.
</v-list-item-subtitle>
</v-list-item>
<v-list-item class="my-4">
<v-icon size="x-large" color="primary" class="mb-2">mdi-square-edit-outline</v-icon>
<v-list-item-title class="font-weight-bold">Add missing points!</v-list-item-title>
<v-list-item-subtitle>
Know of a missing ALPR? <router-link to="/report/id">Contribute</router-link> to the map.
</v-list-item-subtitle>
</v-list-item>
</v-list>
<div class="small text-grey-darken-2 text-center mx-4 mb-2">By using this site, you agree to our <router-link to="/terms">Terms of Service</router-link>.</div>
<v-card-actions>
<v-btn flat class="w-100" size="x-large" color="rgb(18, 151, 195)" variant="elevated" @click="acknowledge">Got it</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
const show = ref(false);
onMounted(() => {
if (!localStorage.getItem('acknowledged')) {
show.value = true;
}
});
function acknowledge() {
show.value = false;
localStorage.setItem('acknowledged', 'true');
}
</script>
<style scoped>
.no-small {
min-width: 160px;
}
.small {
font-size: 0.8rem;
}
</style>
+4 -5
View File
@@ -1,6 +1,5 @@
import { createRouter, createWebHistory } from 'vue-router'
import Landing from '../views/Landing.vue'
import Map from '../views/Map.vue'
import { useHead } from '@unhead/vue'
const router = createRouter({
@@ -25,11 +24,11 @@ const router = createRouter({
}
},
{
path: '/map',
path: '/legacy-map',
name: 'map',
component: Map,
component: () => import('../views/Map.vue'),
meta: {
title: 'ALPR Map | DeFlock'
title: 'ALPR Map (Legacy) | DeFlock'
}
},
{
@@ -204,7 +203,7 @@ router.beforeEach((to, from, next) => {
}
if (to.path === '/' && to.hash) {
next({ path: '/map', hash: to.hash })
next({ path: '/legacy-map', hash: to.hash })
} else {
next()
}
+4 -5
View File
@@ -3,11 +3,10 @@
<template #header>
<Hero
title="Support DeFlock"
subtitle="Your contributions help us fight for privacy and raise awareness about ALPR technology."
image-url="/donate.webp"
background-position="0 25%"
button-text="Donate Now"
button-href="https://github.com/sponsors/frillweeman"
button-href="https://buymeacoffee.com/deflock"
:opacity="0.25"
/>
</template>
@@ -16,9 +15,9 @@
<!-- GitHub Sponsors Section -->
<v-row justify="center" class="sponsors-section text-center">
<v-col cols="12" md="10">
<h2 class="mb-2">Our Amazing Sponsors</h2>
<h2 class="mb-2">Founding Sponsors</h2>
<p class="mb-8">
Want to see your name here? <a target="_blank" href="https://github.com/sponsors/frillweeman">Become a sponsor</a>, and your name will appear on this page!
<a target="_blank" href="https://buymeacoffee.com/deflock">We've made donating easier</a>, but if you want to see your name on this list, <a target="_blank" href="https://github.com/sponsors/frillweeman">sponsor us on GitHub!</a>
</p>
<v-row>
@@ -37,7 +36,7 @@
</v-col>
</v-row>
<!-- GitHub Sponsors Section -->
<!-- Special Thanks Section -->
<v-row justify="center" class="sponsors-section text-center mt-4">
<v-col cols="12" md="10">
<h2 class="mb-2">Special Thanks</h2>
+4 -27
View File
@@ -48,8 +48,8 @@
<ALPRCounter class="my-6" />
<v-btn size="large" color="rgb(18, 151, 195)" large @click="goToMap({ withCurrentLocation: true })">
Explore the Map
<v-btn size="large" color="rgb(18, 151, 195)" large href="https://maps.deflock.org">
Launch the Map
<v-icon end>mdi-map</v-icon>
</v-btn>
</v-col>
@@ -151,8 +151,8 @@
<!-- Map Section -->
<v-container fluid class="map-section py-10 text-center">
<h2 class="display-2 mb-4">Explore ALPR Locations Near You</h2>
<v-btn color="white" large @click="goToMap({ withCurrentLocation: true })">
View the Map
<v-btn color="white" large href="https://maps.deflock.org">
Launch the Map
<v-icon end>mdi-map</v-icon>
</v-btn>
</v-container>
@@ -259,14 +259,9 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import ALPRCounter from '@/components/ALPRCounter.vue';
import { useGlobalStore } from '@/stores/global';
import DefaultLayout from '@/layouts/DefaultLayout.vue';
const router = useRouter();
const { setCurrentLocation } = useGlobalStore();
interface ServiceAlert {
id: number;
date_updated: string | null;
@@ -294,22 +289,4 @@ onMounted(() => {
fetchServiceAlert();
});
interface GoToMapOptions {
withCurrentLocation?: boolean;
}
async function goToMap(options: GoToMapOptions = {}) {
if (options.withCurrentLocation) {
setCurrentLocation()
.then((currentLocation) => {
const [lat, lon] = currentLocation;
router.push({ path: '/map', hash: `#map=12/${lat.toFixed(6)}/${lon.toFixed(6)}` });
})
.catch(() => {
router.push({ path: '/map' });
});
} else {
router.push({ path: '/map' });
}
}
</script>
+6 -2
View File
@@ -1,5 +1,4 @@
<template>
<NewVisitor v-if="!isIframe" />
<ShareDialog v-model="shareDialogOpen" />
<div class="map-container" @keyup="handleKeyUp">
@@ -61,6 +60,12 @@
import 'leaflet/dist/leaflet.css';
import { ref, onMounted, computed } from 'vue';
import { useRouter } from 'vue-router'
import { useHead } from '@unhead/vue'
useHead({
link: [{ rel: 'canonical', href: 'https://maps.deflock.org' }],
meta: [{ name: 'robots', content: 'noindex, nofollow' }]
})
import type { Ref } from 'vue';
import { BoundingBox } from '@/services/apiService';
import { geocodeQuery } from '@/services/apiService';
@@ -72,7 +77,6 @@ import L from 'leaflet';
globalThis.L = L;
import 'leaflet/dist/leaflet.css'
import LeafletMap from '@/components/LeafletMap.vue';
import NewVisitor from '@/components/NewVisitor.vue';
import ShareDialog from '@/components/ShareDialog.vue';
const DEFAULT_ZOOM = 12;
+1 -12
View File
@@ -28,17 +28,7 @@
<h2>Embedding our Map</h2>
<p>
You are welcome to embed our map on your website. Use the following HTML snippet:
</p>
<p>
<DFCode>
&lt;iframe src=&quot;https://deflock.org/map&quot; width=&quot;100%&quot; height=&quot;600&quot; style=&quot;border: none;&quot;&gt;&lt;/iframe&gt;
</DFCode>
</p>
<p>
If you would like to <b>localize the URL</b> to a specific region, please zoom to the area at <router-link to="/map">https://deflock.org/map</router-link> and copy the URL from your browser's address bar.
You are welcome to embed our map on your website. Simply <a href="https://maps.deflock.org" target="_blank">click the share button on our map</a>, and copy the embed code.
</p>
<h2>Contact Us</h2>
@@ -53,5 +43,4 @@
<script setup lang="ts">
import DefaultLayout from '@/layouts/DefaultLayout.vue';
import Hero from '@/components/layout/Hero.vue';
import DFCode from "@/components/DFCode.vue";
</script>
+5
View File
@@ -13,6 +13,11 @@
DeFlock does not collect, store, or process any personal information about our users. We use local storage in your browser to anonymously identify first-time visitors for the purpose of showing an introductory message as well as to persist application state, including your dark/light theme preference. This data cannot be used to identify you personally. We do not use cookies, analytics, or tracking technologies on our website.
</p>
<h2>Route Calculation (maps.deflock.org)</h2>
<p>
On our maps page (<a href="https://maps.deflock.org">maps.deflock.org</a>), we offer a route planning feature that calculates routes designed to avoid ALPR cameras. When you request a route, your start and end coordinates are sent to our server solely for the purpose of computing the route. These coordinates are not logged or retained long-term.
</p>
<h2>Third-Party Services</h2>
<p>
DeFlock relies on OpenStreetMap (OSM) for map data and functionality. If you choose to contribute Automatic License Plate Recognition (ALPR) data or other content to OSM, you will interact directly with their platform. OSM may request personal information, such as your email address and name, to facilitate your contributions. Please refer to the OpenStreetMap Privacy Policy for details on their data practices.