adjust frontend for any filetype and add metadata to api response
This commit is contained in:
@@ -2,7 +2,7 @@ package handlers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"os"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
@@ -16,7 +16,14 @@ func (store *Store) GetNoteFile(ctx *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the filename from path
|
info, err := os.Stat(path)
|
||||||
filename := filepath.Base(path)
|
if err != nil {
|
||||||
ctx.FileAttachment(path, filename)
|
ctx.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.Header("Last-Modified", info.ModTime().UTC().Format(http.TimeFormat))
|
||||||
|
ctx.Header("Access-Control-Expose-Headers", "Content-Disposition, Last-Modified")
|
||||||
|
|
||||||
|
ctx.FileAttachment(path, info.Name())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,19 +2,34 @@
|
|||||||
import Markdown from "@/components/quick/Markdown.vue";
|
import Markdown from "@/components/quick/Markdown.vue";
|
||||||
import { ref, onMounted } from "vue";
|
import { ref, onMounted } from "vue";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
const note = ref(null);
|
const file = ref(null);
|
||||||
|
const filename = ref("");
|
||||||
|
const last_edited = ref(null);
|
||||||
|
|
||||||
function fixContents(contents) {
|
// if the address is https://www.adam-french.co.uk/notes/PATH
|
||||||
// Obsidian notes have links in the form [[link|name]]
|
// request from https://www.adam-french.co.uk/api/notes/PATH
|
||||||
// contents so that they are rendered correctly
|
const route = useRoute();
|
||||||
return contents.replace(/\[\[(.*?)\|(.*)\]\]/g, '<a href="/$1">$2</a>');
|
const path = route.params.path;
|
||||||
|
const url = `/api/notes/${path}`;
|
||||||
|
|
||||||
|
function getFilename(headers) {
|
||||||
|
const disposition = headers["content-disposition"];
|
||||||
|
if (!disposition) return null;
|
||||||
|
|
||||||
|
const match = disposition.match(/filename="?([^"]+)"?/);
|
||||||
|
return match ? match[1] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchNote() {
|
async function fetchFile() {
|
||||||
const response = await axios.get("/api/notes/Index");
|
const response = await axios.get(url, { responseType: "blob" });
|
||||||
response.data.contents = fixContents(response.data.contents);
|
filename.value = getFilename(response.headers);
|
||||||
note.value = response.data;
|
|
||||||
|
const lastModified = response.headers["last-modified"];
|
||||||
|
last_edited.value = lastModified ? new Date(lastModified) : null;
|
||||||
|
|
||||||
|
file.value = response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(fetchNote);
|
onMounted(fetchNote);
|
||||||
@@ -23,14 +38,13 @@ onMounted(fetchNote);
|
|||||||
<template>
|
<template>
|
||||||
<main class="center-content flex-col">
|
<main class="center-content flex-col">
|
||||||
<div class="background halftone" />
|
<div class="background halftone" />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="note"
|
v-if="note"
|
||||||
class="a4page-portrait bdr-1 flex-col relative scroll-y gap bg-primary"
|
class="a4page-portrait bdr-primary flex-col relative scroll-y gap bg-primary"
|
||||||
>
|
>
|
||||||
<h1>{{ note.title }}</h1>
|
<h1>{{ filename }}</h1>
|
||||||
<small>{{ note.last_edited }}</small>
|
<small>{{ last_edited }}</small>
|
||||||
<Markdown class="fill wrap" :source="note.contents" />
|
<Markdown class="fill wrap" :source="file" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else>Loading…</div>
|
<div v-else>Loading…</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user