-
Notifications
You must be signed in to change notification settings - Fork 0
Implement blog snippet system and new landing page #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
91300fd
d737f6a
db70c24
347fea9
a3a55ed
e5271ed
24924f5
065b9f0
8b863fd
f1a5592
4eae751
9f5f6ab
3d560e9
10242ed
f74f774
5dd1241
6b35f55
4ca5a91
565bf1e
7b74943
1c36fad
447ed49
b32ab4e
e36c150
a8f408a
ca454b8
0a1eee3
92ba828
37bb713
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,9 @@ | ||
| // @ts-check | ||
| import { defineConfig } from 'astro/config'; | ||
|
|
||
| import react from '@astrojs/react'; | ||
|
|
||
| // https://astro.build/config | ||
| export default defineConfig({}); | ||
| export default defineConfig({ | ||
| integrations: [react()] | ||
| }); |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,183 @@ | ||||||||||||||||||||||||||
| @import url('https://fonts.googleapis.com/css2?family=Bricolage+Grotesque&display=swap'); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| :root { | ||||||||||||||||||||||||||
| --bg-color: #1a1f2e; | ||||||||||||||||||||||||||
| --text-color: #e2e8f0; | ||||||||||||||||||||||||||
| --font-family:'Bricolage Grotesque', sans-serif; | ||||||||||||||||||||||||||
| --blue-color:#7091ff; | ||||||||||||||||||||||||||
| --lblue-color:#538cd3; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| /* general */ | ||||||||||||||||||||||||||
| html { | ||||||||||||||||||||||||||
| background-color: var(--bg-color); | ||||||||||||||||||||||||||
| color: var(--text-color); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| body { | ||||||||||||||||||||||||||
| font-family: var(--font-family); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* body content */ | ||||||||||||||||||||||||||
| div{ | ||||||||||||||||||||||||||
| /* border: 1px solid white; */ | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| .container{ | ||||||||||||||||||||||||||
| display: flex; | ||||||||||||||||||||||||||
| flex-direction: row; | ||||||||||||||||||||||||||
| height: auto; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| /* container 1 */ | ||||||||||||||||||||||||||
| .content{ | ||||||||||||||||||||||||||
| display: flex; | ||||||||||||||||||||||||||
| flex-direction: column; | ||||||||||||||||||||||||||
| justify-content: center; | ||||||||||||||||||||||||||
| padding-left: 60px; | ||||||||||||||||||||||||||
| /* padding-right: 25px; */ | ||||||||||||||||||||||||||
| height: auto; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| .first_links{ | ||||||||||||||||||||||||||
| display: flex; | ||||||||||||||||||||||||||
| flex-direction: column; | ||||||||||||||||||||||||||
| font-size: 25px; | ||||||||||||||||||||||||||
| margin-top: 80px; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* paragraph title */ | ||||||||||||||||||||||||||
| .title{ | ||||||||||||||||||||||||||
| font-size: 41px; | ||||||||||||||||||||||||||
| font-weight: 400; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| .about{ | ||||||||||||||||||||||||||
| margin-top: 100px; | ||||||||||||||||||||||||||
| padding-right: 90px; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| .last_links{ | ||||||||||||||||||||||||||
| display: flex; | ||||||||||||||||||||||||||
| flex-direction: row; | ||||||||||||||||||||||||||
| gap: 16px; | ||||||||||||||||||||||||||
| font-size: 20px; | ||||||||||||||||||||||||||
| font-weight: 700; | ||||||||||||||||||||||||||
| margin-top: 130px; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* container 2: image */ | ||||||||||||||||||||||||||
| .image_container{ | ||||||||||||||||||||||||||
| width: auto; | ||||||||||||||||||||||||||
| height: auto; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| .header_image{ | ||||||||||||||||||||||||||
| margin-top: 0px; | ||||||||||||||||||||||||||
| width: 700px; | ||||||||||||||||||||||||||
| height: 710px; | ||||||||||||||||||||||||||
| border-radius: 4px; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* all links */ | ||||||||||||||||||||||||||
| a, | ||||||||||||||||||||||||||
| a:visited, | ||||||||||||||||||||||||||
| a:hover, | ||||||||||||||||||||||||||
| a:active, | ||||||||||||||||||||||||||
| a:focus { | ||||||||||||||||||||||||||
| color: white; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* Blogs specific page */ | ||||||||||||||||||||||||||
| .blogs_container{ | ||||||||||||||||||||||||||
| /* border: 1px solid white; */ | ||||||||||||||||||||||||||
| display: flex; | ||||||||||||||||||||||||||
| flex-direction: column; | ||||||||||||||||||||||||||
| margin-top: 10px; | ||||||||||||||||||||||||||
| margin-left: 28%; | ||||||||||||||||||||||||||
| width: 700px; | ||||||||||||||||||||||||||
| gap: 60px; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* date and read more colors */ | ||||||||||||||||||||||||||
| .bluecolor{ | ||||||||||||||||||||||||||
| color: var(--blue-color); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| a.readmore{ | ||||||||||||||||||||||||||
| color: var(--blue-color); | ||||||||||||||||||||||||||
| text-decoration: none; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| a.readmore:hover{ | ||||||||||||||||||||||||||
| color: var(--lblue-color); | ||||||||||||||||||||||||||
| text-decoration: underline; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| .para_space{ | ||||||||||||||||||||||||||
| line-height: 22px; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* blogs styling */ | ||||||||||||||||||||||||||
| .blog-body { | ||||||||||||||||||||||||||
| border: 1px solid pink; | ||||||||||||||||||||||||||
| display: flex; | ||||||||||||||||||||||||||
| flex-direction: column; | ||||||||||||||||||||||||||
| margin-left: 359px; | ||||||||||||||||||||||||||
| font-size: 120%; | ||||||||||||||||||||||||||
| /* align-items: center; */ | ||||||||||||||||||||||||||
| justify-content: center; | ||||||||||||||||||||||||||
| background-color:var(--bg-color); | ||||||||||||||||||||||||||
| font-family: var(--font-family); | ||||||||||||||||||||||||||
| line-height: 1.6; | ||||||||||||||||||||||||||
| padding: 9px; | ||||||||||||||||||||||||||
| color:var(--text-color); | ||||||||||||||||||||||||||
| width: 710px; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| .blog-post img { | ||||||||||||||||||||||||||
| max-width: 700px; /* or whatever width you prefer */ | ||||||||||||||||||||||||||
| height: auto; | ||||||||||||||||||||||||||
| display: block; | ||||||||||||||||||||||||||
| /* margin-top: 1px; */ | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Images should scale with container Use responsive image sizing to avoid overflow. -.blog-post img {
- max-width: 700px; /* or whatever width you prefer */
- height: auto;
- display: block;
- /* margin-top: 1px; */
-}
+.blog-post img {
+ display: block;
+ max-width: 100%;
+ width: 100%;
+ height: auto;
+}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| .blog-post title{ | ||||||||||||||||||||||||||
| align-content: center; | ||||||||||||||||||||||||||
| align-self: center; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Selector does nothing – If you intended to target a -.blog-post title{
+.blog-post .title{🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| .blog-post h1,h2,h3 { | ||||||||||||||||||||||||||
| margin-top: 1.5rem; | ||||||||||||||||||||||||||
| margin-bottom: 0.75rem; | ||||||||||||||||||||||||||
| font-size: 40px; | ||||||||||||||||||||||||||
| font-weight: 200; | ||||||||||||||||||||||||||
| /* margin-left: 3rem; */ | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| .blog-post{ | ||||||||||||||||||||||||||
| border: 1px solid red; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| .blog-post p { | ||||||||||||||||||||||||||
| margin-bottom: 0.5rem; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| .blog-meta { | ||||||||||||||||||||||||||
| display: flex; | ||||||||||||||||||||||||||
| gap: 1rem; | ||||||||||||||||||||||||||
| font-size: 0.9rem; | ||||||||||||||||||||||||||
| margin-top: 0.5rem; | ||||||||||||||||||||||||||
| margin-bottom: 1.5rem; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| .blog-post a { | ||||||||||||||||||||||||||
| color: inherit; | ||||||||||||||||||||||||||
| text-decoration: underline; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| .blog-post blockquote { | ||||||||||||||||||||||||||
| border-left: 2px solid #ccc; | ||||||||||||||||||||||||||
| padding-left: 1rem; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* .blog-body > p > em:nth-of-type(1){ | ||||||||||||||||||||||||||
| font-size: 15px; | ||||||||||||||||||||||||||
| margin-left: 50%; | ||||||||||||||||||||||||||
| color:var(--blue-color) | ||||||||||||||||||||||||||
| } */ | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| /* actual blogdiv */ | ||||||||||||||||||||||||||
| .actualblog_divh1{ | ||||||||||||||||||||||||||
| /* border: 1px solid pink; */ | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| import '../../public/styles/mylanding.css' | ||
|
|
||
| type BlogCardProps = { | ||
| title: string; | ||
| date: string; | ||
| snippet: string; | ||
| link: string; | ||
| }; | ||
|
|
||
| const BlogCard = ({ title, date, snippet, link }: BlogCardProps) => { | ||
| return ( | ||
| <div> | ||
| <p className="bluecolor" >{date}</p> | ||
| <h1><a href={link}>{title}</a></h1> | ||
| <p className="para_space">{snippet}</p> | ||
| <a className="bluecolor readmore" href={link}>Read more→</a> | ||
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default BlogCard; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| export type BlogSnippet = { | ||
| date: string; | ||
| title: string; | ||
| snippet: string; | ||
| link: string; | ||
| }; | ||
|
|
||
| export const blogPosts: BlogSnippet[] = [ | ||
| { | ||
| date: "June 28, 2025", | ||
| title: "The Power of Honest Communication in Teams", | ||
| snippet: "Honesty without clarity Charity, joined the team recently. In one of our internal discussions, we stumbled on the concept of “brutal honesty“. Her interpretation of brutal honesty was focused on the word “brutal”. This led to a very very spirited discussion on whether one needs to be brutal to be honest. She questioned whether brutal…", | ||
| link: "/blogs/blog4", | ||
| }, | ||
| { | ||
| date: "June 28, 2025", | ||
| title: "Solve, Build, Get Paid: Open Source Bounties at Akong’a", | ||
| snippet: "You don’t have to be on payroll to earn money. Akong’a Labs wants you to earn by solving real problems. How? Open source bounties. To be clear, this isn’t the vague “open-source contributions look good on your CV” stuff. Bounties, requirements, and payouts. Open to those willing to build. That’s it. That’s the blog post.…", | ||
| link: "/blogs/blog3", | ||
| }, | ||
| { | ||
| date: "June 18, 2025", | ||
| title: "Understanding Remote Onboarding: Lessons from Akonga Labs", | ||
| snippet: "“Are you readyyyyyy?!?!” That was the message I got from my manager on the morning of my onboarding and even though I was genuinely feeling a little anxious, I replied confidently: “Very ready!” Onboarding into a new company is always a mixed bag of emotions: excitement, nerves, hope, and curiosity. For me, joining Akonga Labs…", | ||
| link: "/blogs/blog2", | ||
| }, | ||
| { | ||
| date: "June 18, 2025", | ||
| title: "Why I’m starting this company", | ||
| snippet: "Outsized returns You’re going to be somewhere in your career in ten years, why not in your absolute ideal role, doing the kind of work you’d find most rewarding and having the kind of impact that you’re capable of? If you don’t believe that this is possible, you will surely fail. If you do believe it’s possible,…", | ||
| link: "/blogs/blog1", | ||
| } | ||
| ]; |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,32 @@ | ||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||
| import "../../public/styles/mylanding.css" | ||||||||||||||||||||||||||||
| import "../../public/images/blog1.webp" | ||||||||||||||||||||||||||||
| import "../../public/images/blog2.webp" | ||||||||||||||||||||||||||||
| import "../../public/images/blog3.webp" | ||||||||||||||||||||||||||||
| import "../../public/images/blog4.webp" | ||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Remove unnecessary image imports. The image imports in the frontmatter appear unused in this layout component. These should only be imported where they're actually referenced. Apply this diff to remove unused imports: ---
import "../../public/styles/mylanding.css"
-import "../../public/images/blog1.webp"
-import "../../public/images/blog2.webp"
-import "../../public/images/blog3.webp"
-import "../../public/images/blog4.webp"
---📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| --- | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| <html lang="en"> | ||||||||||||||||||||||||||||
| <head> | ||||||||||||||||||||||||||||
| <head> | ||||||||||||||||||||||||||||
| <meta charset="utf-8" /> | ||||||||||||||||||||||||||||
| <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> | ||||||||||||||||||||||||||||
| <meta name="viewport" content="width=device-width" /> | ||||||||||||||||||||||||||||
| <title>Blog layout</title> | ||||||||||||||||||||||||||||
| </head> | ||||||||||||||||||||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix duplicate head tags. There are nested Apply this diff to fix the structure: <head>
- <head>
- <meta charset="utf-8" />
- <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
- <meta name="viewport" content="width=device-width" />
- <title>Blog layout</title>
+ <meta charset="utf-8" />
+ <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
+ <meta name="viewport" content="width=device-width" />
+ <title>Blog layout</title>
</head>📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||
| <body > | ||||||||||||||||||||||||||||
| <article class="blog-post"> | ||||||||||||||||||||||||||||
| <div class="blog-body"> | ||||||||||||||||||||||||||||
| <div class="first_links"> | ||||||||||||||||||||||||||||
| <a href="/newLanding">Akong'a Labs</a> | ||||||||||||||||||||||||||||
| <a href="/blogSnippets">Blogs</a> | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| <slot /> <!-- where the blog content goes --> | ||||||||||||||||||||||||||||
| <div class="last_links"> | ||||||||||||||||||||||||||||
| <p> <a href="https://x.com/adrianmurage">X</a> </p> | ||||||||||||||||||||||||||||
| <p> <a href="https://github.com/AkongaLabs">GitHub</a></p> | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||
| </article> | ||||||||||||||||||||||||||||
| </body> | ||||||||||||||||||||||||||||
| </html> | ||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| --- | ||
| import "../../public/styles/mylanding.css" | ||
| import BlogCard from "../components/BlogCard.tsx"; | ||
| import {blogPosts} from '../data/blogsnippets'; | ||
| --- | ||
|
Comment on lines
+1
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sanitize HTML, avoid unnecessary set:html, and improve heading semantics
Apply these diffs: ---
-import "../../src/styles/mylanding.css";
+import "../styles/mylanding.css";
import type { BlogPost } from "../data/types";
+import sanitizeHtml from "sanitize-html";
-const res = await fetch("https://akongalabs.com/wp-json/wp/v2/posts");
-const posts: BlogPost[] = await res.json();
+const res = await fetch("https://akongalabs.com/wp-json/wp/v2/posts?per_page=10");
+let posts: BlogPost[] = [];
+if (res.ok) {
+ posts = (await res.json()) as BlogPost[];
+} else {
+ console.warn("Failed to fetch posts:", res.status, res.statusText);
+}
---- <p class="bluecolor" set:html={formattedDate}></p>
- <h1 class="blog-title" set:html={post.title.rendered}></h1>
- <div class="para_space" set:html={cleanedExcerpt}></div>
+ <p class="bluecolor">{formattedDate}</p>
+ <h2 class="blog-title">
+ {post.title.rendered.replace(/<[^>]*>/g, "")}
+ </h2>
+ <div
+ class="para_space"
+ set:html={sanitizeHtml(cleanedExcerpt, {
+ allowedTags: ["p", "em", "strong", "a", "code", "pre", "ul", "ol", "li", "span", "br"],
+ allowedAttributes: { a: ["href", "rel", "target"] },
+ allowedSchemes: ["http", "https", "mailto"],
+ })}
+ ></div>Also applies to: 34-38 🤖 Prompt for AI Agents |
||
|
|
||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="utf-8" /> | ||
| <link rel="icon" type="image/svg+xml" href="/favicon.svg" /> | ||
| <meta name="viewport" content="width=device-width" /> | ||
| <title>Charity's landing page 🐼</title> | ||
| </head> | ||
| <body> | ||
| <div class="blogs_container"> | ||
| <div class="first_links"> | ||
| <a href="/newLanding">Akong'a Labs</a> | ||
| <a href="/blogSnippets">Blogs</a> | ||
| </div> | ||
| { | ||
| blogPosts.map(post => ( | ||
| <BlogCard | ||
| date={post.date} | ||
| title={post.title} | ||
| snippet={post.snippet} | ||
| link={post.link} | ||
| /> | ||
| )) | ||
| } | ||
| <div class="last_links"> | ||
| <p> <a href="https://x.com/adrianmurage">X</a> </p> | ||
| <p> <a href="https://github.com/AkongaLabs">GitHub</a></p> | ||
| </div> | ||
| </div> | ||
| </body> | ||
| </html> | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Blog body width should be fluid with a max
Prevents clipping and reliance on
overflow-x: hidden.📝 Committable suggestion
🤖 Prompt for AI Agents