Skip to content

Commit

Permalink
feat: Improve Vault UI (#460)
Browse files Browse the repository at this point in the history
  • Loading branch information
HugoRCD authored Jan 28, 2025
1 parent e35ef75 commit ea192e3
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 621 deletions.
2 changes: 1 addition & 1 deletion apps/base/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,4 @@ export default defineNuxtConfig({
},

css: ['./assets/css/base.css'],
})
})
72 changes: 37 additions & 35 deletions apps/vault/app/app.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,52 +60,54 @@ const items = [
<UApp>
<div class="flex flex-col items-center justify-center py-4 sm:py-20">
<div class="w-full border-y border-neutral-500/20">
<div class="mx-auto flex max-w-2xl justify-center px-5 sm:px-0">
<div class="mx-auto flex max-w-4xl font-mono italic justify-center px-5 sm:px-0">
<EncryptDiv encrypted-text class="w-full border-x border-neutral-500/20">
<div>
<h1 class="main-gradient cursor-pointer text-3xl">
<h1 class="main-gradient font-medium text-3xl">
<ScrambleText label="Vault" />
</h1>
<p class="text-neutral-500">
Vault is a small utility to share secrets.
<p class="text-neutral-500 max-w-lg text-xs sm:text-sm">
Share secrets securely without an account. Set expiration time, control number of reads, and ensure encrypted transmission.
</p>
</div>
</EncryptDiv>
</div>
</div>
<Encrypt v-if="!sealMode" />
<Decrypt v-else />
</div>
<div class="mt-8 max-w-2xl flex w-full mx-auto flex-col gap-4 px-5">
<div class="flex flex-col items-center justify-center">
<h3 class="main-gradient text-2xl">
<ScrambleText label="FAQ" />
</h3>
<p class="max-w-lg text-center text-sm text-neutral-500 sm:text-base">
Frequently asked questions about Vault.
</p>
<div class="max-w-4xl w-full mx-auto">
<Encrypt v-if="!sealMode" />
<Decrypt v-else />
<div class="mt-32 flex flex-col gap-4 px-5">
<div class="flex flex-col font-mono items-center justify-center">
<h3 class="main-gradient text-2xl">
<ScrambleText label="FAQ" />
</h3>
<p class="max-w-lg text-center text-sm text-neutral-500 sm:text-base">
Frequently asked questions about Vault.
</p>
</div>
<UAccordion
variant="ghost"
size="sm"
:items
/>
</div>
<footer class="mt-20 flex flex-col gap-4 px-5">
<USeparator />
<div class="flex items-center justify-between">
<span class="text-xs font-mono italic tracking-tight text-neutral-500">
© {{ new Date().getFullYear() }} - Made by <NuxtLink to="https://hrcd.fr/" class="text-neutral-400 hover:text-neutral-200">
HugoRCD
</NuxtLink>
</span>
<span class="text-xs font-mono italic tracking-tight text-neutral-500">
<NuxtLink to="https://dub.sh/shelve" target="_blank" class="text-neutral-400 hover:text-neutral-200">
Powered by Shelve <UIcon name="custom:shelve" />
</NuxtLink>
</span>
</div>
</footer>
</div>
<UAccordion
variant="ghost"
size="sm"
:items
/>
</div>
<footer class="mt-15 flex w-full mx-auto max-w-2xl flex-col gap-4 px-5">
<USeparator />
<div class="flex max-w-2xl items-center justify-between">
<span class="text-xs font-mono italic tracking-tight text-neutral-500">
© {{ new Date().getFullYear() }} - Made by <NuxtLink to="https://hrcd.fr/" class="text-neutral-400 hover:text-neutral-200">
HugoRCD
</NuxtLink>
</span>
<span class="text-xs font-mono italic tracking-tight text-neutral-500">
<NuxtLink to="https://dub.sh/shelve" target="_blank" class="text-neutral-400 hover:text-neutral-200">
Powered by Shelve <UIcon name="custom:shelve" />
</NuxtLink>
</span>
</div>
</footer>
<Toaster close-button position="top-center" />
</UApp>
</Body>
Expand Down
18 changes: 18 additions & 0 deletions apps/vault/app/assets/css/index.css
Original file line number Diff line number Diff line change
@@ -1,2 +1,20 @@
@import "tailwindcss";
@import "@nuxt/ui";

:root {
--ui-bg: white;

::selection {
color: #282a30;
background-color: #c8c8c8;
}
}

.dark {
--ui-bg: #070707;

::selection {
color: #ffffff;
background-color: #474747;
}
}
8 changes: 2 additions & 6 deletions apps/vault/app/components/Decrypt.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ const localId = ref(id)
const timeLeft = ref('')
const readsLeft = ref(0)
const loading = ref(false)
async function decryptEnvFile() {
loading.value = true
try {
const { decryptedValue, reads, ttl } = await $fetch(`/api/vault?id=${localId.value}`, {
method: 'POST',
Expand All @@ -26,12 +24,11 @@ async function decryptEnvFile() {
toast.error('Failed to decrypt your secret(s)')
}
}
loading.value = false
}
</script>

<template>
<form class="mx-auto mt-8 flex w-full max-w-2xl flex-col justify-center gap-2 px-5 sm:px-0" @submit.prevent="decryptEnvFile">
<form class="mx-auto mt-8 flex w-full flex-col justify-center gap-2 px-5 sm:px-0" @submit.prevent="decryptEnvFile">
<template v-if="!value">
<div class="relative flex w-full flex-col gap-2">
<UFormField label="Share ID">
Expand All @@ -48,8 +45,7 @@ async function decryptEnvFile() {
block
label="Decrypt"
type="submit"

:loading
loading-auto
/>
</div>
</template>
Expand Down
26 changes: 13 additions & 13 deletions apps/vault/app/components/Encrypt.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<script setup lang="ts">
const value = ref('')
const state = ref({
value: '',
})
const reads = ref(1)
const ttl = ref([
'1d',
Expand All @@ -16,7 +18,7 @@ async function saveEnvFile() {
shareUrl.value = await $fetch('/api/vault', {
method: 'POST',
body: {
value: value.value,
value: state.value.value,
reads: reads.value,
ttl: selectedTtl.value,
},
Expand All @@ -31,7 +33,7 @@ async function saveEnvFile() {
function parseEnvFile(file: File) {
const reader = new FileReader()
reader.onload = (e) => value.value = e.target?.result as string
reader.onload = (e) => state.value.value = e.target?.result as string
reader.onerror = (e) => console.error('Error reading file:', e)
Expand Down Expand Up @@ -81,10 +83,10 @@ function handleDrop(event: DragEvent) {
</script>

<template>
<form class="mx-auto mt-8 flex w-full max-w-2xl flex-col justify-center gap-2 px-5 sm:px-0" @submit.prevent="saveEnvFile">
<div class="relative w-full">
<UForm :state class="mx-auto mt-8 flex w-full flex-col justify-center gap-2 px-5 sm:px-0" @submit.prevent="saveEnvFile">
<UFormField class="relative w-full" name="value">
<UTextarea
v-model="value"
v-model="state.value"
autoresize
autofocus
required
Expand All @@ -98,7 +100,7 @@ function handleDrop(event: DragEvent) {
@drop.prevent="handleDrop"
/>
<input type="file" accept="text" style="display: none;" @change="handleFileUpload">
</div>
</UFormField>
<div class="mt-2 flex w-full items-end justify-between gap-2">
<UTooltip
:content="{
Expand All @@ -107,11 +109,10 @@ function handleDrop(event: DragEvent) {
text="Reads are used to limit the number of times a secret can be read."
>
<UFormField label="Reads">
<UInput
<UInputNumber
v-model="reads"
label="Reads"
type="number"
min="1"
:min="1"
/>
</UFormField>
</UTooltip>
Expand All @@ -137,8 +138,7 @@ function handleDrop(event: DragEvent) {
block
label="Encrypt"
type="submit"

:loading
loading-auto
/>
</div>
<div v-if="shareUrl" class="mt-4 flex w-full rounded-lg border border-green-600/20 bg-green-600/10 p-4 shadow-md">
Expand All @@ -156,5 +156,5 @@ function handleDrop(event: DragEvent) {
/>
</div>
</div>
</form>
</UForm>
</template>
27 changes: 25 additions & 2 deletions apps/vault/app/components/EncryptDiv.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,35 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue'
defineProps<{
encryptedText: boolean
}>()
const encryptionElement = ref<HTMLElement | null>(null)
const updateMousePosition = (e: MouseEvent) => {
if (!encryptionElement.value) return
const rect = encryptionElement.value.getBoundingClientRect()
const x = ((e.clientX - rect.left) / rect.width) * 100
const y = ((e.clientY - rect.top) / rect.height) * 100
encryptionElement.value.style.setProperty('--x', `${x}%`)
encryptionElement.value.style.setProperty('--y', `${y}%`)
}
onMounted(() => {
window.addEventListener('mousemove', updateMousePosition)
})
onUnmounted(() => {
window.removeEventListener('mousemove', updateMousePosition)
})
</script>

<template>
<CrossedDiv class="h-40">
<div v-if="encryptedText" class="encryption absolute left-0 top-0 size-full overflow-hidden break-words font-mono text-xs leading-5 text-neutral-400">
<div v-if="encryptedText" ref="encryptionElement" class="encryption absolute left-0 top-0 size-full overflow-hidden break-words font-mono text-xs leading-5 text-neutral-400">
GIHXTrTBRIPocF8gMJPAM5dyuwCO7DIqMlrx45EFKa8Ky06RHwDafK1CpxdOLAI6mM8YX4iHsZ188j00gNkbgDYEtrq1S5vaOIxHhALKib3EKVD5tuYf3Ej2QA0R363viNI0tP8RVD4GlLzNPHpBkePL76KLzZrXa6x88wsJN8sslwiKTxEeepv1760YPcdyrfnqv4W4RRv2Fw9f6rBIgzOaBF5Jet4rjo2eIuKCUDkM9t8ZnfvGCzguyoFkTlmLtQuzQKPZLVuPtpbbBOdrUG795uSVFCnFjnJKgHGAiAeGZmu0n1lnfNgOB9t7cLc7Gk7jUfW3aHK3es56mORlQyACrHBDVQjPiBaIbfBBAreNiZAo8NzadXQ28HOHTvdL90GYoqJC9fqitNn0R1CWVJyEqCCKlTZSU2UFhgUNCI7Zzozl7QlZceSE5SrXNjtBnAi0sMiIeJb43o2x2vHQehvUmTaejG3UqETeRxzvg4qhD1qFDkk8y3mwuq31NWDlaszIhhVNnu6NTapPGT9XKXDCMee8QOGnQuBsPEQHCNs3eX3jsZLitOCTTVljHuY8A3AEAiWudJduue5X5PTFSc1UfFt8U1Yhj4qiVQaip3XkfesyBnk7wVaAWUKrKMToGVSyeoD23U1CNibAimwV7TKRpWWGSvXdFclFM6XuigtHlZzSLOE40wY3eEw4rAPeZF30jJMZytpXVc9AsprMpCfoKMbKSPUnDuXCq1nhggY2MTkCdcGkABxsbolIuyYUZMu2Lqt18aNIN1ZudI08ZVJHCX8q2XcPv43nDtjeHE8djSxcxoXb2b0vw4Wc4AuO2Uph0K6fYSXt54nRHit19TkgCi8dhY2PZAfyiULAvmQy6CQYc5Xw8yfSVMtHnNs2kuC1e376penaAMQ1jUozKWJneHjF21aleJWjN2NJ8bMNyfTNIL1ijpGwz6urHGrSyYR94ghvxNxBwZgRJZbx5IVqjwqDxnzAacMBvViVG4UHluE4UaoLPCHkHBrYj6m32mAIjkso2tC3kBu5XmGnAVdz8UzkPzxgtORxHPEisInmi7fgLGywdQ8Zz3Zdh9912kMR9b6MQ3xRFrlZo5gOQYhSSgyH1gIyGAjjcO3O3EptA7CcRsIeaNR5O3NG4iABwLfN1ebEBC6fLMzIDLlSYs8zQwHYsdSZMbb5yoYxvfB7G4rmEQA9FJ2o1kLzk1OTAk4vUKIEt8gfSDxzgROhMjqDoIeLiWgbXLefVRNVDf0mldlPY7oinEnos1JuxfpukoDhQL5aP2e8pqvhnctNHEGyNDtL3nea1JtDOlBic0OriZlTvIRCADyDFWE7otCHnFipuCFMViCR30HM0pzuCAeQdtvChyIe3mXBxIQnbAqgbLQXhhOD79Nyf8wlyT3fWvufGlgJO4jKD0iwerKMeXGQ0lIClU2fsEGfYAno4b2xeDD1mUO78hXABPREdtj38GoIZCNpxN69TLnCqLDG0pIkXxyYDaMmU9C5YnUr81n1xOgVyeH4iJvMF7CQkuYgWAsvwSwcNtIDtU2vjzXORp4VDlRjXDu4SqGbCDvijjn4wCJLJE1mLvv9R5mMOjHDBVdEOjoJuMp7YpVqSIWenC3oLGsJPJl5KarsVxaMnSWTHRw8wDVHNOcXXO9ZGGQGdi31ikeIfZABoUBKmeyBbgepVlCkDy3aytzYiwmX7fosxj1vk6qbji9GbVNEhimXHZR2rFuKBpov1nahPbopBpfaGKY15UoN2pQOtV5oG1MngCxTTqNBu8khxbYDbRDilYYwbiWk
</div>
<div class="relative z-10 ml-4 flex h-full flex-col justify-center">
Expand All @@ -19,7 +42,7 @@ defineProps<{
.encryption {
--x: 80%;
--y: 0%;
transition: .5s;
transition: .2s ease-out;
-webkit-mask-image: radial-gradient(300px circle at var(--x) var(--y), #000 10%, rgba(0, 0, 0, .25), transparent);
mask-image: radial-gradient(300px circle at var(--x) var(--y), #000 10%, rgba(0, 0, 0, .25), transparent);
opacity: .4;
Expand Down
8 changes: 7 additions & 1 deletion apps/vault/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,20 @@ export default defineNuxtConfig({

runtimeConfig: {
private: {
encryptionKey: process.env.NUXT_PRIVATE_ENCRYPTION_KEY,
encryptionKey: '',
},
},

hub: {
kv: true,
},

$development: {
hub: {
remote: true
}
},

devtools: { enabled: true },

future: {
Expand Down
3 changes: 2 additions & 1 deletion apps/vault/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"dependencies": {
"@nuxthub/core": "0.8.14",
"nuxt": "^3.15.3",
"vue": "latest"
"vue": "latest",
"zod": "3.24.1"
},
"devDependencies": {
"wrangler": "^3.105.1"
Expand Down
2 changes: 1 addition & 1 deletion apps/vault/server/services/vault.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class VaultService {
}

constructor(event: H3Event) {
const config = useRuntimeConfig()
const config = useRuntimeConfig(event)
const url = getRequestURL(event)
this.encryptionKey = config.private.encryptionKey
this.siteUrl = url.origin
Expand Down
Loading

0 comments on commit ea192e3

Please sign in to comment.