This commit is contained in:
Will Freeman
2025-12-31 16:39:39 -06:00
parent 472d9ad74b
commit 66098cad91
10 changed files with 160 additions and 239 deletions

View File

@@ -37,18 +37,11 @@ const items = [
{ title: 'Home', icon: 'mdi-home', to: '/' },
{ title: 'Map', icon: 'mdi-map', to: '/map' },
{ title: 'Learn', icon: 'mdi-school', to: '/what-is-an-alpr' },
{ title: 'Get Involved', icon: 'mdi-account-voice', to: '/get-involved' },
{ title: 'News', icon: 'mdi-newspaper', to: '/blog' },
]
const contributeItems = [
{ title: 'Submit Cameras', icon: 'mdi-map-marker-plus', to: '/report' },
{ title: 'Hang Signs', icon: 'mdi-sign-direction', to: '/store' },
{ title: 'Public Records', icon: 'mdi-file-document', to: '/foia' },
{ title: 'City Council', icon: 'mdi-account-voice', to: '/council' },
]
const metaItems = [
{ title: 'Discord', customIcon: '/icon-discord.svg', customIconDark: '/icon-discord-white.svg', customIconGrey: '/icon-discord-grey.svg', href: 'https://discord.gg/aV7v4R3sKT'},
{ title: 'Contact', icon: 'mdi-email-outline', to: '/contact' },
{ title: 'GitHub', icon: 'mdi-github', href: 'https://github.com/frillweeman/deflock'},
{ title: 'Donate', icon: 'mdi-heart', to: '/donate'},
@@ -108,71 +101,9 @@ watch(() => theme.global.name.value, (newTheme) => {
<v-spacer></v-spacer>
<!-- Contribute section -->
<div class="d-flex align-center">
<v-menu offset-y>
<template v-slot:activator="{ props }">
<v-btn
variant="text"
v-bind="props"
append-icon="mdi-chevron-down"
class="mx-1"
>
Contribute
<v-btn icon to="/contact" aria-label="Toggle Theme">
<v-icon>mdi-email-outline</v-icon>
</v-btn>
</template>
<v-list>
<v-list-item
v-for="item in contributeItems"
:key="item.title"
:to="item.to"
link
>
<template v-slot:prepend>
<v-icon>{{ item.icon }}</v-icon>
</template>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<!-- Get Involved section -->
<v-menu offset-y>
<template v-slot:activator="{ props }">
<v-btn
variant="text"
v-bind="props"
append-icon="mdi-chevron-down"
class="mx-1"
>
Get Involved
</v-btn>
</template>
<v-list>
<v-list-item
v-for="item in metaItems"
:key="item.title"
:to="item.to"
:href="item.href"
:target="item.href ? '_blank' : undefined"
link
>
<template v-slot:prepend>
<v-icon v-if="item.icon">{{ item.icon }}</v-icon>
<v-img
v-else-if="item.customIcon"
class="mr-8"
contain
width="24"
height="24"
:src="isDark ? item.customIconDark : item.customIconGrey"
/>
</template>
<v-list-item-title>{{ item.title }}</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</div>
</div>
<v-spacer class="d-md-none" />
@@ -204,23 +135,7 @@ watch(() => theme.global.name.value, (newTheme) => {
<v-divider class="my-2" aria-hidden="true" role="presentation" />
<v-list-subheader class="px-4">Contribute</v-list-subheader>
<v-list nav aria-label="Contribute Links">
<v-list-item
v-for="item in contributeItems"
:key="item.title"
link
:to="item.to"
role="option"
>
<v-icon v-if="item.icon" start>{{ item.icon }}</v-icon>
<span style="vertical-align: middle;">{{ item.title }}</span>
</v-list-item>
</v-list>
<v-divider class="my-2" aria-hidden="true" role="presentation" />
<v-list-subheader class="px-4">Get Involved</v-list-subheader>
<v-list-subheader class="px-4">More</v-list-subheader>
<v-list nav aria-label="Meta Links">
<v-list-item
v-for="item in metaItems"

View File

@@ -1,126 +0,0 @@
<template>
<v-dialog
v-model="show"
:max-width="$vuetify.display.mobile ? undefined : '600'"
:fullscreen="$vuetify.display.mobile"
:transition="$vuetify.display.mobile ? 'dialog-bottom-transition' : 'dialog-transition'"
@click:outside="dismiss"
>
<v-card class="h-100 d-flex flex-column">
<v-card-title class="text-center py-4 font-weight-bold bg-warning d-flex align-center justify-center">
<v-icon icon="mdi-alert-circle" size="large" class="mr-2"></v-icon>
<h3 class="headline">Are you sure it's an ALPR?</h3>
<v-spacer v-if="$vuetify.display.mobile"></v-spacer>
<v-btn
v-if="$vuetify.display.mobile"
icon="mdi-close"
variant="text"
color="on-warning"
@click="dismiss"
></v-btn>
</v-card-title>
<v-card-text class="pa-6 flex-grow-1 d-flex flex-column justify-center">
<div class="content-wrapper">
<div class="text-center mb-6">
<img
src="/alprs/flock-1.jpg"
alt="Example ALPR Camera"
style="max-width: 220px; width: 100%; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.08);"
/>
<div class="mt-2 text-caption text-grey-darken-1">
Example ALPR camera (Flock Safety)
</div>
</div>
<p class="text-center text-body-1 mb-12">
Not every camera on a pole is an ALPR. Many are just traffic monitoring cameras or other equipment.
</p>
<div class="text-center">
<v-btn
color="primary"
variant="elevated"
size="large"
to="/identify"
prepend-icon="mdi-image-search"
class="mb-3"
@click="dismiss"
>
View ALPR Gallery
</v-btn>
</div>
</div>
</v-card-text>
<v-card-actions class="pa-4">
<v-btn
width="100%"
color="success"
variant="text"
size="large"
@click="dismiss"
>
Continue
</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('alpr-verification-acknowledged')) {
show.value = true;
}
});
function dismiss() {
show.value = false;
localStorage.setItem('alpr-verification-acknowledged', 'true');
}
</script>
<style scoped>
.headline {
color: rgb(var(--v-theme-on-warning));
}
ul {
padding-left: 1.2rem;
}
li {
margin-bottom: 0.25rem;
}
/* Mobile fullscreen styling */
@media (max-width: 960px) {
.content-wrapper {
max-width: 100%;
}
.v-card-title h3 {
font-size: 1.25rem !important;
}
.v-card-text {
padding: 1.5rem !important;
}
.v-card-actions {
padding: 1.5rem !important;
flex-direction: column;
gap: 0.75rem;
}
.v-card-actions .v-btn {
width: 100%;
margin: 0 !important;
}
}
</style>

View File

@@ -52,6 +52,9 @@
</div>
<div class="bottomright">
<v-btn icon to="/report" style="color: unset">
<v-icon size="large">mdi-map-marker-plus</v-icon>
</v-btn>
<slot name="bottomright"></slot>
</div>
@@ -583,8 +586,8 @@ function registerMapEvents() {
.bottomright {
position: absolute;
bottom: 50px; /* hack */
right: 60px; /* hack */
bottom: 25px;
right: 10px;
z-index: 1000;
display: flex;
flex-direction: column;

View File

@@ -0,0 +1,34 @@
<template>
<v-card :to="props.to" :href="props.href" :target="props.href ? '_blank' : undefined" hover>
<v-card-title class="font-weight-bold text-primary">
<v-icon start>{{ props.icon }}</v-icon>
<span>{{ props.title }}</span>
</v-card-title>
<v-card-text>{{ props.description }}</v-card-text>
</v-card>
</template>
<script setup lang="ts">
const props = defineProps({
title: {
type: String,
required: true
},
description: {
type: String,
required: true
},
icon: {
type: String,
required: true
},
to: {
type: String,
required: false
},
href: {
type: String,
required: false
}
});
</script>

View File

@@ -79,13 +79,13 @@ const internalLinks = [
{ title: 'Privacy Policy', to: '/privacy', icon: 'mdi-shield-lock', alt: 'Privacy Policy' },
{ title: 'Terms of Service', to: '/terms', icon: 'mdi-file-document', alt: 'Terms of Service' },
{ title: 'Press', to: '/press', icon: 'mdi-newspaper', alt: 'Press' },
{ title: 'Contact', to: '/contact', icon: 'mdi-email', alt: 'Contact' },
];
const externalLinks = [
{ title: 'Discord', href: 'https://discord.gg/aV7v4R3sKT', customIcon: '/icon-discord.svg', customIconDark: '/icon-discord-white.svg', alt: 'Discord Logo' },
{ title: 'Donate', to: '/donate', icon: 'mdi-heart', alt: 'Donate' },
{ title: 'GitHub', href: 'https://github.com/FoggedLens/deflock', icon: 'mdi-github', alt: 'GitHub Logo' },
{ title: 'Contact', to: '/contact', icon: 'mdi-email', alt: 'Contact' },
]
</script>

View File

@@ -32,11 +32,19 @@ const router = createRouter({
}
},
{
path: '/chapters',
name: 'chapters',
component: () => import('../views/Chapters.vue'),
path: '/get-involved',
name: 'get-involved',
component: () => import('../views/WhatToDo.vue'),
meta: {
title: 'DeFlock Chapters | Connect Locally'
title: 'What Can I Do | DeFlock'
}
},
{
path: '/groups',
name: 'groups',
component: () => import('../views/Groups.vue'),
meta: {
title: 'Local Groups | DeFlock'
}
},
{

View File

@@ -15,7 +15,7 @@
</v-col>
</v-row>
<v-row>
<v-col cols="12" md="6" class="mx-auto">
<v-col cols="12" sm="8" lg="6" class="mx-auto">
<div v-if="chapters.length">
<div v-for="(state, idx) in statesWithChapters" :key="state" class="mb-8">
<h3 class="font-weight-bold text-h6 mb-0">{{ abbrevToState[state] }}</h3>
@@ -54,7 +54,7 @@
<div class="text-center">
<p>Don't see a group near you?</p>
<v-btn color="primary" variant="text" to="/contact">
<v-btn color="primary" variant="outlined" to="/contact">
<v-icon start>mdi-plus</v-icon>Submit a Group
</v-btn>
</div>

View File

@@ -38,7 +38,9 @@
<!-- CURRENT LOCATION -->
<template v-slot:bottomright>
<v-fab icon="mdi-crosshairs-gps" @click="goToUserLocation" />
<v-btn icon @click="goToUserLocation">
<v-icon>mdi-crosshairs-gps</v-icon>
</v-btn>
</template>
</leaflet-map>
<div v-else class="loader">

View File

@@ -1,9 +1,6 @@
<template>
<DefaultLayout>
<v-container>
<!-- ALPR Verification Dialog -->
<ALPRVerificationDialog />
<v-row justify="center" class="mb-4">
<v-col cols="12" md="8">
<h2 class="text-center text-h4 font-weight-bold">Choose Your Reporting Method</h2>
@@ -110,19 +107,9 @@
<script setup lang="ts">
import DefaultLayout from '@/layouts/DefaultLayout.vue';
import ALPRVerificationDialog from '@/components/ALPRVerificationDialog.vue';
</script>
<style scoped>
.verification-alert {
border-left-width: 6px !important;
}
.verification-alert .v-alert-title {
font-weight: 600;
font-size: 1.1rem;
}
/* App card disabled styling */
.app-card-container {
position: relative;

View File

@@ -0,0 +1,98 @@
<template>
<DefaultLayout>
<template #header>
<Hero
title="Get Involved"
description="Steps you can take to make a difference"
/>
</template>
<v-container>
<h3 class="text-center">For Your Community</h3>
<v-divider class="mb-4" />
<v-row>
<v-col cols="12" md="6" v-for="{ title, description, icon, to, href } in localActions" :key="title">
<ActionCard :title :description :icon :to :href />
</v-col>
</v-row>
<h3 class="text-center mb-5 mt-10">For the DeFlock Project</h3>
<v-divider class="mb-4" />
<v-row>
<v-col cols="12" md="6" v-for="{ title, description, icon, to, href } in deflockActions" :key="title">
<ActionCard :title :description :icon :to :href />
</v-col>
</v-row>
</v-container>
</DefaultLayout>
</template>
<script setup lang="ts">
import DefaultLayout from '@/layouts/DefaultLayout.vue';
import Hero from '@/components/layout/Hero.vue';
import ActionCard from '@/components/get-involved/ActionCard.vue';
interface Action {
title: string;
description: string;
icon: string;
to?: string;
href?: string;
}
const localActions: Action[] = [
{
title: 'Join a Local Group',
description: 'Connect with local advocacy groups working to regulate LPR use in your community.',
icon: 'mdi-account-group',
to: '/groups'
},
{
title: 'Contact Your Representatives',
description: 'Reaching out to your local council members is surprisingly effective in influencing policy decisions.',
icon: 'mdi-phone',
to: '/council'
},
{
title: 'Submit Cameras',
description: 'Help us build a comprehensive map of LPR deployments by reporting cameras in your area.',
icon: 'mdi-map-marker-plus',
to: '/report'
},
{
title: 'Join our Discord',
description: 'Connect with other volunteers, share ideas, and stay updated on DeFlock\'s progress.',
icon: 'mdi-chat',
href: 'https://discord.gg/aV7v4R3sKT'
},
{
title: 'Hang Signs',
description: 'Use our printable signs to inform your community about LPR surveillance and your rights.',
icon: 'mdi-sign-text',
to: '/store'
},
{
title: 'Request Public Records',
description: 'File public records requests to obtain information about LPR deployments in your area.',
icon: 'mdi-file-document',
to: '/foia'
},
]
const deflockActions: Action[] = [
{
title: 'Become a GitHub Contributor',
description: 'Contribute to our open-source projects by reporting bugs, fixing issues, and adding new features.',
icon: 'mdi-github',
href: 'https://github.com/foggedlens/deflock'
},
{
title: 'Donate to DeFlock',
description: `Don't have the time to volunteer? You can still support DeFlock's mission with a financial contribution.`,
icon: 'mdi-cash-multiple',
to: '/donate'
},
]
</script>