Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
# Changelog

## [1.0.7] - 2025-04-22
## [1.0.8]
### UI Enhancements
- **Redesigned Header and Footer**: Modernized header/footer with theme toggle and improved visual consistency.
- **Improved 404 Page**: Updated design for better responsiveness and refined typography.

### Theme and Styling Updates
- **Custom Themes**: Introduced custom light/dark themes and theme switching functionality.
- **Global Styling Updates**: Updated font to "Inter" and added a gradient background.

### Component Enhancements
- **Reusable Password Input**: Created a component for password handling, including visibility and generation.
- **Secret Display Component**: Added a component for secret copying and file downloading with alerts.

### Code Cleanup and Refactoring
- **Removed Unused API Code**: Deleted obsolete `api.js` to simplify codebase.
- **Form Reset Logic**: Refactored `Create.vue` to use a centralized store for form reset.

## [1.0.7]
### Added
- Customizable application title and description through environment variables
- New build arguments in Dockerfile: VITE_APP_TITLE and VITE_APP_DESCRIPTION
Expand Down Expand Up @@ -61,4 +78,4 @@ Other Enhancements:
- Updated Docker images to use multi-stage builds for backend and frontend.
- Improved project documentation and added sections for installation, configuration, and deployment.

---
---
74 changes: 45 additions & 29 deletions ui/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,37 @@
<v-app>
<v-main class="d-flex flex-column">
<v-container fluid class="pa-0 flex-grow-1">
<!-- Header -->
<v-toolbar color="primary" dark flat>
<v-app-bar color="transparent" flat class="px-4">
<v-toolbar-title>
<router-link to="/" class="logo-link animate__animated animate__pulse">
<img src="./assets/Images/logo.png" alt="Logo" height="50" />
<router-link to="/" class="logo-link animate__animated animate__pulse" @click="requestFormReset">
<img src="./assets/Images/logo.png" alt="Logo" height="40" />
</router-link>
</v-toolbar-title>
<v-spacer></v-spacer>
<v-btn to="/" text class="animate__animated animate__fadeIn">
<v-icon left>mdi-plus</v-icon> Create
<v-btn to="/" text class="animate__animated animate__fadeIn" @click="requestFormReset" rounded>
<v-icon left>mdi-plus</v-icon> Create New
</v-btn>
</v-toolbar>
<v-tooltip :text="isDarkMode ? 'Switch to Light Mode' : 'Switch to Dark Mode'">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" icon @click="toggleTheme" class="ml-2">
<v-icon>{{ isDarkMode ? 'mdi-weather-sunny' : 'mdi-weather-night' }}</v-icon>
</v-btn>
</template>
</v-tooltip>
</v-app-bar>

<!-- Main Content -->
<v-container class="mt-4">
<router-view />
</v-container>
</v-container>

<!-- Footer -->
<v-footer color="primary" dark class="justify-center">
<v-footer color="transparent" class="justify-center mt-8 pa-4">
<span>
© {{ new Date().getFullYear() }} GopherDrop |
© {{ new Date().getFullYear() }} GopherDrop |
<a
href="https://github.com/kek-Sec/gopherdrop"
target="_blank"
rel="noopener noreferrer"
class="text-white"
>
GitHub Repository
</a>
Expand All @@ -44,38 +47,51 @@
* The root component of the application.
* Provides a header, navigation, and footer.
*/
</script>
import { ref, onMounted, computed } from 'vue';
import { formStore } from './stores/formStore.js';
import { useTheme } from 'vuetify';

<style scoped>
.v-toolbar {
width: 100%;
margin: 0;
}
const themeInstance = useTheme();
const isDarkMode = computed(() => themeInstance.global.current.value.dark);

.v-footer {
width: 100%;
padding: 16px;
font-size: 14px;
text-align: center;
// On component mount, check localStorage for a saved theme
onMounted(() => {
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
themeInstance.global.name.value = savedTheme;
}
});

function toggleTheme() {
const newTheme = isDarkMode.value ? 'customLightTheme' : 'customDarkTheme';
themeInstance.global.name.value = newTheme;
// Save the new theme preference to localStorage
localStorage.setItem('theme', newTheme);
}

