Switch to markdown-backed project files

This commit is contained in:
Max Wofford 2025-05-07 22:03:59 -04:00
parent b04962bb04
commit 7f92bb49ad
11 changed files with 249 additions and 79 deletions

View file

@ -1,4 +0,0 @@
class MarkdownProjectsController < ApplicationController
def index
end
end

View file

@ -1,49 +1,83 @@
class ProjectsController < ApplicationController
before_action :set_project, only: %i[ show edit update ]
before_action :require_authentication, only: [:show, :edit, :update]
require 'yaml'
require 'redcarpet'
def index
@projects = Project.all
end
def show
@project = Project.find(params[:repo], params[:project_name])
render_not_found unless @project
end
def new
@project = Project.new
end
def create
@project = Project.new(project_params)
@project.user = current_user
if @project.save
redirect_to @project
private
def load_projects
projects = []
Dir.glob(Rails.root.join('content/projects/*/*/journal.md')).each do |file|
content = File.read(file)
metadata, _ = parse_frontmatter(content)
# Extract repo and project name from path
path_parts = file.split('/')
repo = path_parts[-3]
project_name = path_parts[-2]
projects << {
repo: repo,
project_name: project_name,
title: metadata['title'],
author: metadata['author'],
description: metadata['description'],
created_at: metadata['created_at']
}
end
projects.sort_by { |p| p[:created_at] }.reverse
end
def load_project(repo, project_name)
file_path = Rails.root.join('content/projects', repo, project_name, 'journal.md')
return nil unless File.exist?(file_path)
content = File.read(file_path)
metadata, markdown_content = parse_frontmatter(content)
{
repo: repo,
project_name: project_name,
title: metadata['title'],
author: metadata['author'],
description: metadata['description'],
created_at: metadata['created_at'],
content: render_markdown(markdown_content)
}
end
def parse_frontmatter(content)
if content =~ /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m
metadata = YAML.safe_load($1)
content = content[$2.size..-1]
[metadata, content]
else
render :new, status: :unprocessable_entity
[{}, content]
end
end
def edit
def render_markdown(content)
markdown = Redcarpet::Markdown.new(
Redcarpet::Render::HTML,
autolink: true,
tables: true,
fenced_code_blocks: true
)
markdown.render(content)
end
def update
if @project.update(project_params)
redirect_to @project, notice: "Project was successfully updated."
else
render :edit, status: :unprocessable_entity
end
def render_not_found
render file: "#{Rails.root}/public/404.html", status: :not_found
end
private
def set_project
@project = Project.find(params[:id])
end
def project_params
params.expect(project: [ :github_repo, :kitted_guide, :proposed_tier, :proposed_tier_explanation, :group_project, :name ])
end
end

View file

@ -1,14 +1,94 @@
class Project < ApplicationRecord
belongs_to :user
has_many :posts, dependent: :destroy
class Project
attr_reader :repo, :project_name, :title, :author, :description, :created_at, :content
def initialize(attributes = {})
@repo = attributes[:repo]
@project_name = attributes[:project_name]
@title = attributes[:title]
@author = attributes[:author]
@description = attributes[:description]
@created_at = attributes[:created_at]
@content = attributes[:content]
end
def name
title
end
def github_slug
return unless github_repo
segments = github_repo.split("/")
segments.last(2).join("/")
"#{repo}/#{project_name}"
end
def hours
posts.sum(:hours)
def github_repo
"https://github.com/#{github_slug}"
end
def created_at_date
Date.parse(created_at)
end
def formatted_created_at
created_at_date.strftime("%B %d, %Y")
end
def self.all
Dir.glob(Rails.root.join('content/projects/*/*/journal.md')).map do |file|
content = File.read(file)
metadata, _ = parse_frontmatter(content)
# Extract repo and project name from path
path_parts = file.split('/')
repo = path_parts[-3]
project_name = path_parts[-2]
new(
repo: repo,
project_name: project_name,
title: metadata['title'],
author: metadata['author'],
description: metadata['description'],
created_at: metadata['created_at']
)
end.sort_by(&:created_at_date).reverse
end
def self.find(repo, project_name)
file_path = Rails.root.join('content/projects', repo, project_name, 'journal.md')
return nil unless File.exist?(file_path)
content = File.read(file_path)
metadata, markdown_content = parse_frontmatter(content)
new(
repo: repo,
project_name: project_name,
title: metadata['title'],
author: metadata['author'],
description: metadata['description'],
created_at: metadata['created_at'],
content: render_markdown(markdown_content)
)
end
private
def self.parse_frontmatter(content)
if content =~ /\A(---\s*\n.*?\n?)^(---\s*$\n?)/m
metadata = YAML.safe_load($1)
content = content[$2.size..-1]
[metadata, content]
else
[{}, content]
end
end
def self.render_markdown(content)
markdown = Redcarpet::Markdown.new(
Redcarpet::Render::HTML,
autolink: true,
tables: true,
fenced_code_blocks: true
)
markdown.render(content)
end
end

