Compare commits

...
4 Commits
9 changed files with 69 additions and 24 deletions
+4
View File
@@ -22,3 +22,7 @@ dist-ssr
*.njsproj *.njsproj
*.sln *.sln
*.sw? *.sw?
.env
tsconfig.tsbuildinfo
package-lock.json
Executable
+2
View File
@@ -0,0 +1,2 @@
#!/bin/bash
/snap/bin/node /home/nonroot/unloze-wrapper/server.js
+1
View File
@@ -17,6 +17,7 @@
"path": "^0.12.7", "path": "^0.12.7",
"url": "^0.11.4", "url": "^0.11.4",
"vue": "^3.5.13", "vue": "^3.5.13",
"vue-router": "^4.5.1",
"vuetify": "^3.8.0-beta.0" "vuetify": "^3.8.0-beta.0"
}, },
"devDependencies": { "devDependencies": {
+1 -5
View File
@@ -1,11 +1,7 @@
<template> <template>
<v-app> <v-app>
<v-main> <v-main>
<download-list /> <router-view />
</v-main> </v-main>
</v-app> </v-app>
</template> </template>
<script setup lang="ts">
import DownloadList from './components/DownloadList.vue'
</script>
+34 -12
View File
@@ -47,12 +47,17 @@
<span <span
v-if="item.isDir" v-if="item.isDir"
class="blue--text text--darken-2" class="blue--text text--darken-2"
@click="enterFolder(item.path)"
style="cursor: pointer" style="cursor: pointer"
> >
<v-icon small class="me-2">mdi-folder-outline</v-icon> <v-icon small class="me-2">mdi-folder-outline</v-icon>
{{ item.name }} <a
:href="`${API_BASE_URL}/${item.path}`"
class="blue--text text--darken-2"
style="text-decoration: none"
>
{{ item.name }}
</a>
</span> </span>
<span v-else> <span v-else>
<v-icon small class="me-2">mdi-file-outline</v-icon> <v-icon small class="me-2">mdi-file-outline</v-icon>
@@ -86,8 +91,6 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, ref, nextTick } from "vue"; import { defineComponent, ref, nextTick } from "vue";
const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
interface FolderItem { interface FolderItem {
name: string; name: string;
path: string; path: string;
@@ -128,7 +131,8 @@ export default defineComponent({
{ title: "Size", key: "size", width: "120px" }, { title: "Size", key: "size", width: "120px" },
{ title: "Last Modified", key: "lastModified", width: "200px" }, { title: "Last Modified", key: "lastModified", width: "200px" },
], ],
DOWNLOAD_BASE_URL: import.meta.env.VITE_DOWNLOAD_BASE_URL DOWNLOAD_BASE_URL: import.meta.env.VITE_DOWNLOAD_BASE_URL,
API_BASE_URL: import.meta.env.VITE_API_BASE_URL,
}; };
}, },
computed: { computed: {
@@ -169,12 +173,17 @@ export default defineComponent({
methods: { methods: {
async fetchList(reset = false) { async fetchList(reset = false) {
if (this.loading) return; if (this.loading) return;
this.loading = true; this.loading = true;
const url = new URL(`${API_BASE_URL}/api/list`); const url = new URL(`${this.API_BASE_URL}/api/list`);
console.log(this.currentPath);
url.searchParams.set("prefix", this.currentPath); url.searchParams.set("prefix", this.currentPath);
url.searchParams.set("limit", "50"); url.searchParams.set("limit", "50");
if (this.search) url.searchParams.set("search", this.search); if (this.search) url.searchParams.set("search", this.search);
if (this.nextToken && !reset) { if (this.nextToken && !reset) {
url.searchParams.set("token", this.nextToken); url.searchParams.set("token", this.nextToken);
} }
@@ -195,19 +204,19 @@ export default defineComponent({
this.files.push(...(data.files || [])); this.files.push(...(data.files || []));
this.nextToken = data.nextToken; this.nextToken = data.nextToken;
this.loading = false; this.loading = false;
// Keep fetching until we've retrieved every page for this prefix/search
if (data.isTruncated && data.nextToken) {
await this.fetchList(false);
}
}, },
onSearch() { onSearch() {
this.nextToken = null; this.nextToken = null;
this.fetchList(true); this.fetchList(true);
}, },
enterFolder(path: string) {
this.currentPath = path;
this.nextToken = null;
this.fetchList(true);
},
goToBreadcrumb(path: string) { goToBreadcrumb(path: string) {
this.currentPath = path; this.currentPath = path;
this.nextToken = null; this.$router.push("/" + path);
this.fetchList(true); this.fetchList(true);
}, },
extractFolderName(path: string): string { extractFolderName(path: string): string {
@@ -220,6 +229,19 @@ export default defineComponent({
return size + " B"; return size + " B";
}, },
}, },
created() {
// Remove leading slash if it exists
this.currentPath = this.$route?.path.replace(/^\/+/, "") || "";
// Check if the path ends in `.bz2` (case-sensitive)
if (this.currentPath.endsWith(".bz2")) {
window.open(`${this.DOWNLOAD_BASE_URL}${this.currentPath}`, '_blank', 'popup');
this.currentPath = "";
}
// Only add trailing slash if there's something left
this.currentPath = this.currentPath ? this.currentPath.replace(/\/?$/, "/") : "";
},
mounted() { mounted() {
this.fetchList(true); this.fetchList(true);
}, },
+6 -6
View File
@@ -1,20 +1,20 @@
/* src/main.css */ /* src/main.css */
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap');
body { html, body {
margin: 0; margin: 0;
padding: 0; padding: 0;
font-family: 'Roboto', sans-serif; font-family: 'Roboto', sans-serif;
overflow: hidden; height: 100%;
overflow: auto; /* Allow natural scrolling */
} }
#app, #app,
.v-application { .v-application {
min-height: 100vh;
background-image: url('/carbon.jpg'); background-image: url('/carbon.jpg');
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
position: relative; background-attachment: fixed;
z-index: 0; background-size: cover;
height: 100vh;
overflow-y: auto;
} }
+3
View File
@@ -1,9 +1,12 @@
import { createApp } from 'vue' import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import { vuetify } from './plugins/vuetify' import { vuetify } from './plugins/vuetify'
import router from './router'
import '@mdi/font/css/materialdesignicons.css' import '@mdi/font/css/materialdesignicons.css'
import './main.css'; import './main.css';
const app = createApp(App) const app = createApp(App)
app.use(vuetify) app.use(vuetify)
app.use(router)
app.mount('#app') app.mount('#app')
+17
View File
@@ -0,0 +1,17 @@
import { createRouter, createWebHistory } from 'vue-router'
import DownloadList from '../components/DownloadList.vue'
const routes = [
{
path: '/:catchAll(.*)*', // catches anything
name: 'DownloadList',
component: DownloadList,
},
]
const router = createRouter({
history: createWebHistory(),
routes,
})
export default router
+1 -1
View File
@@ -1 +1 @@
{"root":["./src/app.vue","./src/main.ts","./src/vite-env.d.ts","./src/components/downloadlist.vue","./src/plugins/vuetify.ts"],"version":"5.8.3"} {"root":["./src/app.vue","./src/main.ts","./src/vite-env.d.ts","./src/components/downloadlist.vue","./src/plugins/vuetify.ts","./src/router/index.ts"],"version":"5.8.3"}