diff --git a/README.md b/README.md index 3dcf23f..9d05ef5 100644 --- a/README.md +++ b/README.md @@ -1 +1,37 @@ -# sheikhcoders.github.io \ No newline at end of file +# Sheikh Coders Blog + +A bilingual (English & Bangla) static blog hosted on GitHub Pages. The homepage highlights each post with English and Bangla summaries, "Continue reading" links, and an SEO-ready banner. Individual posts live under `/posts//` with matching meta tags and structured data. + +## Project structure + +``` +assets/ + posts.json # Post metadata used to render homepage cards + site.js # Shared scripts (year + homepage population) + styles.css # Global styles for homepage + posts +posts/ + /index.html # Full bilingual article +index.html # Homepage with hero banner and auto-loaded posts +``` + +## Adding a new post + +1. **Duplicate a folder** in `posts/` (for example `posts/portfolio-landing/`) and rename it to your new slug. +2. **Update meta tags and copy** inside the new `index.html`. Keep both English and Bangla sections, and refresh the JSON-LD block. +3. **List the post** in `assets/posts.json` with the same slug, title, date, excerpts, and topics. The homepage automatically refreshes the cards using this file. + +## Local preview + +You can open the HTML files directly in a browser or serve the repo locally with any static server, e.g. + +```bash +python3 -m http.server 8000 +``` + +Then visit `http://localhost:8000` to check responsive layouts and "Continue reading" links. + +## SEO checklist + +- Canonical URLs and language alternates are configured for every page. +- Structured data (`Blog`, `BlogPosting`, and `FAQPage`) is embedded for richer search snippets. +- Mobile-first design with fluid typography and accessible language attributes for English and Bangla. diff --git a/assets/posts.json b/assets/posts.json new file mode 100644 index 0000000..132dfed --- /dev/null +++ b/assets/posts.json @@ -0,0 +1,57 @@ +[ + { + "slug": "nextjs-github-actions", + "title": "Deploy Next.js with GitHub Actions", + "date": "2024-06-02", + "displayDate": "02 Jun 2024", + "readTime": "6 min read", + "excerpt_en": "Automate build, test, and deployment steps for a Next.js app using reusable workflow jobs and Vercel or static hosting.", + "excerpt_bn": "গিটহাব অ্যাকশন্স দিয়ে কীভাবে নেক্সট.জেএস অ্যাপের বিল্ড, টেস্ট ও ডিপ্লয়মেন্ট সম্পূর্ণ স্বয়ংক্রিয় করবেন তার ধাপসমূহ।", + "topics": ["GitHub Actions", "Next.js Deploy", "CI/CD"], + "url": "/posts/nextjs-github-actions/" + }, + { + "slug": "query-string-seo", + "title": "Mastering URL Query Strings for Focused SEO", + "date": "2024-05-18", + "displayDate": "18 May 2024", + "readTime": "5 min read", + "excerpt_en": "Decode how query parameters shape personalized content, campaign tracking, and crawlable experiences with clear naming logic.", + "excerpt_bn": "কুয়েরি প্যারামিটার দিয়ে কীভাবে ব্যক্তিকৃত কন্টেন্ট, ক্যাম্পেইন ট্র্যাকিং এবং এসইও পারফরমেন্স উন্নত করা যায় তা ধাপে ধাপে জানুন।", + "topics": ["URL Query String", "SEO Logic", "Analytics"], + "url": "/posts/query-string-seo/" + }, + { + "slug": "portfolio-landing", + "title": "Build a Clean Portfolio Landing Page", + "date": "2024-05-10", + "displayDate": "10 May 2024", + "readTime": "4 min read", + "excerpt_en": "Learn the layout, typography, and SEO checklist for a one-page portfolio that loads fast on every screen size.", + "excerpt_bn": "প্রতিটি ডিভাইসে দ্রুত লোড হওয়ার জন্য কীভাবে এক-পেইজের পরিচিতিমূলক ওয়েবসাইটকে সুন্দর ও কার্যকরী রাখা যায় তার টিপস।", + "topics": ["Responsive HTML", "Minimal CSS", "SEO Basics"], + "url": "/posts/portfolio-landing/" + }, + { + "slug": "nextjs-performance", + "title": "Starter Guide to Next.js Performance", + "date": "2024-04-28", + "displayDate": "28 Apr 2024", + "readTime": "5 min read", + "excerpt_en": "A short list of essentials: dynamic metadata, image optimization, and how to measure Core Web Vitals before launch.", + "excerpt_bn": "নেক্সট.জেএস অ্যাপ লাইভ করার আগে কোন মেটাডাটা, ইমেজ অপ্টিমাইজেশন ও পারফরমেন্স পরীক্ষাগুলো জরুরি তা সহজ ভাষায়।", + "topics": ["Next.js", "Core Web Vitals", "Meta Tags"], + "url": "/posts/nextjs-performance/" + }, + { + "slug": "ai-writing", + "title": "AI Writing Workflow for Developers", + "date": "2024-04-12", + "displayDate": "12 Apr 2024", + "readTime": "4 min read", + "excerpt_en": "Keep documentation clear: prompt planning, review loops, and tone control to make AI your writing teammate.", + "excerpt_bn": "ডকুমেন্টেশন পরিষ্কার রাখতে প্রম্পট পরিকল্পনা, পুনঃমূল্যায়ন, ও টোন নিয়ন্ত্রণের মাধ্যমে কীভাবে এআই-কে সহলেখক বানাবেন।", + "topics": ["AI Workflow", "Technical Writing", "Productivity"], + "url": "/posts/ai-writing/" + } +] diff --git a/assets/site.js b/assets/site.js new file mode 100644 index 0000000..a9d922f --- /dev/null +++ b/assets/site.js @@ -0,0 +1,70 @@ +(function () { + const yearTarget = document.querySelector('[data-current-year]'); + if (yearTarget) { + yearTarget.textContent = new Date().getFullYear(); + } + + const escapeHtml = (value = '') => + String(value) + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + + const postsGrid = document.querySelector('[data-posts-grid]'); + if (!postsGrid) return; + + fetch('/assets/posts.json') + .then((response) => { + if (!response.ok) throw new Error('Failed to load posts'); + return response.json(); + }) + .then((posts) => { + if (!Array.isArray(posts) || posts.length === 0) { + return; + } + + const sortedPosts = posts.slice().sort((a, b) => new Date(b.date) - new Date(a.date)); + const fragment = document.createDocumentFragment(); + + sortedPosts.forEach((post) => { + const article = document.createElement('article'); + article.className = 'post-card'; + + const topics = Array.isArray(post.topics) ? post.topics : []; + const topicsMarkup = topics + .map((topic) => `
  • ${escapeHtml(topic)}
  • `) + .join(''); + + const url = escapeHtml(post.url); + const title = escapeHtml(post.title); + + article.innerHTML = ` + + ${post.readTime ? `

    ${escapeHtml(post.readTime)}

    ` : ''} +

    ${title}

    +

    ${escapeHtml(post.excerpt_en)}

    +

    ${escapeHtml(post.excerpt_bn)}

    + ${topicsMarkup ? `` : ''} + + Continue reading + + + `; + + fragment.appendChild(article); + }); + + postsGrid.replaceChildren(fragment); + }) + .catch(() => { + const status = document.createElement('p'); + status.className = 'bangla'; + status.setAttribute('role', 'status'); + status.textContent = 'পোস্ট তালিকা লোড করা যাচ্ছে না। অনুগ্রহ করে পরে চেষ্টা করুন।'; + postsGrid.appendChild(status); + }); +})(); diff --git a/assets/styles.css b/assets/styles.css new file mode 100644 index 0000000..3633495 --- /dev/null +++ b/assets/styles.css @@ -0,0 +1,517 @@ +:root { + color-scheme: light dark; + --background: #f9fafb; + --foreground: #0f172a; + --accent: #0f172a; + --accent-foreground: #f9fafb; + --muted: #475569; + --muted-foreground: rgba(15, 23, 42, 0.68); + --card: #ffffff; + --card-border: rgba(15, 23, 42, 0.08); + --radius: 18px; + --shadow: 0 18px 45px rgba(15, 23, 42, 0.12); + font-size: 16px; +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #020617; + --foreground: #f8fafc; + --accent: #f8fafc; + --accent-foreground: #020617; + --muted: #cbd5f5; + --muted-foreground: rgba(203, 213, 255, 0.78); + --card: rgba(15, 23, 42, 0.66); + --card-border: rgba(248, 250, 252, 0.1); + --shadow: 0 20px 40px rgba(15, 23, 42, 0.4); + } +} + +* { + box-sizing: border-box; +} + +body { + margin: 0; + font-family: "Inter", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + background: var(--background); + color: var(--foreground); + line-height: 1.65; + -webkit-font-smoothing: antialiased; +} + +a { + color: inherit; +} + +a:hover, +a:focus { + color: inherit; +} + +img { + max-width: 100%; + display: block; +} + +.site-header, +.post-header { + padding: clamp(2.5rem, 6vw, 4rem) clamp(1rem, 7vw, 5rem) clamp(1.5rem, 5vw, 3rem); +} + +.top-nav { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + gap: 0.75rem; + margin-bottom: clamp(1.5rem, 4vw, 2.75rem); +} + +.brand { + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; + font-size: 0.9rem; + text-decoration: none; +} + +.subscribe { + display: inline-flex; + align-items: center; + gap: 0.6rem; + padding: 0.55rem 1.1rem; + border-radius: 999px; + background: var(--accent); + color: var(--accent-foreground); + font-weight: 600; + text-decoration: none; + transition: transform 150ms ease, box-shadow 150ms ease; + box-shadow: 0 12px 30px rgba(15, 23, 42, 0.16); +} + +.subscribe:hover, +.subscribe:focus-visible { + transform: translateY(-2px); + box-shadow: 0 18px 36px rgba(15, 23, 42, 0.18); +} + +.hero-banner { + background: radial-gradient(circle at top right, rgba(59, 130, 246, 0.15), transparent 55%), + linear-gradient(135deg, rgba(15, 23, 42, 0.94), rgba(30, 64, 175, 0.7)); + color: #f8fafc; + border-radius: clamp(1.5rem, 5vw, 2.5rem); + padding: clamp(2rem, 6vw, 3rem); + display: grid; + gap: clamp(0.75rem, 2vw, 1.25rem); + max-width: 920px; + box-shadow: var(--shadow); +} + +.hero-banner .tagline { + text-transform: uppercase; + letter-spacing: 0.12em; + font-size: 0.75rem; + opacity: 0.85; +} + +.hero-banner h1 { + margin: 0; + font-size: clamp(2.4rem, 6vw, 3.4rem); + line-height: 1.15; + letter-spacing: -0.015em; +} + +.hero-banner .lead { + margin: 0; + font-size: clamp(1rem, 2.5vw, 1.15rem); + color: rgba(248, 250, 252, 0.84); +} + +main { + padding: 0 clamp(1rem, 7vw, 5rem) clamp(4rem, 10vw, 6rem); + display: grid; + gap: clamp(3rem, 8vw, 4.5rem); +} + +.section-heading { + display: grid; + gap: 0.5rem; + max-width: 720px; +} + +.section-heading h2 { + margin: 0; + font-size: clamp(1.8rem, 4vw, 2.35rem); +} + +.section-heading p { + margin: 0; + color: var(--muted-foreground); +} + +.posts-section .section-heading { + margin-bottom: 1.5rem; +} + +.posts-grid { + display: grid; + gap: clamp(1.5rem, 4vw, 2rem); + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); +} + +.post-card { + background: var(--card); + border: 1px solid var(--card-border); + border-radius: var(--radius); + padding: clamp(1.4rem, 3.5vw, 1.9rem); + display: grid; + gap: 0.75rem; + transition: transform 180ms ease, box-shadow 180ms ease; +} + +.post-card:hover, +.post-card:focus-within { + transform: translateY(-4px); + box-shadow: var(--shadow); +} + +.post-card time { + font-size: 0.85rem; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--muted); +} + +.post-card .reading-time { + font-size: 0.85rem; + color: var(--muted-foreground); + margin: 0; +} + +.post-card h3 { + margin: 0; + font-size: 1.35rem; + line-height: 1.35; +} + +.post-card h3 a { + text-decoration: none; +} + +.post-card p { + margin: 0; + color: var(--muted-foreground); +} + +.bangla { + font-weight: 500; + color: var(--foreground); +} + +.topic-list { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin: 0.5rem 0 0; + padding: 0; + list-style: none; +} + +.topic-list li { + padding: 0.35rem 0.75rem; + border-radius: 999px; + background: rgba(15, 23, 42, 0.08); + font-size: 0.82rem; + color: var(--foreground); +} + +@media (prefers-color-scheme: dark) { + .topic-list li { + background: rgba(248, 250, 252, 0.1); + color: var(--accent-foreground); + } +} + +.read-more { + display: inline-flex; + align-items: center; + gap: 0.35rem; + font-weight: 600; + color: var(--accent); + text-decoration: none; + font-size: 0.95rem; +} + +code { + font-family: "Fira Code", "Geist Mono", "SFMono-Regular", monospace; + font-size: 0.92rem; + background: rgba(15, 23, 42, 0.08); + padding: 0.15rem 0.35rem; + border-radius: 0.4rem; +} + +pre { + margin: 0; + background: rgba(15, 23, 42, 0.08); + padding: 1rem; + border-radius: 0.75rem; + overflow-x: auto; + font-size: 0.9rem; + line-height: 1.6; +} + + (prefers-color-scheme: dark) { + code { + background: rgba(248, 250, 252, 0.12); + color: var(--accent-foreground); + } + + pre { + background: rgba(248, 250, 252, 0.12); + } +} + + +.read-more svg { + width: 1rem; + height: 1rem; + transition: transform 150ms ease; +} + +.read-more:hover svg, +.read-more:focus svg { + transform: translateX(3px); +} + +.seo-section, +.workflow-section, +.faq-section { + background: var(--card); + border: 1px solid var(--card-border); + border-radius: var(--radius); + padding: clamp(1.8rem, 5vw, 2.4rem); + display: grid; + gap: clamp(1.4rem, 4vw, 2rem); +} + +.seo-points, +.workflow-steps, +.faq-grid { + display: grid; + gap: clamp(1rem, 3vw, 1.4rem); + grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); +} + +.card { + background: rgba(15, 23, 42, 0.04); + border-radius: calc(var(--radius) - 6px); + padding: 1.1rem 1.25rem; + display: grid; + gap: 0.5rem; +} + +@media (prefers-color-scheme: dark) { + .card { + background: rgba(248, 250, 252, 0.08); + } +} + +.card h3 { + margin: 0; + font-size: 1.05rem; +} + +.card p { + margin: 0; + color: var(--muted-foreground); +} + +.workflow-steps { + counter-reset: step; +} + +.workflow-steps li { + list-style: none; + background: rgba(15, 23, 42, 0.04); + border-radius: calc(var(--radius) - 8px); + padding: 1.1rem 1.25rem 1.1rem 1.65rem; + position: relative; + display: grid; + gap: 0.4rem; +} + +.workflow-steps li::before { + counter-increment: step; + content: counter(step); + position: absolute; + left: 1rem; + top: 1rem; + font-weight: 700; + font-size: 0.9rem; + color: var(--accent); +} + +.workflow-steps p { + margin: 0; + color: var(--muted-foreground); +} + +@media (prefers-color-scheme: dark) { + .workflow-steps li { + background: rgba(248, 250, 252, 0.08); + } +} + +footer { + padding: clamp(2rem, 6vw, 3rem) clamp(1rem, 7vw, 5rem) 3rem; + display: grid; + gap: 0.5rem; + color: var(--muted-foreground); + font-size: 0.95rem; +} + +footer a { + color: inherit; + text-decoration: underline; + text-decoration-thickness: 2px; + text-decoration-color: rgba(15, 23, 42, 0.25); +} + +@media (prefers-color-scheme: dark) { + footer a { + text-decoration-color: rgba(248, 250, 252, 0.4); + } +} + +/* Post detail pages */ + +.post-main { + padding: 0 clamp(1rem, 7vw, 5rem) clamp(4rem, 10vw, 6rem); +} + +.post-article { + max-width: 820px; + margin: 0 auto; + background: var(--card); + border: 1px solid var(--card-border); + border-radius: var(--radius); + padding: clamp(1.8rem, 5vw, 2.6rem); + display: grid; + gap: clamp(1.5rem, 4vw, 2.1rem); +} + +.post-hero { + display: grid; + gap: 0.75rem; +} + +.post-hero .post-meta { + margin: 0; + font-size: 0.85rem; + text-transform: uppercase; + letter-spacing: 0.08em; + color: var(--muted); +} + +.post-hero h1 { + margin: 0; + font-size: clamp(2rem, 5vw, 2.6rem); + line-height: 1.2; +} + +.post-hero p { + margin: 0; + color: var(--muted-foreground); +} + +.post-body { + display: grid; + gap: 0.75rem; +} + +.post-body h2, +.post-body h3 { + margin-bottom: 0.35rem; + margin-top: 1.2rem; +} + +.post-body p { + margin: 0; + color: var(--muted-foreground); +} + +.post-body ul, +.post-body ol { + margin: 0; + padding-left: 1.2rem; + display: grid; + gap: 0.5rem; + color: var(--muted-foreground); +} + +.post-topics { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin: 0; + padding: 0; + list-style: none; +} + +.post-topics li { + padding: 0.4rem 0.8rem; + border-radius: 999px; + background: rgba(15, 23, 42, 0.08); + font-size: 0.82rem; + color: var(--foreground); +} + +@media (prefers-color-scheme: dark) { + .post-topics li { + background: rgba(248, 250, 252, 0.1); + color: var(--accent-foreground); + } +} + +.post-footer { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + gap: 1rem; + align-items: center; +} + +.back-link { + display: inline-flex; + align-items: center; + gap: 0.35rem; + font-weight: 600; + text-decoration: none; +} + +.back-link svg { + width: 1rem; + height: 1rem; +} + +@media (max-width: 640px) { + .hero-banner { + border-radius: 1.25rem; + } + + .posts-grid { + grid-template-columns: 1fr; + } + + .seo-points, + .workflow-steps, + .faq-grid { + grid-template-columns: 1fr; + } + + .post-footer { + flex-direction: column; + align-items: flex-start; + } +} diff --git a/index.html b/index.html index b1a6f3b..5809706 100644 --- a/index.html +++ b/index.html @@ -4,14 +4,14 @@ - Sheikh Coders Blog | Minimal Insights in English & Bangla + Sheikh Coders Blog | Bilingual Tech Notes & SEO-Focused Guides @@ -23,7 +23,7 @@ @@ -34,7 +34,7 @@ @@ -43,272 +43,13 @@ href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet" /> - + + + -
    -