View file

@ -1,4 +0,0 @@
whi
# Hello world
_by acorn_

View file

@ -1,11 +1,7 @@
<%# locals: (project:) %>
<h1 class="text-2xl mb-4"><%= project.name %></h1>
<%= link_to "View on GitHub", project.github_repo, class: "bg-[#96ABF9] text-white px-4 py-2 rounded hover:opacity-80 transition duration-200" %>
<h1 class="text-2xl mb-4"><%= project.name %></h1>
<%= link_to "View on GitHub", project.github_repo, class: "bg-[#96ABF9] text-white px-4 py-2 rounded hover:opacity-80 transition duration-200" %>
<% if project.user == current_user %>
<div class="flex flex-wrap my-4 gap-4 items-center">
<%= link_to "New Post", new_post_path(project: project), class: "bg-[#62D5C3] text-white px-4 py-2 rounded hover:opacity-80 transition duration-200" %>
<div class="flex flex-wrap my-4 gap-4 items-center">
<%= link_to "New Post", new_post_path(project: project), class: "bg-[#62D5C3] text-white px-4 py-2 rounded hover:opacity-80 transition duration-200" %>
<div class="opacity-70 hover:opacity-100 transition duration-100"><%= link_to "Edit", edit_project_path(project) %></div>
</div>
<% end %>
</div>

View file

@ -1,19 +1,12 @@
<p class="text-3xl font-bold">My projects:</p>
<div class="grid md:grid-cols-3 gap-4 mt-4 sm:grid-cols-2 grid-cols-1">
<%= link_to new_project_path, class: "bg-opacity-70 hover:bg-opacity-100 transition duration-100 bg-[#00D8C3] rounded-lg font-bold h-full justify-center text-center items-center p-4 text-xl flex flex-col leading-none" do %>
<span>Create new project</span>
<span class="text-6xl">+</span>
<% end %>
<% @projects.each do |project| %>
<%= link_to project_path(project), class: "block bg-[#2E2A54] max-w-4xl py-8 px-8 rounded-lg text-white hover:bg-[#3A3A6D] transition duration-100" do %>
<%= link_to project_path(repo: project.repo, project_name: project.project_name), class: "block bg-[#2E2A54] max-w-4xl py-8 px-8 rounded-lg text-white hover:bg-[#3A3A6D] transition duration-100" do %>
<h1 class="text-2xl"><%= project.name %> <span class="text-base text-[#96ABF9]">(<%= project.github_slug %>)</span></h1>
<p class="mb-2">created by <span class="text-[#96ABF9]">[<%= "foo" %>]</span> </p>
<p class="opacity-70"><%= project.hours %> hours</p>
<p class="mb-2">created by <span class="text-[#96ABF9]">[<%= project.author %>]</span></p>
<p class="opacity-70"><%= project.description %></p>
<p class="opacity-70 mt-2">Started on <%= project.formatted_created_at %></p>
<% end %>
<% end %>
</div>

