diff options
-rw-r--r-- | app/assets/stylesheets/main/entries.scss | 43 | ||||
-rw-r--r-- | app/controllers/blogs_controller.rb | 11 | ||||
-rw-r--r-- | app/controllers/streams_controller.rb | 4 | ||||
-rw-r--r-- | app/helpers/application_helper.rb | 11 | ||||
-rw-r--r-- | app/models/stream.rb | 11 | ||||
-rw-r--r-- | app/models/update.rb | 8 | ||||
-rw-r--r-- | app/views/streams/_stream.html.haml | 6 | ||||
-rw-r--r-- | app/views/streams/index.html.haml | 19 | ||||
-rw-r--r-- | app/views/streams/show.html.haml | 2 | ||||
-rw-r--r-- | config/routes.rb | 1 | ||||
-rw-r--r-- | db/migrate/20250512181245_add_latest_post_at_to_stream.rb | 21 | ||||
-rw-r--r-- | db/schema.rb | 3 |
12 files changed, 126 insertions, 14 deletions
diff --git a/app/assets/stylesheets/main/entries.scss b/app/assets/stylesheets/main/entries.scss index 6ccaf7e..d67ae67 100644 --- a/app/assets/stylesheets/main/entries.scss +++ b/app/assets/stylesheets/main/entries.scss | |||
@@ -472,3 +472,46 @@ | |||
472 | .next-post { | 472 | .next-post { |
473 | float: right; | 473 | float: right; |
474 | } | 474 | } |
475 | |||
476 | #streams-index { | ||
477 | width: 100%; | ||
478 | border-collapse: collapse; | ||
479 | |||
480 | #streams-index-header-row { | ||
481 | th { | ||
482 | background-color: #bdbdbd; | ||
483 | padding-left: 0.5em; | ||
484 | border-top: 1px solid #848484; | ||
485 | border-bottom: 1px solid #848484; | ||
486 | } | ||
487 | } | ||
488 | |||
489 | th { | ||
490 | padding-bottom: 0.5em; | ||
491 | padding-top: 0.5em; | ||
492 | text-align: left; | ||
493 | } | ||
494 | |||
495 | td { | ||
496 | padding-top: 1em; | ||
497 | padding-left: 0.5em; | ||
498 | |||
499 | time { | ||
500 | font-size: .75em; | ||
501 | } | ||
502 | |||
503 | .stream-link { | ||
504 | font-weight: bold; | ||
505 | text-decoration: none; | ||
506 | |||
507 | &, &:visited { | ||
508 | color: #ee2c2c; | ||
509 | } | ||
510 | |||
511 | &:hover { | ||
512 | text-decoration: underline; | ||
513 | color: #9ea1ad; | ||
514 | } | ||
515 | } | ||
516 | } | ||
517 | } | ||
diff --git a/app/controllers/blogs_controller.rb b/app/controllers/blogs_controller.rb index 4f6d9ce..6e80754 100644 --- a/app/controllers/blogs_controller.rb +++ b/app/controllers/blogs_controller.rb | |||
@@ -1,12 +1,7 @@ | |||
1 | require 'redcarpet/render_strip' | ||
2 | 1 | ||
3 | class StrippedSummary < Redcarpet::Render::StripDown | ||
4 | def block_html(raw_html) | ||
5 | nil | ||
6 | end | ||
7 | end | ||
8 | 2 | ||
9 | class BlogsController < ApplicationController | 3 | class BlogsController < ApplicationController |
4 | include ApplicationHelper | ||
10 | 5 | ||
11 | def summary | 6 | def summary |
12 | @blogs = Blog.where(published: true).order(published_at: :desc).paginate(page: params[:page], per_page: 10) | 7 | @blogs = Blog.where(published: true).order(published_at: :desc).paginate(page: params[:page], per_page: 10) |
@@ -33,12 +28,12 @@ class BlogsController < ApplicationController | |||
33 | @prev = @blog.prev | 28 | @prev = @blog.prev |
34 | @next = @blog.next | 29 | @next = @blog.next |
35 | 30 | ||
36 | body = Redcarpet::Markdown.new(StrippedSummary).render(@blog.body) | 31 | body = stripped_markdown(@blog.body) |
37 | 32 | ||
38 | set_meta_tags(og: { | 33 | set_meta_tags(og: { |
39 | title: @blog.title, | 34 | title: @blog.title, |
40 | type: "article", | 35 | type: "article", |
41 | description: (body.length <= 300 ? body : body[0..299]), | 36 | description: body[0, 299], |
42 | url: blog_url(@blog, host: "www.fourisland.com"), | 37 | url: blog_url(@blog, host: "www.fourisland.com"), |
43 | article: { | 38 | article: { |
44 | published_time: @blog.published_at.iso8601, | 39 | published_time: @blog.published_at.iso8601, |
diff --git a/app/controllers/streams_controller.rb b/app/controllers/streams_controller.rb index 9b7588c..aa81ab1 100644 --- a/app/controllers/streams_controller.rb +++ b/app/controllers/streams_controller.rb | |||
@@ -1,5 +1,9 @@ | |||
1 | class StreamsController < ApplicationController | 1 | class StreamsController < ApplicationController |
2 | 2 | ||
3 | def index | ||
4 | @streams = Stream.order(latest_post_at: :desc).paginate(page: params[:page], per_page: 10) | ||
5 | end | ||
6 | |||
3 | def show | 7 | def show |
4 | @stream = Stream.find_by_slug(params[:slug]) | 8 | @stream = Stream.find_by_slug(params[:slug]) |
5 | @updates = @stream.updates.paginate(page: params[:page], per_page: 10) | 9 | @updates = @stream.updates.paginate(page: params[:page], per_page: 10) |
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 97a897f..a51f1a1 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb | |||
@@ -1,6 +1,7 @@ | |||
1 | require 'redcarpet' | 1 | require 'redcarpet' |
2 | require 'rouge' | 2 | require 'rouge' |
3 | require 'rouge/plugins/redcarpet' | 3 | require 'rouge/plugins/redcarpet' |
4 | require 'redcarpet/render_strip' | ||
4 | 5 | ||
5 | module ApplicationHelper | 6 | module ApplicationHelper |
6 | 7 | ||
@@ -45,4 +46,14 @@ module ApplicationHelper | |||
45 | ] | 46 | ] |
46 | end | 47 | end |
47 | 48 | ||
49 | class StrippedSummary < Redcarpet::Render::StripDown | ||
50 | def block_html(raw_html) | ||
51 | nil | ||
52 | end | ||
53 | end | ||
54 | |||
55 | def stripped_markdown(text) | ||
56 | Redcarpet::Markdown.new(StrippedSummary).render(text) | ||
57 | end | ||
58 | |||
48 | end | 59 | end |
diff --git a/app/models/stream.rb b/app/models/stream.rb index 0773143..6a738e2 100644 --- a/app/models/stream.rb +++ b/app/models/stream.rb | |||
@@ -8,11 +8,22 @@ class Stream < ApplicationRecord | |||
8 | validates :title, presence: true | 8 | validates :title, presence: true |
9 | validates :slug, presence: true, format: /\A[-a-z0-9]+\z/ | 9 | validates :slug, presence: true, format: /\A[-a-z0-9]+\z/ |
10 | 10 | ||
11 | before_create :set_post_timestamp | ||
12 | |||
11 | def path | 13 | def path |
12 | "/thinks/#{slug}" | 14 | "/thinks/#{slug}" |
13 | end | 15 | end |
14 | 16 | ||
17 | def to_param | ||
18 | slug | ||
19 | end | ||
20 | |||
15 | def taggable | 21 | def taggable |
16 | self | 22 | self |
17 | end | 23 | end |
24 | |||
25 | private | ||
26 | def set_post_timestamp | ||
27 | self.latest_post_at = self.created_at | ||
28 | end | ||
18 | end | 29 | end |
diff --git a/app/models/update.rb b/app/models/update.rb index 01907d8..a98a5d4 100644 --- a/app/models/update.rb +++ b/app/models/update.rb | |||
@@ -5,6 +5,8 @@ class Update < ApplicationRecord | |||
5 | 5 | ||
6 | validates :stream, :body, presence: true | 6 | validates :stream, :body, presence: true |
7 | 7 | ||
8 | after_create :set_latest_timestamp | ||
9 | |||
8 | def path | 10 | def path |
9 | "/thinks/#{stream.slug}\#update-#{id}" | 11 | "/thinks/#{stream.slug}\#update-#{id}" |
10 | end | 12 | end |
@@ -12,4 +14,10 @@ class Update < ApplicationRecord | |||
12 | def taggable | 14 | def taggable |
13 | stream | 15 | stream |
14 | end | 16 | end |
17 | |||
18 | private | ||
19 | def set_latest_timestamp | ||
20 | self.stream.latest_post_at = self.created_at | ||
21 | self.stream.save! | ||
22 | end | ||
15 | end | 23 | end |
diff --git a/app/views/streams/_stream.html.haml b/app/views/streams/_stream.html.haml index 4a6b1e9..97d4813 100644 --- a/app/views/streams/_stream.html.haml +++ b/app/views/streams/_stream.html.haml | |||
@@ -2,9 +2,7 @@ | |||
2 | %h2#stream-title= stream.title | 2 | %h2#stream-title= stream.title |
3 | - unless stream.body.blank? | 3 | - unless stream.body.blank? |
4 | %header#stream-intro.entry-content= markdown(stream.body) | 4 | %header#stream-intro.entry-content= markdown(stream.body) |
5 | - if stream.updates.size > 10 | 5 | = will_paginate @updates |
6 | = will_paginate @updates | ||
7 | - unless @updates.empty? | 6 | - unless @updates.empty? |
8 | = render @updates | 7 | = render @updates |
9 | - if stream.updates.size > 10 | 8 | = will_paginate @updates |
10 | = will_paginate @updates | ||
diff --git a/app/views/streams/index.html.haml b/app/views/streams/index.html.haml new file mode 100644 index 0000000..bf5073f --- /dev/null +++ b/app/views/streams/index.html.haml | |||
@@ -0,0 +1,19 @@ | |||
1 | %table#streams-index | ||
2 | %tr#streams-index-header-row | ||
3 | %th Stream Topic | ||
4 | %th Updates | ||
5 | %th Last Post | ||
6 | - @streams.each do |stream| | ||
7 | %tr | ||
8 | %td | ||
9 | = link_to stream.title, stream, class: "stream-link" | ||
10 | %br | ||
11 | %time= stream.created_at.strftime("%B #{stream.created_at.day.ordinalize}, %Y at %-I:%M:%S%P") | ||
12 | %td= stream.updates.size | ||
13 | %td | ||
14 | - unless stream.updates.empty? | ||
15 | - latest_post = stream.updates.order(created_at: :desc).first | ||
16 | = link_to (stripped_markdown(latest_post.body)[0, 30] + "..."), stream | ||
17 | %br | ||
18 | %time= latest_post.created_at.strftime("%B #{latest_post.created_at.day.ordinalize}, %Y at %-I:%M:%S%P") | ||
19 | = will_paginate @streams | ||
diff --git a/app/views/streams/show.html.haml b/app/views/streams/show.html.haml index 8365556..8d58f62 100644 --- a/app/views/streams/show.html.haml +++ b/app/views/streams/show.html.haml | |||
@@ -1,3 +1,3 @@ | |||
1 | - title @stream.title | 1 | - title @stream.title |
2 | .breadcrumb= link_to "← Back to home page", root_path | 2 | .breadcrumb= link_to "← Back to streams", streams_path |
3 | = render @stream | 3 | = render @stream |
diff --git a/config/routes.rb b/config/routes.rb index 9e62ebb..ad66501 100644 --- a/config/routes.rb +++ b/config/routes.rb | |||
@@ -56,6 +56,7 @@ Rails.application.routes.draw do | |||
56 | end | 56 | end |
57 | end | 57 | end |
58 | 58 | ||
59 | get 'thinks', to: 'streams#index', as: :streams | ||
59 | get 'thinks/:slug', to: 'streams#show', as: :stream | 60 | get 'thinks/:slug', to: 'streams#show', as: :stream |
60 | 61 | ||
61 | get 'plays', to: 'games#index' | 62 | get 'plays', to: 'games#index' |
diff --git a/db/migrate/20250512181245_add_latest_post_at_to_stream.rb b/db/migrate/20250512181245_add_latest_post_at_to_stream.rb new file mode 100644 index 0000000..9d753e3 --- /dev/null +++ b/db/migrate/20250512181245_add_latest_post_at_to_stream.rb | |||
@@ -0,0 +1,21 @@ | |||
1 | class AddLatestPostAtToStream < ActiveRecord::Migration[7.1] | ||
2 | def up | ||
3 | add_column :streams, :latest_post_at, :datetime | ||
4 | |||
5 | Stream.all.each do |stream| | ||
6 | if stream.updates.empty? | ||
7 | stream.latest_post_at = stream.created_at | ||
8 | else | ||
9 | stream.latest_post_at = stream.updates.order(created_at: :desc).first.created_at | ||
10 | end | ||
11 | |||
12 | stream.save! | ||
13 | end | ||
14 | |||
15 | change_column_null :streams, :latest_post_at, false | ||
16 | end | ||
17 | |||
18 | def down | ||
19 | remove_column :streams, :latest_post_at, :datetime | ||
20 | end | ||
21 | end | ||
diff --git a/db/schema.rb b/db/schema.rb index 795a986..76e9ad8 100644 --- a/db/schema.rb +++ b/db/schema.rb | |||
@@ -10,7 +10,7 @@ | |||
10 | # | 10 | # |
11 | # It's strongly recommended that you check this file into your version control system. | 11 | # It's strongly recommended that you check this file into your version control system. |
12 | 12 | ||
13 | ActiveRecord::Schema[7.1].define(version: 2025_01_12_025207) do | 13 | ActiveRecord::Schema[7.1].define(version: 2025_05_12_181245) do |
14 | create_table "active_storage_attachments", force: :cascade do |t| | 14 | create_table "active_storage_attachments", force: :cascade do |t| |
15 | t.string "name", null: false | 15 | t.string "name", null: false |
16 | t.string "record_type", null: false | 16 | t.string "record_type", null: false |
@@ -358,6 +358,7 @@ ActiveRecord::Schema[7.1].define(version: 2025_01_12_025207) do | |||
358 | t.string "slug" | 358 | t.string "slug" |
359 | t.datetime "created_at", precision: nil, null: false | 359 | t.datetime "created_at", precision: nil, null: false |
360 | t.datetime "updated_at", precision: nil, null: false | 360 | t.datetime "updated_at", precision: nil, null: false |
361 | t.datetime "latest_post_at", null: false | ||
361 | end | 362 | end |
362 | 363 | ||
363 | create_table "taggings", force: :cascade do |t| | 364 | create_table "taggings", force: :cascade do |t| |