diff --git a/src/components/ArticleList.astro b/src/components/ArticleList.astro
index 698b205..29512d2 100644
--- a/src/components/ArticleList.astro
+++ b/src/components/ArticleList.astro
@@ -5,7 +5,7 @@ const { posts, displayDate = false, placeholder = false } = Astro.props;
{posts.map((post) => (
{displayDate && {new Date(post.data.date).toISOString().split('T')[0]}}
- {post.data.title}
+ {post.data.draft && [draft] }{post.data.title}
))}
diff --git a/src/components/OutDatedCallOut.astro b/src/components/OutDatedCallOut.astro
new file mode 100644
index 0000000..ff09685
--- /dev/null
+++ b/src/components/OutDatedCallOut.astro
@@ -0,0 +1,14 @@
+---
+import Callout from "./shortcodes/Callout.astro"
+const { lastUpdatedAt } = Astro.props
+const lastUpdated = new Date(lastUpdatedAt).getTime()
+const dateNow = new Date().getTime()
+const dateDelta = dateNow - lastUpdated
+const Day = 1000 * 60 * 60 * 24
+const daysDelta = Math.round(dateDelta / Day)
+---
+{ daysDelta >= 30 &&
+
+ This article was updated on {daysDelta} days ago. The content may be outdated.
+
+}
\ No newline at end of file
diff --git a/src/config.ts b/src/config.ts
index d7663b0..d0fb3de 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -37,6 +37,13 @@ export const siteConfig = {
listuuid: '3546fc35-fd75-4163-936a-114514191981', // the id of the list to subscribe to, can be found in the listmonk admin panel
}
},
+ // outdated callout
+ // enable the callout to notify users that the content maybe outdated, this will add a callout to the top of the article page,
+ // initialized by the server islands
+ outdatedCallout: {
+ enabled: true,
+ daysBeforeOutdated: 90, // the number of days before the content is considered outdated, defaults to 90 days
+ },
// encryption
// the global password to encrypt/decrypt the content, if set, all without specifying a password will be encrypted with this password
// To use an environment variable to set the password, replace the value with `import.meta.env.CONTENT_PASSWORD`
diff --git a/src/content/posts/outdated-test/index.md b/src/content/posts/outdated-test/index.md
new file mode 100644
index 0000000..21fffb7
--- /dev/null
+++ b/src/content/posts/outdated-test/index.md
@@ -0,0 +1,9 @@
+---
+title: 'the Origin of the Computer Science'
+description: 'A walkthrough of my current terminal configuration'
+date: '1970-01-01'
+updated: '2000-01-01'
+author:
+ - 'Wheatley'
+---
+The
\ No newline at end of file
diff --git a/src/pages/blog/[...slug].astro b/src/pages/blog/[...slug].astro
index a4c5164..5b9b4e0 100644
--- a/src/pages/blog/[...slug].astro
+++ b/src/pages/blog/[...slug].astro
@@ -11,6 +11,7 @@ import AuthorInfo from "../../components/helper/authors/Info.astro";
import TableOfContents from "../../components/TableOfContents.astro";
import "katex/dist/katex.css"
import { getLangFromUrl, useTranslations, useTranslatedPath } from '../../i18n/utils';
+import OutDatedCallOut from "../../components/OutDatedCallOut.astro";
const lang = getLangFromUrl(Astro.url);
const t = useTranslations(lang);
@@ -34,10 +35,10 @@ const author = Array.isArray(entry.data.author) ? entry.data.author : (entry.dat
// Get Wordcount and Last Updated Date
const wordcount = remarkPluginFrontmatter.wordcount;
-const lastUpdated = remarkPluginFrontmatter.lastModified;
+const lastUpdated = entry.data.updated ? entry.data.updated : remarkPluginFrontmatter.lastModified;
const pubDate = new Date(entry.data.date).toISOString().split('T')[0]
-const lastUpdatedDate = entry.data.updated ? new Date(entry.data.updated).toISOString().split('T')[0] : new Date(lastUpdated).toISOString().split('T')[0];
+const lastUpdatedDate = new Date(lastUpdated).toISOString().split('T')[0]
// Get author data
const authorData = await Promise.all((author).map((singleAuthor) => getEntry(singleAuthor).then(authorEntry => authorEntry?.data)))
@@ -73,6 +74,7 @@ const cover = customFeaturedImage || matchedImage_src?.src || firstImageURL || `
{ (cover && cover !== firstImageURL && cover !== `/blog/${slug}/featured.png`) && }
{headings.length !== 0 && }
{entry.data.summary && {entry.data.summary}
}
+
diff --git a/src/styles/global.css b/src/styles/global.css
index 9b0cc3f..d946250 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -1,336 +1,358 @@
@import url(@fontsource-variable/jetbrains-mono);
/* Global Styles for Terminal Blog */
:root {
- /* Dark theme (default) */
- --bg-color: #2e3440;
- --text-color: #d8dee9;
- --secondary-text-color: #c8c8c8;
- --accent-color: #90a8c0;
- --secondary-color: #7890a8;
- --border-color: #3b4351;
- --header-color: #eceff4;
- --terminal-green: #a3be8c;
- --terminal-yellow: #ebcb8b;
- --terminal-red: #bf616a;
- --font-mono: 'JetBrains Mono',ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
+ /* Dark theme (default) */
+ --bg-color: #2e3440;
+ --text-color: #d8dee9;
+ --secondary-text-color: #c8c8c8;
+ --accent-color: #90a8c0;
+ --secondary-color: #7890a8;
+ --border-color: #3b4351;
+ --header-color: #eceff4;
+ --terminal-green: #a3be8c;
+ --terminal-yellow: #ebcb8b;
+ --terminal-red: #bf616a;
+ --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, "SF Mono", Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}
+
/* Light theme */
@media (prefers-color-scheme: light) {
- :root:not([data-theme="dark"]) {
+ :root:not([data-theme="dark"]) {
+ --bg-color: #eceff4;
+ --text-color: #2e3440;
+ --secondary-text-color: #4c566a;
+ --accent-color: #486090;
+ --secondary--color: #6078a8;
+ --border-color: #d1d5db;
+ --header-color: #2e3440;
+ --terminal-green: #4b644b;
+ --terminal-yellow: #ebcb8b;
+ --terminal-red: #bf616a;
+ }
+}
+
+/* Light theme override (for switch) */
+:root[data-theme="light"] {
--bg-color: #eceff4;
--text-color: #2e3440;
--secondary-text-color: #4c566a;
--accent-color: #486090;
- --secondary--color: #6078a8;
--border-color: #d1d5db;
--header-color: #2e3440;
--terminal-green: #4b644b;
--terminal-yellow: #ebcb8b;
--terminal-red: #bf616a;
- }
-}
-/* Light theme override (for switch) */
-:root[data-theme="light"] {
- --bg-color: #eceff4;
- --text-color: #2e3440;
- --secondary-text-color: #4c566a;
- --accent-color: #486090;
- --border-color: #d1d5db;
- --header-color: #2e3440;
- --terminal-green: #4b644b;
- --terminal-yellow: #ebcb8b;
- --terminal-red: #bf616a;
}
*, *::before, *::after {
- box-sizing: border-box;
- margin: 0;
- padding: 0;
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
}
html, body {
- font-family: var(--font-mono);
- background-color: var(--bg-color);
- color: var(--text-color);
- line-height: 1.5;
- height: 100%;
- width: 100%;
- transition: background-color 0.3s ease, color 0.3s ease;
- text-align: left;
- word-wrap: break-word;
- overflow-wrap: break-word;
+ font-family: var(--font-mono);
+ background-color: var(--bg-color);
+ color: var(--text-color);
+ line-height: 1.5;
+ height: 100%;
+ width: 100%;
+ transition: background-color 0.3s ease, color 0.3s ease;
+ text-align: left;
+ word-wrap: break-word;
+ overflow-wrap: break-word;
}
a {
- color: var(--accent-color);
- text-decoration: none;
- transition: opacity 0.2s ease;
+ color: var(--accent-color);
+ text-decoration: none;
+ transition: opacity 0.2s ease;
}
a:hover {
- opacity: 0.8;
+ opacity: 0.8;
}
body {
- max-width: 1200px;
- margin: 0 auto;
- padding: 2rem 1rem;
- min-height: calc(100vh - 120px);
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 2rem 1rem;
+ min-height: calc(100vh - 120px);
}
.container {
- max-width: 900px;
- margin: 0 auto;
+ max-width: 900px;
+ margin: 0 auto;
}
.terminal-path {
- background-color: var(--accent-color);
- color: var(--bg-color);
- padding: 5px 10px;
- font-size: 1rem;
- font-weight: 500;
- margin-bottom: 1rem;
- display: inline-block;
+ background-color: var(--accent-color);
+ color: var(--bg-color);
+ padding: 5px 10px;
+ font-size: 1rem;
+ font-weight: 500;
+ margin-bottom: 1rem;
+ display: inline-block;
}
.content-box {
- border: 1px solid var(--accent-color);
- padding: 2rem;
- margin-bottom: 2rem;
- transition: border-color 0.3s ease;
+ border: 1px solid var(--accent-color);
+ padding: 2rem;
+ margin-bottom: 2rem;
+ transition: border-color 0.3s ease;
}
.nav {
- display: flex;
- flex-wrap: wrap;
- gap: 2rem;
- margin: 1.5rem 0;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 2rem;
+ margin: 1.5rem 0;
}
.nav a {
- font-size: 1rem;
+ font-size: 1rem;
}
.nav a::before {
- content: "./";
- opacity: 0.7;
+ content: "./";
+ opacity: 0.7;
}
-.nav a.home::before{
- content: "";
+
+.nav a.home::before {
+ content: "";
}
+
.cursor {
- display: inline-block;
- width: 0.6em;
- height: 1em;
- background-color: var(--text-color);
- margin-left: 0.2em;
- animation: blink 1s step-end infinite;
+ display: inline-block;
+ width: 0.6em;
+ height: 1em;
+ background-color: var(--text-color);
+ margin-left: 0.2em;
+ animation: blink 1s step-end infinite;
}
@keyframes blink {
- from, to { opacity: 1; }
- 50% { opacity: 0; }
+ from, to {
+ opacity: 1;
+ }
+ 50% {
+ opacity: 0;
+ }
}
.footer {
- text-align: center;
- padding: 2rem 0;
- font-size: 0.9rem;
- font-weight: 300;
- color: var(--secondary-text-color);
+ text-align: center;
+ padding: 2rem 0;
+ font-size: 0.9rem;
+ font-weight: 300;
+ color: var(--secondary-text-color);
}
.footer svg {
- vertical-align: middle;
+ vertical-align: middle;
}
.footer .floating {
- position: fixed;
- bottom: 20px;
- right: 30px;
- z-index: 10;
- display: flex;
- flex-direction: column;
- border: none;
- outline: none;
- padding: 15px;
+ position: fixed;
+ bottom: 20px;
+ right: 30px;
+ z-index: 10;
+ display: flex;
+ flex-direction: column;
+ border: none;
+ outline: none;
+ padding: 15px;
}
#toTopBtn {
- display: none;
- background: var(--border-color);
- border: none;
- color: var(--text-color);
- padding: 0.5rem 1rem;
- font-family: var(--font-mono);
- cursor: pointer;
+ display: none;
+ background: var(--border-color);
+ border: none;
+ color: var(--text-color);
+ padding: 0.5rem 1rem;
+ font-family: var(--font-mono);
+ cursor: pointer;
}
#toTopBtn:hover {
- background: var(--accent-color);
- color: var(--bg-color);
+ background: var(--accent-color);
+ color: var(--bg-color);
}
+
/* Theme Switcher */
.theme-switcher {
- background: var(--border-color);
- border: none;
- color: var(--text-color);
- padding: 0.5rem 1rem;
- font-family: var(--font-mono);
- cursor: pointer;
- transition: background-color 0.3s ease, color 0.3s ease;
+ background: var(--border-color);
+ border: none;
+ color: var(--text-color);
+ padding: 0.5rem 1rem;
+ font-family: var(--font-mono);
+ cursor: pointer;
+ transition: background-color 0.3s ease, color 0.3s ease;
}
.theme-switcher:hover {
- background: var(--accent-color);
- color: var(--bg-color);
+ background: var(--accent-color);
+ color: var(--bg-color);
}
/* Contents */
h1.title {
- color: var(--header-color);
- font-size: 1.75rem;
- font-weight: bold;
- margin-bottom: 0.5rem;
+ color: var(--header-color);
+ font-size: 1.75rem;
+ font-weight: bold;
+ margin-bottom: 0.5rem;
}
+
div.content {
- margin: 1rem auto;
- span.date {
- color: var(--secondary-text-color);
- font-size: 0.9rem;
- font-weight: 300;
- margin-bottom: 1.5rem;
- display: block;
- }
- span.list-date {
- color: var(--secondary-text-color);
- font-size: 0.9rem;
- font-weight: 300;
- margin-bottom: 1.5rem;
- }
-
- ul, ol, li {
- list-style-position: inside;
- }
- ul {
- padding-left: 20px;
- margin-top: 0.5em;
- margin-bottom: 1em;
- }
- ul li {
- padding-left: 0.5em;
- margin-bottom: 0.5em;
- line-height: 1.3;
- }
-
- pre {
- padding: 1rem;
margin: 1rem auto;
- }
- /* Highlighted Code Blocks */
- pre.astro-code,
- pre.astro-code span {
- background-color: #3b4252 !important;
- }
- table {
- border-collapse: collapse;
- }
+ span.date {
+ color: var(--secondary-text-color);
+ font-size: 0.9rem;
+ font-weight: 300;
+ margin-bottom: 1.5rem;
+ display: block;
+ }
- table,
- th,
- td {
- border: 1px dashed var(--secondary-text-color);
- padding: 10px;
- }
+ span.list-date {
+ color: var(--secondary-text-color);
+ font-size: 0.9rem;
+ font-weight: 300;
+ margin-bottom: 1.5rem;
+ }
- h1, h2, h3, h4 {
- margin: 0.5rem 0;
- line-height: 1.3;
- }
+ span.draft-badge {
+ color: var(--secondary-text-color);
+ font-weight: 300;
+ }
- a {
- text-decoration: underline 1px;
- }
+ ul, ol, li {
+ list-style-position: inside;
+ }
- blockquote {
- border-left: 1px solid var(--accent-color);
- color: var(--text-color);
- padding: 20px;
- font-style: italic;
- margin-left: 0;
- margin-right: 0;
- }
+ ul {
+ padding-left: 20px;
+ margin-top: 0.5em;
+ margin-bottom: 1em;
+ }
- /* Responsive Images */
- img {
- max-width: 100%;
- height: 100%;
- }
+ ul li {
+ padding-left: 0.5em;
+ margin-bottom: 0.5em;
+ line-height: 1.3;
+ }
+
+ pre {
+ padding: 1rem;
+ margin: 1rem auto;
+ }
+
+ /* Highlighted Code Blocks */
+
+ pre.astro-code,
+ pre.astro-code span {
+ background-color: #3b4252 !important;
+ }
+
+ table {
+ border-collapse: collapse;
+ }
+
+ table,
+ th,
+ td {
+ border: 1px dashed var(--secondary-text-color);
+ padding: 10px;
+ }
+
+ h1, h2, h3, h4 {
+ margin: 0.5rem 0;
+ line-height: 1.3;
+ }
+
+ a {
+ text-decoration: underline 1px;
+ }
+
+ blockquote {
+ border-left: 1px solid var(--accent-color);
+ color: var(--text-color);
+ padding: 20px;
+ font-style: italic;
+ margin-left: 0;
+ margin-right: 0;
+ }
+
+ /* Responsive Images */
+
+ img {
+ max-width: 100%;
+ height: 100%;
+ }
}
-
/* Terminal Commands */
.command {
- color: var(--terminal-green);
- margin-right: 0.5rem;
+ color: var(--terminal-green);
+ margin-right: 0.5rem;
}
.command::before {
- content: "$ ";
- opacity: 0.7;
+ content: "$ ";
+ opacity: 0.7;
}
/* helper Class */
.fade-in {
- opacity: 1;
- transition-property: opacity;
- transition-duration: .7s;
- transition-timing-function: cubic-bezier(.4,0,1,1);
+ opacity: 1;
+ transition-property: opacity;
+ transition-duration: .7s;
+ transition-timing-function: cubic-bezier(.4, 0, 1, 1);
}
+
.fade-out {
- opacity: 0;
- transition-property: opacity;
- transition-duration: .7s;
- transition-timing-function: cubic-bezier(.4,0,1,1);
+ opacity: 0;
+ transition-property: opacity;
+ transition-duration: .7s;
+ transition-timing-function: cubic-bezier(.4, 0, 1, 1);
}
/* Media Queries */
@media (max-width: 768px) {
- .terminal-path {
- font-size: 1rem;
- }
-
- .nav {
- gap: 1rem;
- }
-
- .content-box {
- padding: 1.5rem;
- }
+ .terminal-path {
+ font-size: 1rem;
+ }
+
+ .nav {
+ gap: 1rem;
+ }
+
+ .content-box {
+ padding: 1.5rem;
+ }
}
@media (max-width: 480px) {
- .terminal-path {
- font-size: 0.9rem;
- }
-
- .nav {
- gap: 0.8rem;
- }
-
- .content-box {
- padding: 1rem;
- }
+ .terminal-path {
+ font-size: 0.9rem;
+ }
+
+ .nav {
+ gap: 0.8rem;
+ }
+
+ .content-box {
+ padding: 1rem;
+ }
}
/* Printing */
@media print {
- /* Hide elements not needed for print */
- nav.nav,.search-container,footer,div.extra-post {
- display: none;
- }
+ /* Hide elements not needed for print */
+ nav.nav, .search-container, footer, div.extra-post {
+ display: none;
+ }
}