mirror of
https://github.com/FoggedLens/deflock.git
synced 2026-02-12 15:02:45 +00:00
cleanup
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
|
||||
34
webapp/src/components/get-involved/ActionCard.vue
Normal file
34
webapp/src/components/get-involved/ActionCard.vue
Normal 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>
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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>
|
||||
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
|
||||
98
webapp/src/views/WhatToDo.vue
Normal file
98
webapp/src/views/WhatToDo.vue
Normal 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>
|
||||
Reference in New Issue
Block a user