Benard John
feat: implement feedback API endpoint and add new frontend views for status, legal, and documentation pages.
2a72aeb | <template> | |
| <div class="not-found-view"> | |
| <div class="nf-content"> | |
| <div class="nf-flag" aria-hidden="true"> | |
| <span class="stripe black" /> | |
| <span class="stripe fimbriation" /> | |
| <span class="stripe red" /> | |
| <span class="stripe fimbriation" /> | |
| <span class="stripe green" /> | |
| </div> | |
| <h1 class="nf-code">404</h1> | |
| <h2 class="nf-title">This page is missing</h2> | |
| <p class="nf-body"> | |
| The page you're looking for doesn't exist on Ukweli — or it | |
| was moved, archived, or never published. Every audit report, | |
| however, is in the catalogue. Maybe try a search? | |
| </p> | |
| <div class="nf-actions"> | |
| <n-input | |
| v-model:value="search" | |
| placeholder="Search audit reports..." | |
| size="large" | |
| @keyup.enter="goSearch" | |
| > | |
| <template #prefix> | |
| <n-icon><search-outline /></n-icon> | |
| </template> | |
| </n-input> | |
| <div class="nf-buttons"> | |
| <n-button type="primary" size="large" @click="goSearch"> | |
| Search | |
| </n-button> | |
| <n-button quaternary size="large" @click="router.push('/')"> | |
| Back to home | |
| </n-button> | |
| </div> | |
| </div> | |
| <div class="nf-suggestions"> | |
| <p class="suggestions-label">Or jump to:</p> | |
| <div class="suggestion-list"> | |
| <router-link to="/chat" class="suggestion-chip"> | |
| <n-icon size="14"><chatbubbles-outline /></n-icon> | |
| Ask the auditor | |
| </router-link> | |
| <router-link to="/explore" class="suggestion-chip"> | |
| <n-icon size="14"><compass-outline /></n-icon> | |
| Explore reports | |
| </router-link> | |
| <router-link to="/graph" class="suggestion-chip"> | |
| <n-icon size="14"><share-social-outline /></n-icon> | |
| Knowledge graph | |
| </router-link> | |
| <router-link to="/about" class="suggestion-chip"> | |
| <n-icon size="14"><information-circle-outline /></n-icon> | |
| About | |
| </router-link> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </template> | |
| <script setup lang="ts"> | |
| import { ref } from 'vue' | |
| import { useRouter } from 'vue-router' | |
| import { | |
| SearchOutline, | |
| ChatbubblesOutline, | |
| CompassOutline, | |
| ShareSocialOutline, | |
| InformationCircleOutline, | |
| } from '@vicons/ionicons5' | |
| const router = useRouter() | |
| const search = ref('') | |
| function goSearch() { | |
| if (!search.value.trim()) return | |
| router.push({ path: '/', query: { q: search.value } }) | |
| } | |
| </script> | |
| <style scoped lang="scss"> | |
| .not-found-view { | |
| min-height: calc(100vh - 200px); | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| padding: 40px 16px; | |
| } | |
| .nf-content { | |
| max-width: 560px; | |
| text-align: center; | |
| } | |
| .nf-flag { | |
| display: flex; | |
| width: 140px; | |
| height: 10px; | |
| margin: 0 auto 32px; | |
| border-radius: 4px; | |
| overflow: hidden; | |
| box-shadow: var(--shadow-sm); | |
| .stripe { flex: 1; } | |
| .stripe.black { background: var(--ke-black); flex: 1.4; } | |
| .stripe.fimbriation { background: var(--ke-white); flex: 0.15; } | |
| .stripe.red { background: var(--ke-red); flex: 1.2; } | |
| .stripe.green { background: var(--ke-green); flex: 1.4; } | |
| } | |
| .nf-code { | |
| font-family: var(--font-display); | |
| font-size: 128px; | |
| line-height: 1; | |
| font-weight: 800; | |
| margin: 0; | |
| background: linear-gradient(135deg, var(--ke-black) 0%, var(--ke-red) 50%, var(--ke-green) 100%); | |
| -webkit-background-clip: text; | |
| background-clip: text; | |
| color: transparent; | |
| letter-spacing: -0.04em; | |
| } | |
| .nf-title { | |
| font-family: var(--font-display); | |
| font-size: 28px; | |
| margin: 0 0 12px; | |
| color: var(--text-primary); | |
| } | |
| .nf-body { | |
| font-size: 15px; | |
| color: var(--text-secondary); | |
| line-height: 1.6; | |
| max-width: 480px; | |
| margin: 0 auto 28px; | |
| } | |
| .nf-actions { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 12px; | |
| margin-bottom: 32px; | |
| } | |
| .nf-buttons { | |
| display: flex; | |
| gap: 8px; | |
| justify-content: center; | |
| } | |
| .nf-suggestions { | |
| padding-top: 24px; | |
| border-top: 1px solid var(--border); | |
| } | |
| .suggestions-label { | |
| font-size: 11px; | |
| font-weight: 700; | |
| text-transform: uppercase; | |
| letter-spacing: 0.12em; | |
| color: var(--text-muted); | |
| margin-bottom: 12px; | |
| } | |
| .suggestion-list { | |
| display: flex; | |
| flex-wrap: wrap; | |
| justify-content: center; | |
| gap: 8px; | |
| } | |
| .suggestion-chip { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 6px; | |
| background: var(--bg-card); | |
| border: 1px solid var(--border); | |
| border-radius: 999px; | |
| padding: 8px 14px; | |
| font-size: 13px; | |
| font-weight: 600; | |
| color: var(--text-primary); | |
| text-decoration: none; | |
| transition: all 0.2s var(--ease-out); | |
| &:hover { | |
| border-color: var(--primary); | |
| background: var(--primary-soft); | |
| color: var(--primary); | |
| } | |
| } | |
| @media (max-width: 768px) { | |
| .nf-code { font-size: 96px; } | |
| .nf-title { font-size: 22px; } | |
| .nf-buttons { flex-direction: column; } | |
| } | |
| </style> | |