-
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.
Features: - Database and Ecto setup • Add Ecto repositories (04aea36) • Base Ecto repo setup (cdec157) • Add dev database (cbac664) - Project structure and routing • Base projects setup (a0be400, f20f705) • Update routers (33964e6) • Add projects as another controller (b31ca91) - Blog functionality • Update blog setup (bf76f16) • Setup proper blog posts and schema (e2e10f7) - Frontend enhancements • Add Tailwind typography (c27c0e4) • Tailwind node updates (9263f9e) • Add static assets (21cd893) - Performance improvements • Add cache (9de8b0b) - Development tools • Add migrations (e31a4d9) • Add packages (35d80ce) • Tests buildout (abdbd85) Bug Fixes: - Improve post rendering • Fix how posts are rendered (e7bd8a2) • Actually set HTML from Markdown (5d87f32) - Resolve sticky footer issue (6b2c8f6) - Disable robots temporarily (9f45891) Other Changes: - Add node modules to .gitignore (ab9aaf9)
- Loading branch information
1 parent
4575631
commit 3fe1dc8
Showing
53 changed files
with
2,448 additions
and
111 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
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
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
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,78 +1,73 @@ | ||
defmodule Portfolio.Blog.Post do | ||
@moduledoc """ | ||
This module defines a struct to represent a blog post and provides functions | ||
to fetch and parse blog posts from a GitHub repository. | ||
use Ecto.Schema | ||
import Ecto.Changeset | ||
|
||
## Struct Fields | ||
schema "posts" do | ||
field(:context, :string) | ||
field(:title, :string) | ||
field(:slug, :string) | ||
field(:published_at, :naive_datetime) | ||
field(:content, :string, virtual: true) | ||
field(:date, :date, virtual: true) | ||
field(:description, :string, virtual: true) | ||
field(:status, :string, virtual: true) | ||
|
||
- `title`: The title of the blog post. | ||
- `content`: The HTML content of the blog post. | ||
- `date`: The date the blog post was published. | ||
- `slug`: The slug (URL-friendly version of the title) for the blog post. | ||
- `description`: A short description of the blog post. | ||
- `status`: The status of the blog post (e.g., "published", "draft"). | ||
## Functions | ||
- `fetch_posts/2`: Fetches blog posts from a GitHub repository. | ||
- `parse_content/2`: Parses the content of a blog post file. | ||
""" | ||
defstruct [:title, :content, :date, :slug, :description, :status] | ||
|
||
@doc """ | ||
Fetches blog posts from a GitHub repository. | ||
This function retrieves the contents of the specified `path` (defaulting to "posts/") | ||
in the given `owner` and `repo`. It filters the contents to only include Markdown files, | ||
parses the content of each file, and returns a list of `%Portfolio.Blog.Post{}` structs | ||
representing the published blog posts, sorted in descending order by date. | ||
## Examples | ||
iex> Portfolio.Blog.Post.fetch_posts("owner", "repo") | ||
[%Portfolio.Blog.Post{...}, ...] | ||
timestamps() | ||
end | ||
|
||
iex> Portfolio.Blog.Post.fetch_posts("owner", "repo", "custom/path/") | ||
[%Portfolio.Blog.Post{...}, ...] | ||
@doc false | ||
def changeset(post, attrs) do | ||
post | ||
|> cast(attrs, [:title, :slug, :context, :published_at]) | ||
|> validate_required([:title, :slug, :context, :published_at]) | ||
end | ||
|
||
""" | ||
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 -> | ||
|> 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.filter(&(&1.status == "published")) | ||
|> Enum.sort_by(& &1.date, {:desc, Date}) | ||
|
||
{404, _, _} -> | ||
[] | ||
|
||
{status, body, _} -> | ||
IO.puts "GitHub API returned status #{status}: #{inspect(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} -> | ||
# Clean up any potential whitespace or formatting issues | ||
cleaned_content = | ||
markdown_content | ||
|> String.trim() | ||
|> String.replace(~r/\r\n?/, "\n") | ||
|
||
%__MODULE__{ | ||
title: metadata["title"], | ||
date: Date.from_iso8601!(metadata["date"]), | ||
description: metadata["description"], | ||
content: Earmark.as_html!(markdown_content), | ||
content: cleaned_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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
defmodule Portfolio.Projects do | ||
@moduledoc """ | ||
The Projects context. | ||
""" | ||
|
||
import Ecto.Query, warn: false | ||
alias Portfolio.Repo | ||
|
||
alias Portfolio.Projects.Project | ||
|
||
@doc """ | ||
Returns the list of projects. | ||
## Examples | ||
iex> list_projects() | ||
[%Project{}, ...] | ||
""" | ||
def list_projects do | ||
Repo.all(Project) | ||
end | ||
|
||
@doc """ | ||
Gets a single project. | ||
Raises `Ecto.NoResultsError` if the Project does not exist. | ||
## Examples | ||
iex> get_project!(123) | ||
%Project{} | ||
iex> get_project!(456) | ||
** (Ecto.NoResultsError) | ||
""" | ||
def get_project!(id), do: Repo.get!(Project, id) | ||
|
||
@doc """ | ||
Creates a project. | ||
## Examples | ||
iex> create_project(%{field: value}) | ||
{:ok, %Project{}} | ||
iex> create_project(%{field: bad_value}) | ||
{:error, %Ecto.Changeset{}} | ||
""" | ||
def create_project(attrs \\ %{}) do | ||
%Project{} | ||
|> Project.changeset(attrs) | ||
|> Repo.insert() | ||
end | ||
|
||
@doc """ | ||
Updates a project. | ||
## Examples | ||
iex> update_project(project, %{field: new_value}) | ||
{:ok, %Project{}} | ||
iex> update_project(project, %{field: bad_value}) | ||
{:error, %Ecto.Changeset{}} | ||
""" | ||
def update_project(%Project{} = project, attrs) do | ||
project | ||
|> Project.changeset(attrs) | ||
|> Repo.update() | ||
end | ||
|
||
@doc """ | ||
Deletes a project. | ||
## Examples | ||
iex> delete_project(project) | ||
{:ok, %Project{}} | ||
iex> delete_project(project) | ||
{:error, %Ecto.Changeset{}} | ||
""" | ||
def delete_project(%Project{} = project) do | ||
Repo.delete(project) | ||
end | ||
|
||
@doc """ | ||
Returns an `%Ecto.Changeset{}` for tracking project changes. | ||
## Examples | ||
iex> change_project(project) | ||
%Ecto.Changeset{data: %Project{}} | ||
""" | ||
def change_project(%Project{} = project, attrs \\ %{}) do | ||
Project.changeset(project, attrs) | ||
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,21 @@ | ||
defmodule Portfolio.Projects.Project do | ||
use Ecto.Schema | ||
import Ecto.Changeset | ||
|
||
schema "projects" do | ||
field :description, :string | ||
field :title, :string | ||
field :url, :string | ||
field :tech_stack, {:array, :string} | ||
field :featured, :boolean, default: false | ||
|
||
timestamps() | ||
end | ||
|
||
@doc false | ||
def changeset(project, attrs) do | ||
project | ||
|> cast(attrs, [:title, :description, :url, :tech_stack, :featured]) | ||
|> validate_required([:title, :description, :url, :tech_stack, :featured]) | ||
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,5 @@ | ||
defmodule Portfolio.Repo do | ||
use Ecto.Repo, | ||
otp_app: :portfolio, | ||
adapter: Ecto.Adapters.Postgres | ||
end |
Oops, something went wrong.