.v-footer a {
text-decoration: none;
color: inherit;
/**
* Triggers the form reset via the store.
* This will be picked up by a watcher in Create.vue.
*/
function requestFormReset() {
formStore.triggerReset();
}
</script>

.v-footer a:hover {
text-decoration: underline;
<style scoped>
.v-footer a {
font-weight: 500;
}

.logo-link {
display: inline-block;
text-decoration: none;
vertical-align: middle;
}

.v-main {
display: flex;
flex-direction: column;
min-height: 100vh;
}
</style>
</style>
79 changes: 0 additions & 79 deletions ui/src/api.js

This file was deleted.

43 changes: 28 additions & 15 deletions ui/src/assets/style.css
Original file line number Diff line number Diff line change
@@ -1,25 +1,38 @@
/**
* Global styles for responsive and clean layout.
*/
html, body {
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap');

html, body {
margin: 0;
padding: 0;
font-family: Arial, sans-serif;
font-family: 'Inter', Arial, sans-serif;
color: #333;
}

a {
color: #007bff;
background: #f4f4f9; /* Fallback background */
}

/* Add a subtle gradient background */
body {
background: linear-gradient(180deg, rgba(232,222,248,0.3) 0%, rgba(255,255,255,1) 30%);
}

.v-application {
background: transparent !important;
}


a {
color: #6750A4; /* Using the new primary color */
text-decoration: none;
}

a:hover {
transition: color 0.3s ease;
}

a:hover {
text-decoration: underline;
}
@media (max-width: 600px) {
}

@media (max-width: 600px) {
main, header {
padding: 1rem;
padding: 0.5rem;
}
}

}
41 changes: 41 additions & 0 deletions ui/src/components/PasswordInput.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<template>
<v-text-field
label="Password (optional)"
:type="showPassword ? 'text' : 'password'"
:model-value="modelValue"
@update:modelValue="$emit('update:modelValue', $event)"
>
<template v-slot:append-inner>
<v-tooltip text="Toggle Password Visibility">
<template v-slot:activator="{ on, attrs }">
<v-btn icon v-bind="attrs" v-on="on" @click="showPassword = !showPassword" size="small">
<v-icon>{{ showPassword ? 'mdi-eye-off' : 'mdi-eye' }}</v-icon>
</v-btn>
</template>
</v-tooltip>
<v-tooltip text="Generate Random Password">
<template v-slot:activator="{ on, attrs }">
<v-btn icon color="primary" v-bind="attrs" v-on="on" @click="generateNewPassword" size="small" style="margin-left: 4px">
<v-icon>mdi-refresh</v-icon>
</v-btn>
</template>
</v-tooltip>
</template>
</v-text-field>
</template>

<script setup>
import { ref } from 'vue';
import { generatePassword } from '../utils/passwordGenerator.js';

const props = defineProps({
modelValue: String
});
const emit = defineEmits(['update:modelValue']);

const showPassword = ref(false);

function generateNewPassword() {
emit('update:modelValue', generatePassword());
}
</script>
47 changes: 47 additions & 0 deletions ui/src/components/SecretDisplay.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<template>
<div>
<v-alert v-if="textContent" type="info" class="mb-4 text-left" variant="tonal">
{{ textContent }}
</v-alert>

<div v-if="file">
<v-btn color="primary" @click="download" block x-large height="50" rounded>
<v-icon left>mdi-download</v-icon> Download File
</v-btn>
</div>

<v-btn v-if="textContent" color="primary" @click="copy" block x-large height="50" rounded class="mt-4">
<v-icon left>mdi-content-copy</v-icon> Copy Secret
</v-btn>

<v-snackbar v-model="snackbar" timeout="2000">
Text copied to clipboard!
</v-snackbar>
</div>
</template>

<script setup>
import { ref } from 'vue';
import { downloadFile } from '../utils/fileDownloader.js';

const props = defineProps({
textContent: String,
file: Blob,
filename: String
});

const snackbar = ref(false);

function download() {
if (props.file) {
downloadFile(props.file, props.filename);
}
}

function copy() {
if (props.textContent) {
navigator.clipboard.writeText(props.textContent);
snackbar.value = true;
}
}
</script>
Loading
Loading