mirror of
https://gitlab.vegova.si/rkv/spletisce.git
synced 2025-08-15 09:37:42 +00:00
Remove contentlayer, bump next
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,7 +1,5 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
.contentlayer/
|
||||
|
||||
package-lock.json
|
||||
|
||||
# dependencies
|
||||
|
@ -7,9 +7,9 @@ authors:
|
||||
image: "/images/gallery/stol_skupinska.jpg"
|
||||
---
|
||||
|
||||
Včeraj smo se Aleks [S51PA], Domen, Kimi, Primož [S54UNC], Sergio [OE8CXC] in Žiga [S50ZK] odpravili na pohod na Karavanški Stol.
|
||||
Včeraj smo se Aleks [S51PA], Domen, Kimi, Primož [S54UNC], Sergio [OE8CXC] in Žiga [S50ZK] odpravili na pohod na Karavanški Stol.
|
||||
|
||||
Po 3-urnem pohodu smo se v Prešernovi koči okrepčali ter srečali s skrbnikom repetitorja Stol, Alenom [S56RAL], ki nam je tudi razkazal bivak. Odpravili smo se proti SOTA vrhu S5/KA-001, ki smo ga tudi aktivirali. Po končani aktivaciji smo na bivaku postavili še Diamond X300 anteno in z njo opravili nekaj zvez.
|
||||
Po 3-urnem pohodu smo se v Prešernovi koči okrepčali ter srečali s skrbnikom repetitorja Stol, Alenom [S56RAL], ki nam je tudi razkazal bivak. Odpravili smo se proti SOTA vrhu S5/KA-001, ki smo ga tudi aktivirali. Po končani aktivaciji smo na bivaku postavili še Diamond X300 anteno in z njo opravili nekaj zvez.
|
||||
|
||||
Po prihodu v dolino smo se ustavili na Bledu pri našem članu Jerneju [S54JR], ki nas je pogostil z domačimi dobrotami. Po končani pogostitvi smo se še ohladili v prijetno toplem Blejskem jezeru.
|
||||
|
||||
|
@ -1,5 +1,4 @@
|
||||
const path = require("path");
|
||||
const ncl = require("next-contentlayer");
|
||||
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
@ -9,4 +8,4 @@ const nextConfig = {
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = ncl.withContentlayer(nextConfig);
|
||||
module.exports = nextConfig;
|
||||
|
40
package.json
40
package.json
@ -14,31 +14,33 @@
|
||||
"@fortawesome/free-brands-svg-icons": "^6.2.1",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||
"@types/node": "^20.6.5",
|
||||
"@types/react": "^18.2.22",
|
||||
"@types/react-dom": "^18.2.7",
|
||||
"@types/rss": "^0.0.32",
|
||||
"bulma": "^0.9.4",
|
||||
"contentlayer": "0.3.2",
|
||||
"eslint": "^8.50.0",
|
||||
"eslint-config-next": "^13.5.2",
|
||||
"exifreader": "^4.12.0",
|
||||
"next": "^13.5.2",
|
||||
"next-contentlayer": "0.3.2",
|
||||
"next": "^14.2.3",
|
||||
"next-mdx-remote": "^5.0.0",
|
||||
"next-plausible": "^3.7.2",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"rehype-autolink-headings": "^6.1.1",
|
||||
"rehype-pretty-code": "^0.9.3",
|
||||
"rehype-slug": "^5.1.0",
|
||||
"remark-gfm": "^3.0.1",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"rehype-autolink-headings": "^7.1.0",
|
||||
"rehype-pretty-code": "^0.13.0",
|
||||
"rehype-slug": "^6.0.0",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"rss": "^1.2.2",
|
||||
"sass": "^1.68.0",
|
||||
"sharp": "^0.32.6",
|
||||
"shiki": "^0.14.0",
|
||||
"typescript": "^5.2.2"
|
||||
"shiki": "^1.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^2.8.3"
|
||||
"@types/node": "^20",
|
||||
"@types/react": "^18",
|
||||
"@types/react-dom": "^18",
|
||||
"@types/rss": "^0.0.32",
|
||||
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
||||
"@typescript-eslint/parser": "^7.3.1",
|
||||
"eslint": "^8",
|
||||
"eslint-config-next": "^14.1.3",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"prettier": "^3.2.5",
|
||||
"sass": "^1.68.0",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
import { notFound } from "next/navigation";
|
||||
import { allBlogs } from "contentlayer/generated";
|
||||
import { useMDXComponent } from "next-contentlayer/hooks";
|
||||
import { allBlogs } from "@/util/posts";
|
||||
import { Metadata } from "next";
|
||||
import { DiscordInvite } from "@/components/discord_invite";
|
||||
import ModalImage from "@/components/modal_image";
|
||||
import { MDX } from "@/components/mdx";
|
||||
|
||||
export function generateStaticParams() {
|
||||
return allBlogs.map((post) => ({ slug: post.slug }));
|
||||
export async function generateStaticParams() {
|
||||
return (await allBlogs).map((post) => ({ slug: post.slug }));
|
||||
}
|
||||
|
||||
interface BlogPageProps {
|
||||
@ -15,8 +13,10 @@ interface BlogPageProps {
|
||||
};
|
||||
}
|
||||
|
||||
export function generateMetadata({ params }: BlogPageProps): Metadata {
|
||||
const post = allBlogs.find((post) => post.slug === params.slug);
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: BlogPageProps): Promise<Metadata> {
|
||||
const post = (await allBlogs).find((post) => post.slug === params.slug);
|
||||
|
||||
if (!post) return {};
|
||||
|
||||
@ -37,41 +37,13 @@ export function generateMetadata({ params }: BlogPageProps): Metadata {
|
||||
};
|
||||
}
|
||||
|
||||
function BlogImage(props: any) {
|
||||
return (
|
||||
<div className="mb-4 is-flex">
|
||||
<div className="mx-auto blog-img">
|
||||
<ModalImage
|
||||
image={props.src}
|
||||
alt={props.alt}
|
||||
height={800}
|
||||
width={800}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Paragraph(props: any) {
|
||||
return <div className="mb-4" {...props} />;
|
||||
}
|
||||
|
||||
const components = {
|
||||
p: Paragraph,
|
||||
img: BlogImage,
|
||||
DiscordInvite,
|
||||
};
|
||||
|
||||
export default function Blog({ params }: BlogPageProps) {
|
||||
const post = allBlogs.find((post) => post.slug === params.slug);
|
||||
export default async function Blog({ params }: BlogPageProps) {
|
||||
const post = (await allBlogs).find((post) => post.slug === params.slug);
|
||||
|
||||
if (!post) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const Component = useMDXComponent(post.body.code);
|
||||
|
||||
return (
|
||||
<div className="container blog-container">
|
||||
<section className="section">
|
||||
@ -90,7 +62,7 @@ export default function Blog({ params }: BlogPageProps) {
|
||||
</div>
|
||||
</div>
|
||||
<article>
|
||||
<Component components={components} />
|
||||
<MDX source={post.content} />
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Metadata } from "next";
|
||||
import { allBlogs } from "contentlayer/generated";
|
||||
import { allBlogs } from "@/util/posts";
|
||||
import { ArticleLink } from "@/components/article_link";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
@ -11,7 +11,7 @@ export const metadata: Metadata = {
|
||||
},
|
||||
};
|
||||
|
||||
export default function BlogPage() {
|
||||
export default async function BlogPage() {
|
||||
return (
|
||||
<div className="container">
|
||||
<section className="section">
|
||||
@ -21,7 +21,7 @@ export default function BlogPage() {
|
||||
className="is-flex is-flex-direction-column is-align-items-start"
|
||||
style={{ gap: "1rem" }}
|
||||
>
|
||||
{allBlogs
|
||||
{(await allBlogs)
|
||||
.sort((a, b) => {
|
||||
const dateA = new Date(a.publishedAt).valueOf();
|
||||
const dateB = new Date(b.publishedAt).valueOf();
|
||||
|
@ -1,5 +1,5 @@
|
||||
import RSS from "rss";
|
||||
import { allBlogs, Blog } from "contentlayer/generated";
|
||||
import { allBlogs, BlogPost } from "@/util/posts";
|
||||
|
||||
function buildAuthorList(authors: string[]): string {
|
||||
let toReturn: string = "";
|
||||
@ -25,8 +25,8 @@ export async function GET() {
|
||||
language: "sl",
|
||||
});
|
||||
|
||||
allBlogs
|
||||
.sort((a: Blog, b: Blog) => {
|
||||
(await allBlogs)
|
||||
.sort((a: BlogPost, b: BlogPost) => {
|
||||
const dateA = new Date(a.publishedAt).valueOf();
|
||||
const dateB = new Date(b.publishedAt).valueOf();
|
||||
if (dateA !== dateB) {
|
||||
@ -35,7 +35,7 @@ export async function GET() {
|
||||
|
||||
return a.title.localeCompare(b.title);
|
||||
})
|
||||
.map((blog: Blog) =>
|
||||
.map((blog: BlogPost) =>
|
||||
feed.item({
|
||||
title: blog.title,
|
||||
guid: blog.slug,
|
||||
@ -43,7 +43,7 @@ export async function GET() {
|
||||
date: blog.publishedAt,
|
||||
description: blog.summary,
|
||||
author: buildAuthorList(blog.authors),
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
return new Response(feed.xml({ indent: true }), {
|
||||
|
@ -26,7 +26,7 @@ export default async function Gallery() {
|
||||
alt: exif?.ImageDescription?.description ?? "",
|
||||
time: exif?.DateTimeOriginal?.description,
|
||||
};
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
const images = imgWithMeta.sort((a, b) => {
|
||||
|
@ -5,10 +5,14 @@ import "@fortawesome/fontawesome-svg-core/styles.css";
|
||||
config.autoAddCss = false;
|
||||
|
||||
import Header from "@/components/header";
|
||||
import { Metadata } from "next";
|
||||
import { Metadata, Viewport } from "next";
|
||||
import PlausibleProvider from "next-plausible";
|
||||
import Footer from "@/components/footer";
|
||||
|
||||
export const viewport: Viewport = {
|
||||
themeColor: "#FF5100",
|
||||
};
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: {
|
||||
default: "Radioklub Vegova",
|
||||
@ -16,7 +20,6 @@ export const metadata: Metadata = {
|
||||
},
|
||||
description: "Spletna stran Radiokluba Vegova",
|
||||
metadataBase: new URL("https://www.s59veg.si"),
|
||||
themeColor: "#FF5100",
|
||||
openGraph: {
|
||||
title: {
|
||||
default: "Radioklub Vegova",
|
||||
|
@ -1,7 +1,6 @@
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { Metadata } from "next";
|
||||
import { allBlogs } from "contentlayer/generated";
|
||||
import { allBlogs } from "@/util/posts";
|
||||
import { DiscordInvite } from "@/components/discord_invite";
|
||||
import { ArticleLink } from "@/components/article_link";
|
||||
import ModalImage from "@/components/modal_image";
|
||||
@ -13,7 +12,9 @@ export const metadata: Metadata = {
|
||||
},
|
||||
};
|
||||
|
||||
export default function Home() {
|
||||
export default async function Home() {
|
||||
const blogs = await allBlogs;
|
||||
|
||||
return (
|
||||
<div className="container">
|
||||
<section className="section">
|
||||
@ -68,7 +69,7 @@ export default function Home() {
|
||||
</div>
|
||||
<h3>Najnovejše objave</h3>
|
||||
<div className="article-grid">
|
||||
{allBlogs
|
||||
{blogs
|
||||
.sort((a, b) => {
|
||||
const dateA = new Date(a.publishedAt).valueOf();
|
||||
const dateB = new Date(b.publishedAt).valueOf();
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { allBlogs } from "contentlayer/generated";
|
||||
import { allBlogs } from "@/util/posts";
|
||||
import { MetadataRoute } from "next";
|
||||
|
||||
export default function sitemap(): MetadataRoute.Sitemap {
|
||||
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
|
||||
const host = "https://www.s59veg.si";
|
||||
|
||||
const pages = ["", "/blog", "/galerija", "/tecaj"].map((url) => ({
|
||||
@ -9,7 +9,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
||||
lastModified: new Date(),
|
||||
}));
|
||||
|
||||
const posts = allBlogs.map((post) => ({
|
||||
const posts = (await allBlogs).map((post) => ({
|
||||
url: `${host}/blog/${post.slug}`,
|
||||
lastModified: new Date(post.publishedAt),
|
||||
}));
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Blog } from "contentlayer/generated";
|
||||
import { BlogPost } from "@/util/posts";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
|
||||
interface ArticleLinkProps {
|
||||
post: Blog;
|
||||
post: BlogPost;
|
||||
}
|
||||
|
||||
export function ArticleLink({ post }: ArticleLinkProps) {
|
||||
|
@ -2,14 +2,12 @@ import {
|
||||
faDiscord,
|
||||
faFacebook,
|
||||
faInstagram,
|
||||
faYoutube,
|
||||
} from "@fortawesome/free-brands-svg-icons";
|
||||
import {
|
||||
faEnvelope,
|
||||
faFilm,
|
||||
faPhone,
|
||||
faRss,
|
||||
faVideo,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import Image from "next/image";
|
||||
|
73
src/components/mdx.tsx
Normal file
73
src/components/mdx.tsx
Normal file
@ -0,0 +1,73 @@
|
||||
import { MDXRemote } from "next-mdx-remote/rsc";
|
||||
import remarkGfm from "remark-gfm";
|
||||
import rehypeSlug from "rehype-slug";
|
||||
import rehypePrettyCode from "rehype-pretty-code";
|
||||
import ModalImage from "./modal_image";
|
||||
import { DiscordInvite } from "./discord_invite";
|
||||
|
||||
function BlogImage(props: any) {
|
||||
return (
|
||||
<div className="mb-4 is-flex">
|
||||
<div className="mx-auto blog-img">
|
||||
<ModalImage
|
||||
image={props.src}
|
||||
alt={props.alt}
|
||||
height={800}
|
||||
width={800}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Paragraph(props: any) {
|
||||
return <div className="mb-4" {...props} />;
|
||||
}
|
||||
|
||||
const components = {
|
||||
p: Paragraph,
|
||||
img: BlogImage,
|
||||
DiscordInvite,
|
||||
};
|
||||
|
||||
export function MDX({ source }: { source: string }) {
|
||||
return (
|
||||
<MDXRemote
|
||||
source={source}
|
||||
components={components}
|
||||
options={{
|
||||
parseFrontmatter: true,
|
||||
mdxOptions: {
|
||||
remarkPlugins: [remarkGfm],
|
||||
rehypePlugins: [
|
||||
rehypeSlug,
|
||||
[
|
||||
rehypePrettyCode,
|
||||
{
|
||||
theme: "one-dark-pro",
|
||||
onVisitLine(node: { children: string | any[] }) {
|
||||
// Prevent lines from collapsing in `display: grid` mode, and allow empty
|
||||
// lines to be copy/pasted
|
||||
if (node.children.length === 0) {
|
||||
node.children = [{ type: "text", value: " " }];
|
||||
}
|
||||
},
|
||||
onVisitHighlightedLine(node: {
|
||||
properties: { className: string[] };
|
||||
}) {
|
||||
node.properties.className.push("line--highlighted");
|
||||
},
|
||||
onVisitHighlightedWord(node: {
|
||||
properties: { className: string[] };
|
||||
}) {
|
||||
node.properties.className = ["word--highlighted"];
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
@ -3,7 +3,9 @@
|
||||
color: white;
|
||||
font-weight: 500;
|
||||
|
||||
transition: background-color 0.2s ease-in-out, color 0.2s ease-in-out;
|
||||
transition:
|
||||
background-color 0.2s ease-in-out,
|
||||
color 0.2s ease-in-out;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
|
46
src/util/posts.ts
Normal file
46
src/util/posts.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import fs from "fs";
|
||||
import { serialize } from "next-mdx-remote/serialize";
|
||||
import path from "path";
|
||||
|
||||
export interface BlogPost {
|
||||
title: string;
|
||||
publishedAt: string;
|
||||
summary: string;
|
||||
authors: string[];
|
||||
slug: string;
|
||||
image?: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
const getBlogs = async (): Promise<BlogPost[]> => {
|
||||
const fPath = path.join(process.cwd(), "content/blog");
|
||||
const files = fs.readdirSync(fPath);
|
||||
|
||||
const posts = await Promise.all(
|
||||
files.map(async (file) => {
|
||||
const source = fs.readFileSync(path.join(fPath, file), "utf8");
|
||||
const x = await serialize(source, { parseFrontmatter: true });
|
||||
return {
|
||||
title: x.frontmatter.title as string,
|
||||
publishedAt: x.frontmatter.publishedAt as string,
|
||||
summary: x.frontmatter.summary as string,
|
||||
authors: x.frontmatter.authors as string[],
|
||||
slug: file.replace(/\.mdx$/, ""),
|
||||
image: x.frontmatter.image as string | undefined,
|
||||
content: source,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
return posts.sort((a, b) => {
|
||||
const dateA = new Date(a.publishedAt).valueOf();
|
||||
const dateB = new Date(b.publishedAt).valueOf();
|
||||
if (dateA !== dateB) {
|
||||
return dateB - dateA;
|
||||
}
|
||||
|
||||
return a.title.localeCompare(b.title);
|
||||
});
|
||||
};
|
||||
|
||||
export const allBlogs: Promise<BlogPost[]> = getBlogs();
|
@ -16,8 +16,7 @@
|
||||
"incremental": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"],
|
||||
"contentlayer/generated": ["./.contentlayer/generated"]
|
||||
"@/*": ["./src/*"]
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
@ -25,12 +24,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx",
|
||||
".contentlayer/generated",
|
||||
".next/types/**/*.ts"
|
||||
],
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
|
Reference in New Issue
Block a user