-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## New Features - Implemented blog functionality: - Added blog page HTML (843d2b4) - Created post page HTML (707da17) - Developed an action for parsing and displaying posts (6450161) - Implemented list posts feature (1de0b9a) - Added a route for `/blog/:slug` (02e1443) - Enhanced GitHub integration: - Added cache for GitHub API calls (794a972) - Implemented logic to fetch posts from GitHub (3a572bd) - Improved blog actions and cache logic (a38f5a6) ## Bug Fixes - Added ability to use Phoenix links (81576a0) - Updated robots.txt to disallow certain routes (8aff117) ## Maintenance - Updated packages and added new ones for blog functionality (f9f4c98)
- Loading branch information
1 parent
2902184
commit 697e9e1
Showing
11 changed files
with
196 additions
and
61 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,36 +1,29 @@ | ||
defmodule Portfolio.Application do | ||
# See https://hexdocs.pm/elixir/Application.html | ||
# for more information on OTP Applications | ||
@moduledoc false | ||
|
||
use Application | ||
|
||
@impl true | ||
def start(_type, _args) do | ||
children = [ | ||
# Start the Telemetry supervisor | ||
PortfolioWeb.Telemetry, | ||
# Start the PubSub system | ||
{Phoenix.PubSub, name: Portfolio.PubSub}, | ||
# Start Finch | ||
{Finch, name: Portfolio.Finch}, | ||
# Start the Endpoint (http/https) | ||
PortfolioWeb.Endpoint | ||
# Start a worker by calling: Portfolio.Worker.start_link(arg) | ||
# {Portfolio.Worker, arg} | ||
PortfolioWeb.Endpoint, | ||
{ConCache, [ | ||
name: :blog_cache, | ||
ttl_check_interval: :timer.seconds(1), | ||
global_ttl: :timer.hours(1) | ||
]} | ||
] | ||
|
||
# See https://hexdocs.pm/elixir/Supervisor.html | ||
# for other strategies and supported options | ||
opts = [strategy: :one_for_one, name: Portfolio.Supervisor] | ||
Supervisor.start_link(children, opts) | ||
end | ||
|
||
# Tell Phoenix to update the endpoint configuration | ||
# whenever the application is updated. | ||
@impl true | ||
def config_change(changed, _new, removed) do | ||
PortfolioWeb.Endpoint.config_change(changed, removed) | ||
:ok | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
defmodule Portfolio.Blog do | ||
@cache_ttl :timer.hours(1) | ||
|
||
def list_posts do | ||
case ConCache.get_or_store(:blog_cache, :posts, fn -> | ||
posts = Portfolio.Blog.Post.fetch_posts("remoterabbit", "blog-posts") | ||
%{value: posts, ttl: @cache_ttl} | ||
end) do | ||
%{value: posts} -> posts | ||
posts -> posts | ||
end | ||
end | ||
|
||
def get_post_by_slug(slug) do | ||
list_posts() | ||
|> Enum.find(&(&1.slug == slug)) | ||
end | ||
|
||
def refresh_cache do | ||
ConCache.delete(:blog_cache, :posts) | ||
list_posts() | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
defmodule Portfolio.Blog.Post do | ||
defstruct [:title, :content, :date, :slug, :description, :status] | ||
|
||
def fetch_posts(owner, repo, path \\ "posts/") do | ||
case Tentacat.Contents.find(owner, repo, path) do | ||
{200, contents, _} -> | ||
contents | ||
|> Enum.filter(&(&1["type"] == "file" && String.ends_with?(&1["name"], ".md"))) | ||
|> Enum.map(fn file -> | ||
{200, content, _} = Tentacat.Contents.find(owner, repo, file["path"]) | ||
content["content"] | ||
|> String.replace("\n", "") | ||
|> Base.decode64!() | ||
|> parse_content(file["path"]) | ||
end) | ||
|> Enum.filter(& &1.status == "published") | ||
|> Enum.sort_by(& &1.date, {:desc, Date}) | ||
|
||
{404, _, _} -> | ||
[] | ||
|
||
{status, body, _} -> | ||
IO.puts "GitHub API returned status #{status}: #{inspect(body)}" | ||
[] | ||
end | ||
end | ||
|
||
defp parse_content(content, path) do | ||
case YamlFrontMatter.parse(content) do | ||
{:ok, metadata, markdown_content} -> | ||
%__MODULE__{ | ||
title: metadata["title"], | ||
date: Date.from_iso8601!(metadata["date"]), | ||
description: metadata["description"], | ||
content: Earmark.as_html!(markdown_content), | ||
slug: Path.basename(path, ".md"), | ||
status: metadata["status"] || "published" | ||
} | ||
_ -> | ||
raise "Invalid blog post format" | ||
end | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
defmodule PortfolioWeb.PageHTML do | ||
use PortfolioWeb, :html | ||
import Phoenix.HTML.Link | ||
|
||
embed_templates "page_html/*" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,33 @@ | ||
<h1>as;dlkf</h1> | ||
<% posts = if is_map(@posts) && Map.has_key?(@posts, :value), do: @posts.value, else: @posts %> | ||
|
||
<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12"> | ||
<h1 class="text-4xl font-bold text-gray-900 mb-8">Blog Posts</h1> | ||
|
||
<div class="space-y-8"> | ||
<%= for post <- posts do %> | ||
<article class="bg-white rounded-lg shadow-md overflow-hidden hover:shadow-lg transition-shadow duration-300"> | ||
<div class="p-6"> | ||
<div class="flex items-center justify-between mb-3"> | ||
<time class="text-sm text-gray-500"> | ||
<%= Calendar.strftime(post.date, "%B %d, %Y") %> | ||
</time> | ||
</div> | ||
|
||
<h2 class="text-2xl font-semibold text-gray-900 mb-3"> | ||
<%= link post.title, to: ~p"/blog/#{post.slug}", class: "hover:text-blue-600" %> | ||
</h2> | ||
|
||
<p class="text-gray-600 mb-4"> | ||
<%= post.description %> | ||
</p> | ||
|
||
<div class="flex items-center"> | ||
<%= link "Read more →", to: ~p"/blog/#{post.slug}", | ||
class: "text-blue-600 hover:text-blue-800 font-medium" %> | ||
</div> | ||
</div> | ||
</article> | ||
<% end %> | ||
</div> | ||
</div> | ||
|
19 changes: 19 additions & 0 deletions
19
lib/portfolio_web/controllers/page_html/show_posts.html.heex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<% post = if is_map(@post) && Map.has_key?(@post, :value), do: @post.value, else: @post %> | ||
|
||
<article class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-12"> | ||
<header class="mb-8"> | ||
<time class="text-sm text-gray-500"> | ||
<%= Calendar.strftime(post.date, "%B %d, %Y") %> | ||
</time> | ||
<h1 class="text-4xl font-bold text-gray-900 mt-2"><%= post.title %></h1> | ||
</header> | ||
|
||
<div class="prose prose-lg max-w-none"> | ||
<%= raw(post.content) %> | ||
</div> | ||
|
||
<div class="mt-8"> | ||
<%= link "← Back to all posts", to: ~p"/blog", class: "text-blue-600 hover:text-blue-800" %> | ||
</div> | ||
</article> | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.