View file

@ -2,19 +2,12 @@
<%= render partial: "header", locals: { project: @project } %>
<div class="grid grid-cols-1 gap-4">
<% @project.posts.each do |post| %>
<%= link_to post_path(post), class: "block bg-[#2E2A54] max-w-4xl p-4 px-8 rounded-lg text-white hover:bg-[#3A3A6D] transition duration-100" do %>
<p class="mb-2">posted by <span class="text-[#96ABF9]">[name]</span> <span class="opacity-50">// <%= time_ago_in_words(post.created_at) %> ago // <%= pluralize(post.hours, "hour") %> spent on </span> <span class="text-[#96ABF9]">[project]</span></p>
<p class="text-xl font-bold mb-2"><%= post.name %></p>
<div class="opacity-70"><%= post.description %></div>
<% end %>
<% end %>
<div class="prose prose-invert max-w-none mt-8">
<%= @project.content.html_safe %>
</div>
<% if current_user.admin? %>
<details>
<% if current_user&.admin? %>
<details class="mt-8">
<summary class="text-[#96ABF9] cursor-pointer">Project Details</summary>
<%= (ap @project).html_safe %>
</details>

View file

@ -20,5 +20,7 @@
</div>
<%= link_to "@#{current_user.username}", user_path(current_user), class: "#{current_page?(user_path(current_user)) || current_page?(edit_user_path(current_user)) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 transition duration-100 block" %>
<% if current_user %>
<%= link_to "@#{current_user.username}", user_path(current_user), class: "#{current_page?(user_path(current_user)) || current_page?(edit_user_path(current_user)) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 transition duration-100 block" %>
<% end %>
</div>

View file

@ -13,7 +13,8 @@ Rails.application.routes.draw do
root "landing#index"
resources :posts
resources :users
resources :projects
get '/projects', to: 'projects#index'
get '/projects/:repo/:project_name', to: 'projects#show', as: :project
get "/markdown", to: "markdown_projects#index"
@ -53,5 +54,4 @@ Rails.application.routes.draw do
get '/prize_box', to: 'users#prize_box', as: :prize_box
end

View file

@ -0,0 +1,78 @@
---
title: "Highway - A Modern Web Development Framework"
author: "Max Wofford"
description: "A framework for building modern web applications with a focus on developer experience and performance"
created_at: "2024-03-20"
---
<!-- This is an AI generaated example file to test markdown rendering -->
# Highway - A Modern Web Development Framework
Highway is a framework designed to make web development more accessible and enjoyable. Built with modern best practices in mind, it provides a streamlined development experience while maintaining flexibility and power.
## Key Features
- **Modern Architecture**: Built on top of Rails 8, leveraging the latest web technologies
- **Developer Experience**: Hot reloading, intuitive APIs, and comprehensive documentation
- **Performance First**: Optimized for speed and efficiency out of the box
- **Extensible**: Easy to customize and extend with plugins and middleware
## Getting Started
1. Clone the repository:
```bash
git clone https://github.com/hackclub/highway.git
cd highway
```
2. Install dependencies:
```bash
bundle install
```
3. Start the development server:
```bash
bin/dev
```
## Project Structure
```
highway/
├── app/
│ ├── controllers/
│ ├── models/
│ └── views/
├── config/
├── content/
│ └── projects/
└── public/
```
## Development Progress
### Week 1
- Set up basic project structure
- Implemented core routing system
- Added basic authentication
### Week 2
- Built project documentation system
- Implemented markdown rendering
- Added project submission workflow
## Next Steps
- [ ] Add more comprehensive testing
- [ ] Improve documentation
- [ ] Add more example projects
- [ ] Implement CI/CD pipeline
## Contributing
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for more details.
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

2
submissions.yml Normal file
View file

@ -0,0 +1,2 @@
projects:
- "https://github.com/Dongathan-Jong/SpotifyDisplay"