diff --git a/src/App.css b/src/App.css
index 41194b4..73a76d1 100644
--- a/src/App.css
+++ b/src/App.css
@@ -1,4 +1,5 @@
@import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap");
+@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,100..700;1,100..700&display=swap");
code {
font-family: "JetBrains Mono";
diff --git a/src/components/EntriesListSidebar.tsx b/src/components/EntriesListSidebar.tsx
index 87b0866..d1a0dbd 100644
--- a/src/components/EntriesListSidebar.tsx
+++ b/src/components/EntriesListSidebar.tsx
@@ -10,68 +10,68 @@ import { Link } from "react-router"
import { useState, useRef, useEffect } from "react"
export default function EntriesListSidebar() {
- const scrollRef = useRef(null)
- const [isOpen, setIsOpen] = useState(() => {
- if (typeof window !== "undefined") {
- const saved = sessionStorage.getItem("entries_list_sidebar_open")
- return saved ? JSON.parse(saved) : false
- }
- return false
- })
+ const scrollRef = useRef(null)
+ const [isOpen, setIsOpen] = useState(() => {
+ if (typeof window !== "undefined") {
+ const saved = sessionStorage.getItem("entries_list_sidebar_open")
+ return saved ? JSON.parse(saved) : false
+ }
+ return false
+ })
- const { data: entries, isLoading } = useQuery({
- queryKey: ["entries_list"],
- queryFn: () => api.get("/entries").then((res) => res.data),
- })
+ const { data: entries, isLoading } = useQuery({
+ queryKey: ["entries_list"],
+ queryFn: () => api.get("/entries").then((res) => res.data),
+ })
- useEffect(() => {
- sessionStorage.setItem("entries_list_sidebar_open", JSON.stringify(isOpen))
- }, [isOpen])
+ useEffect(() => {
+ sessionStorage.setItem("entries_list_sidebar_open", JSON.stringify(isOpen))
+ }, [isOpen])
- useEffect(() => {
- const savedScroll = sessionStorage.getItem("entries_list_sidebar_scroll_position")
- if (savedScroll && scrollRef.current) {
- scrollRef.current.scrollTop = parseInt(savedScroll)
- }
- }, [entries])
+ useEffect(() => {
+ const savedScroll = sessionStorage.getItem("entries_list_sidebar_scroll_position")
+ if (savedScroll && scrollRef.current) {
+ scrollRef.current.scrollTop = parseInt(savedScroll)
+ }
+ }, [entries])
- const handleScroll = () => {
- if (scrollRef.current) {
- sessionStorage.setItem("entries_list_sidebar_scroll_position", scrollRef.current.scrollTop)
- }
- }
+ const handleScroll = () => {
+ if (scrollRef.current) {
+ sessionStorage.setItem("entries_list_sidebar_scroll_position", scrollRef.current.scrollTop)
+ }
+ }
- return (
-
-
-
-
-
-
- Entries
-
- {entries?.count}
-
-
-
-
-
-
-
-
- {entries?.data.map((item, i) => (
-
-
-
- {item.title.replace(/_/g, " ")}
-
-
-
- ))}
-
-
-
-
-
- )
+ return (
+
+
+
+
+
+
+ Entries
+
+ {entries?.count}
+
+
+
+
+
+
+
+
+ {entries?.data.map((item, i) => (
+
+
+
+ {item.title.replace(/_/g, " ")}
+
+
+
+ ))}
+
+
+
+
+
+ )
}
diff --git a/src/components/EntryReferences.tsx b/src/components/EntryReferences.tsx
index 821a694..f526a4f 100644
--- a/src/components/EntryReferences.tsx
+++ b/src/components/EntryReferences.tsx
@@ -1,87 +1,70 @@
-import { useQuery } from "@tanstack/react-query"
-import api from "../api/eolas-api"
import { Link } from "react-router"
import { Badge } from "./ui/badge"
-export default function EntryReferences({ entryTitle }) {
- const { data: tags, isLoading: tagsLoading } = useQuery({
- queryKey: [`tags_for_${entryTitle}`],
- queryFn: () => api.get(`/tags/${entryTitle}`).then((res) => res.data),
- })
+export default function EntryReferences({ tags, backlinks, outlinks }) {
+ return (
+
+
+
+
Incoming links
+
+ {backlinks?.count}
+
+
- const { data: backlinks, isLoading: backlinksLoading } = useQuery({
- queryKey: [`backlinks_for_${entryTitle}`],
- queryFn: () => api.get(`/entries/backlinks/${entryTitle}`).then((res) => res.data),
- })
+
+ {backlinks &&
+ backlinks?.data.map((item, i) => (
+
+ {item.replace(/_/g, " ")}
+
+ ))}
+
- const { data: outlinks, isLoading: outlinksLoading } = useQuery({
- queryKey: [`outlinks_for_${entryTitle}`],
- queryFn: () => api.get(`/entries/outlinks/${entryTitle}`).then((res) => res.data),
- })
+
+
Outgoing links
+
+ {outlinks?.count}
+
+
- return (
-
-
-
-
Incoming links
-
- {backlinks?.count}
-
-
+
+ {outlinks &&
+ outlinks?.data.map((item, i) => (
+
+ {item.replace(/_/g, " ")}
+
+ ))}
+
+
-
- {backlinks &&
- backlinks?.data.map((item, i) => (
-
- {item.replace(/_/g, " ")}
-
- ))}
-
-
-
-
Outgoing links
-
- {outlinks?.count}
-
-
-
-
- {outlinks &&
- outlinks?.data.map((item, i) => (
-
- {item.replace(/_/g, " ")}
-
- ))}
-
-
-
-
-
-
Tags
-
- {tags?.count}
-
-
-
- {tags?.data.map((item, i) => (
-
- {item}
-
- ))}
-
-
-
- )
+
+
+
Tags
+
+ {tags?.count}
+
+
+
+ {tags?.data.map((item, i) => (
+
+ {item}
+
+ ))}
+
+
+
+ )
}
diff --git a/src/components/NetworkGraph.tsx b/src/components/NetworkGraph.tsx
index 2d5bf7a..f8bc09f 100644
--- a/src/components/NetworkGraph.tsx
+++ b/src/components/NetworkGraph.tsx
@@ -3,38 +3,38 @@ import LoadGraph from "./LoadGraph"
import GraphEvents from "./GraphEvents"
export default function NetworkGraph({ data }) {
- const nodeCount = data?.nodes.length
+ const nodeCount = data?.nodes.length
- const sigmaStyle = {
- height: "400px",
- width: "100%",
- }
+ const sigmaStyle = {
+ height: "400px",
+ width: "100%",
+ }
- const settings = {
- allowInvalidContainer: true,
- defaultEdgeColor: "#a4a4a4",
- labelColor: { color: "#0a0a0a" },
- labelFont: "Inter",
- labelSize: 14,
- labelWeight: "400",
- labelRenderedSizeThreshold: nodeCount > 15 ? 10 : 8,
- renderLabels: true,
- }
+ const settings = {
+ allowInvalidContainer: true,
+ defaultEdgeColor: "#a4a4a4",
+ labelColor: { color: "#0a0a0a" },
+ labelFont: "IBM Plex Sans",
+ labelSize: 14,
+ labelWeight: "400",
+ labelRenderedSizeThreshold: nodeCount > 15 ? 10 : 8,
+ renderLabels: true,
+ }
- return (
-
-
-
-
-
-
- )
+ return (
+
+
+
+
+
+
+ )
}
diff --git a/src/components/TagListSidebar.tsx b/src/components/TagListSidebar.tsx
index d4c2b7d..55b8878 100644
--- a/src/components/TagListSidebar.tsx
+++ b/src/components/TagListSidebar.tsx
@@ -9,69 +9,69 @@ import { Link } from "react-router"
import { useState, useRef, useEffect } from "react"
export default function TagListSidebar() {
- const scrollRef = useRef(null)
+ const scrollRef = useRef(null)
- const [isOpen, setIsOpen] = useState(() => {
- if (typeof window !== "undefined") {
- const saved = sessionStorage.getItem("tags_list_sidebar_open")
- return saved ? JSON.parse(saved) : false
- }
- return false
- })
+ const [isOpen, setIsOpen] = useState(() => {
+ if (typeof window !== "undefined") {
+ const saved = sessionStorage.getItem("tags_list_sidebar_open")
+ return saved ? JSON.parse(saved) : false
+ }
+ return false
+ })
- const { data: tags } = useQuery({
- queryKey: ["tag_list"],
- queryFn: () => api.get("/tags").then((res) => res.data),
- })
+ const { data: tags } = useQuery({
+ queryKey: ["tag_list"],
+ queryFn: () => api.get("/tags").then((res) => res.data),
+ })
- useEffect(() => {
- sessionStorage.setItem("tags_list_sidebar_open", JSON.stringify(isOpen))
- }, [isOpen])
+ useEffect(() => {
+ sessionStorage.setItem("tags_list_sidebar_open", JSON.stringify(isOpen))
+ }, [isOpen])
- useEffect(() => {
- const savedScroll = sessionStorage.getItem("tags_list_sidebar_open")
- if (savedScroll && scrollRef.current) {
- scrollRef.current.scrollTop = parseInt(savedScroll)
- }
- }, [tags])
+ useEffect(() => {
+ const savedScroll = sessionStorage.getItem("tags_list_sidebar_open")
+ if (savedScroll && scrollRef.current) {
+ scrollRef.current.scrollTop = parseInt(savedScroll)
+ }
+ }, [tags])
- const handleScroll = () => {
- if (scrollRef.current) {
- sessionStorage.setItem("tags_list_sidebar_open", scrollRef.current.scrollTop)
- }
- }
+ const handleScroll = () => {
+ if (scrollRef.current) {
+ sessionStorage.setItem("tags_list_sidebar_open", scrollRef.current.scrollTop)
+ }
+ }
- return (
-
-
-
-
-
-
- Tags
-
- {tags?.count}
-
-
-
-
-
-
-
-
- {tags?.data.map((item, i) => (
-
-
-
- {item}
-
-
-
- ))}
-
-
-
-
-
- )
+ return (
+
+
+
+
+
+
+ Tags
+
+ {tags?.count}
+
+
+
+
+
+
+
+
+ {tags?.data.map((item, i) => (
+
+
+
+ {item}
+
+
+
+ ))}
+
+
+
+
+
+ )
}
diff --git a/src/containers/EntryMetadata.tsx b/src/containers/EntryMetadata.tsx
index 0e06bbc..a3f9730 100644
--- a/src/containers/EntryMetadata.tsx
+++ b/src/containers/EntryMetadata.tsx
@@ -1,53 +1,68 @@
+import { useQuery } from "@tanstack/react-query"
+import api from "../api/eolas-api"
import EntryReferences from "@/components/EntryReferences"
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
import { Bookmark } from "lucide-react"
-import { History } from "lucide-react"
import { Braces } from "lucide-react"
-
+import { Badge } from "@/components/ui/badge"
+import { convertDateFriendly } from "@/lib/utils"
export default function EntryMetadata({ entryTitle, history, metadata }) {
- return (
-
-
-
-
- References
-
+ const { data: tags } = useQuery({
+ queryKey: [`tags_for_${entryTitle}`],
+ queryFn: () => api.get(`/tags/${entryTitle}`).then((res) => res.data),
+ })
-
-
- History
-
+ const { data: backlinks } = useQuery({
+ queryKey: [`backlinks_for_${entryTitle}`],
+ queryFn: () => api.get(`/entries/backlinks/${entryTitle}`).then((res) => res.data),
+ })
-
-
- Metadata
-
-
+ const { data: outlinks } = useQuery({
+ queryKey: [`outlinks_for_${entryTitle}`],
+ queryFn: () => api.get(`/entries/outlinks/${entryTitle}`).then((res) => res.data),
+ })
-
-
-
-
-
-
-
Last modified: {history.lastModified}
-
-
-
-
-
Size on disk: {metadata.fileSize} B
-
-
-
-
- )
+ const sizeInKb = parseFloat((metadata?.fileSize / 1000).toFixed(1))
+
+ return (
+
+
+
+
+ References
+
+
+
+
+ Metadata
+
+
+
+
+
+
+
+
+
+
+
Last modified
+
+ {convertDateFriendly(new Date(history.lastModified))}
+
+
+
+
Size on disk
+
{sizeInKb} Kb
+
+
+
+
+
+ )
}
diff --git a/src/index.css b/src/index.css
index 4256742..0252064 100644
--- a/src/index.css
+++ b/src/index.css
@@ -2,130 +2,130 @@
@import "tw-animate-css";
html {
- overflow-y: hidden;
+ overflow-y: hidden;
}
@custom-variant dark (&:is(.dark *));
@theme inline {
- --radius-sm: calc(var(--radius) - 4px);
- --radius-md: calc(var(--radius) - 2px);
- --radius-lg: var(--radius);
- --radius-xl: calc(var(--radius) + 4px);
- --color-background: var(--background);
- --color-foreground: var(--foreground);
- --color-card: var(--card);
- --color-card-foreground: var(--card-foreground);
- --color-popover: var(--popover);
- --color-popover-foreground: var(--popover-foreground);
- --color-primary: var(--primary);
- --color-primary-foreground: var(--primary-foreground);
- --color-secondary: var(--secondary);
- --color-secondary-foreground: var(--secondary-foreground);
- --color-muted: var(--muted);
- --color-muted-foreground: var(--muted-foreground);
- --color-accent: var(--accent);
- --color-accent-foreground: var(--accent-foreground);
- --color-destructive: var(--destructive);
- --color-border: var(--border);
- --color-input: var(--input);
- --color-ring: var(--ring);
- --color-chart-1: var(--chart-1);
- --color-chart-2: var(--chart-2);
- --color-chart-3: var(--chart-3);
- --color-chart-4: var(--chart-4);
- --color-chart-5: var(--chart-5);
- --color-sidebar: var(--sidebar);
- --color-sidebar-foreground: var(--sidebar-foreground);
- --color-sidebar-primary: var(--sidebar-primary);
- --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
- --color-sidebar-accent: var(--sidebar-accent);
- --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
- --color-sidebar-border: var(--sidebar-border);
- --color-sidebar-ring: var(--sidebar-ring);
+ --radius-sm: calc(var(--radius) - 4px);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) + 4px);
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --color-card: var(--card);
+ --color-card-foreground: var(--card-foreground);
+ --color-popover: var(--popover);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-primary: var(--primary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-secondary: var(--secondary);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-muted: var(--muted);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-accent: var(--accent);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-destructive: var(--destructive);
+ --color-border: var(--border);
+ --color-input: var(--input);
+ --color-ring: var(--ring);
+ --color-chart-1: var(--chart-1);
+ --color-chart-2: var(--chart-2);
+ --color-chart-3: var(--chart-3);
+ --color-chart-4: var(--chart-4);
+ --color-chart-5: var(--chart-5);
+ --color-sidebar: var(--sidebar);
+ --color-sidebar-foreground: var(--sidebar-foreground);
+ --color-sidebar-primary: var(--sidebar-primary);
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
+ --color-sidebar-accent: var(--sidebar-accent);
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
+ --color-sidebar-border: var(--sidebar-border);
+ --color-sidebar-ring: var(--sidebar-ring);
}
:root {
- --radius: 0.625rem;
- --background: oklch(1 0 0);
- --foreground: oklch(0.145 0 0);
- --card: oklch(1 0 0);
- --card-foreground: oklch(0.145 0 0);
- --popover: oklch(1 0 0);
- --popover-foreground: oklch(0.145 0 0);
- --primary: oklch(0.205 0 0);
- --primary-foreground: oklch(0.985 0 0);
- --secondary: oklch(0.97 0 0);
- --secondary-foreground: oklch(0.205 0 0);
- --muted: oklch(0.97 0 0);
- --muted-foreground: oklch(0.556 0 0);
- --accent: oklch(0.97 0 0);
- --accent-foreground: oklch(0.205 0 0);
- --destructive: oklch(0.577 0.245 27.325);
- --border: oklch(0.922 0 0);
- --input: oklch(0.922 0 0);
- --ring: oklch(0.708 0 0);
- --chart-1: oklch(0.646 0.222 41.116);
- --chart-2: oklch(0.6 0.118 184.704);
- --chart-3: oklch(0.398 0.07 227.392);
- --chart-4: oklch(0.828 0.189 84.429);
- --chart-5: oklch(0.769 0.188 70.08);
- --sidebar: oklch(0.985 0 0);
- --sidebar-foreground: oklch(0.145 0 0);
- --sidebar-primary: oklch(0.205 0 0);
- --sidebar-primary-foreground: oklch(0.985 0 0);
- --sidebar-accent: oklch(0.97 0 0);
- --sidebar-accent-foreground: oklch(0.205 0 0);
- --sidebar-border: oklch(0.922 0 0);
- --sidebar-ring: oklch(0.708 0 0);
- color-scheme: light;
+ --radius: 0.625rem;
+ --background: oklch(1 0 0);
+ --foreground: oklch(0.145 0 0);
+ --card: oklch(1 0 0);
+ --card-foreground: oklch(0.145 0 0);
+ --popover: oklch(1 0 0);
+ --popover-foreground: oklch(0.145 0 0);
+ --primary: oklch(0.205 0 0);
+ --primary-foreground: oklch(0.985 0 0);
+ --secondary: oklch(0.97 0 0);
+ --secondary-foreground: oklch(0.205 0 0);
+ --muted: oklch(0.97 0 0);
+ --muted-foreground: oklch(0.556 0 0);
+ --accent: oklch(0.97 0 0);
+ --accent-foreground: oklch(0.205 0 0);
+ --destructive: oklch(0.577 0.245 27.325);
+ --border: oklch(0.922 0 0);
+ --input: oklch(0.922 0 0);
+ --ring: oklch(0.708 0 0);
+ --chart-1: oklch(0.646 0.222 41.116);
+ --chart-2: oklch(0.6 0.118 184.704);
+ --chart-3: oklch(0.398 0.07 227.392);
+ --chart-4: oklch(0.828 0.189 84.429);
+ --chart-5: oklch(0.769 0.188 70.08);
+ --sidebar: oklch(0.985 0 0);
+ --sidebar-foreground: oklch(0.145 0 0);
+ --sidebar-primary: oklch(0.205 0 0);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.97 0 0);
+ --sidebar-accent-foreground: oklch(0.205 0 0);
+ --sidebar-border: oklch(0.922 0 0);
+ --sidebar-ring: oklch(0.708 0 0);
+ color-scheme: light;
}
.dark {
- --background: oklch(0.145 0 0);
- --foreground: oklch(0.985 0 0);
- --card: oklch(0.205 0 0);
- --card-foreground: oklch(0.985 0 0);
- --popover: oklch(0.205 0 0);
- --popover-foreground: oklch(0.985 0 0);
- --primary: oklch(0.922 0 0);
- --primary-foreground: oklch(0.205 0 0);
- --secondary: oklch(0.269 0 0);
- --secondary-foreground: oklch(0.985 0 0);
- --muted: oklch(0.269 0 0);
- --muted-foreground: oklch(0.708 0 0);
- --accent: oklch(0.269 0 0);
- --accent-foreground: oklch(0.985 0 0);
- --destructive: oklch(0.704 0.191 22.216);
- --border: oklch(1 0 0 / 10%);
- --input: oklch(1 0 0 / 15%);
- --ring: oklch(0.556 0 0);
- --chart-1: oklch(0.488 0.243 264.376);
- --chart-2: oklch(0.696 0.17 162.48);
- --chart-3: oklch(0.769 0.188 70.08);
- --chart-4: oklch(0.627 0.265 303.9);
- --chart-5: oklch(0.645 0.246 16.439);
- --sidebar: oklch(0.205 0 0);
- --sidebar-foreground: oklch(0.985 0 0);
- --sidebar-primary: oklch(0.488 0.243 264.376);
- --sidebar-primary-foreground: oklch(0.985 0 0);
- --sidebar-accent: oklch(0.269 0 0);
- --sidebar-accent-foreground: oklch(0.985 0 0);
- --sidebar-border: oklch(1 0 0 / 10%);
- --sidebar-ring: oklch(0.556 0 0);
- color-scheme: dark;
+ --background: oklch(0.145 0 0);
+ --foreground: oklch(0.985 0 0);
+ --card: oklch(0.205 0 0);
+ --card-foreground: oklch(0.985 0 0);
+ --popover: oklch(0.205 0 0);
+ --popover-foreground: oklch(0.985 0 0);
+ --primary: oklch(0.922 0 0);
+ --primary-foreground: oklch(0.205 0 0);
+ --secondary: oklch(0.269 0 0);
+ --secondary-foreground: oklch(0.985 0 0);
+ --muted: oklch(0.269 0 0);
+ --muted-foreground: oklch(0.708 0 0);
+ --accent: oklch(0.269 0 0);
+ --accent-foreground: oklch(0.985 0 0);
+ --destructive: oklch(0.704 0.191 22.216);
+ --border: oklch(1 0 0 / 10%);
+ --input: oklch(1 0 0 / 15%);
+ --ring: oklch(0.556 0 0);
+ --chart-1: oklch(0.488 0.243 264.376);
+ --chart-2: oklch(0.696 0.17 162.48);
+ --chart-3: oklch(0.769 0.188 70.08);
+ --chart-4: oklch(0.627 0.265 303.9);
+ --chart-5: oklch(0.645 0.246 16.439);
+ --sidebar: oklch(0.205 0 0);
+ --sidebar-foreground: oklch(0.985 0 0);
+ --sidebar-primary: oklch(0.488 0.243 264.376);
+ --sidebar-primary-foreground: oklch(0.985 0 0);
+ --sidebar-accent: oklch(0.269 0 0);
+ --sidebar-accent-foreground: oklch(0.985 0 0);
+ --sidebar-border: oklch(1 0 0 / 10%);
+ --sidebar-ring: oklch(0.556 0 0);
+ color-scheme: dark;
}
@layer base {
- * {
- @apply border-border outline-ring/50;
- }
+ * {
+ @apply border-border outline-ring/50;
+ }
- html {
- font-family: "Inter", sans-serif;
- }
+ html {
+ font-family: "IBM Plex Sans", sans-serif;
+ }
- body {
- @apply bg-background text-foreground;
- }
+ body {
+ @apply bg-background text-foreground;
+ }
}
diff --git a/src/lib/utils.ts b/src/lib/utils.ts
index bd0c391..5709946 100644
--- a/src/lib/utils.ts
+++ b/src/lib/utils.ts
@@ -2,5 +2,28 @@ import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
- return twMerge(clsx(inputs))
+ return twMerge(clsx(inputs))
+}
+
+export const convertDateFriendly = (isoStamp) => {
+ const months = [
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December",
+ ]
+
+ const unixSeconds = new Date(isoStamp)
+ const day = unixSeconds.getDate()
+ const month = months[unixSeconds.getMonth()]
+ const year = unixSeconds.getFullYear()
+ return `${day} ${month} ${year}`
}