diff --git a/app/repos/trip_repo.rb b/app/repos/trip_repo.rb index a175450..6192ab6 100644 --- a/app/repos/trip_repo.rb +++ b/app/repos/trip_repo.rb @@ -10,6 +10,7 @@ module Adamantium def list trips + .combine(:posts) .order(:start_date) .to_a end diff --git a/app/templates/shared/_compact_post.html.slim b/app/templates/shared/_compact_post.html.slim index 8778b08..c3bdffd 100644 --- a/app/templates/shared/_compact_post.html.slim +++ b/app/templates/shared/_compact_post.html.slim @@ -1,11 +1,13 @@ -div class="mb-2 h-entry" +div class="mb-2 h-entry relative" - if !first - div class="rounded-full bg-orange-100 p-2 w-1 h-4 inline-block mb-2 dark:bg-orange-400" + div class="-top-4 absolute rounded-full border-2 bg-orange-100 border-orange-200 p-1 w-1 h-2 inline-block dark:border-orange-400 dark:bg-orange-400" - if first - div class="w-2 h-2 inline-block mb-6" - = "🛬" + div class="inline-block mb-2" + span class="mr-2" + = "🛬" + = trip.start_date - div class="ml-[7] pl-6 border-solid border-l-2 border-orange-100 dark:border-orange-400" + div class="ml-[5] #{ last ? '' : 'mb-[20]'} pl-6 border-solid border-l-2 border-orange-200 dark:border-orange-400" h3 class="text-xl font-semibold text-blue-600" a class="border-b-2 border-transparent hover:border-blue-600 hover:border-b-2" href="/post/#{post.slug}" = post.name @@ -20,5 +22,7 @@ div class="mb-2 h-entry" time class="dt-published" datetime=post.machine_published_at = post.display_published_at - if last - div class="w-2 h-2 inline-block mb-6" - = "🛫" \ No newline at end of file + div class="inline-block mb-6" + span class="mr-2" + = "🛫" + = trip.end_date \ No newline at end of file diff --git a/app/templates/trips/index.html.slim b/app/templates/trips/index.html.slim index 1471d63..4c5d568 100644 --- a/app/templates/trips/index.html.slim +++ b/app/templates/trips/index.html.slim @@ -1,15 +1,24 @@ div class="mb-4 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200" h1 Trips -div class="h-feed mb-12 max-w-prose mx-auto" - - trips.each do |trip| - div class="mb-8 h-entry" - h3 class="text-xl font-semibold text-blue-600 mb-2" - a class="border-b-2 border-transparent hover:border-blue-600 hover:border-b-2" href="/trips/#{trip.id}" - = trip.name - p class="text-sm text-blue-400" - a class="u-url" href="/trips/#{trip.id}" - = "#{trip.start_date} - #{trip.end_date}" - + div class="mb-12 max-w-prose mx-auto" + table class="prose dark:prose-invert table-auto" + - trip_years.each do |year, trips| + thead + tr colspan=4 + td class="text-xl" = year + - trips.each do |trip| + tr + td + a href="/trips/#{trip.id}" + = trip.name + td + = trip.subtitle + td + = "#{trip.posts.count} entries" + td class="text-right text-gray-400 dark:text-gray-600" + = "#{trip.start_date}" + == " → " + = "#{trip.end_date}" div class="max-w-screen-md mx-auto border-t-4 border-solid border-gray-400 dark:border-gray-600" diff --git a/app/templates/trips/show.html.slim b/app/templates/trips/show.html.slim index c15aa39..e058a3d 100644 --- a/app/templates/trips/show.html.slim +++ b/app/templates/trips/show.html.slim @@ -1,9 +1,9 @@ div class="mb-4 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200" h1 class="mb-0" #{trip.name} - p class="mt-2" class="text-gray-600 dark:text-gray-200 text-sm" (#{trip.start_date} - #{trip.end_date}) + / p class="mt-2" class="text-gray-600 dark:text-gray-200 text-sm" (#{trip.start_date} - #{trip.end_date}) div class="h-feed mb-12 max-w-prose mx-auto" - posts.each do |post| - == render "shared/compact_post", post: post, first: post.id == posts.first.id, last: post.id == posts.last.id + == render "shared/compact_post", post: post, trip: trip, first: post.id == posts.first.id, last: post.id == posts.last.id div class="max-w-screen-md mx-auto border-t-4 border-solid border-gray-400 dark:border-gray-600" diff --git a/app/views/trips/index.rb b/app/views/trips/index.rb index e773b3b..4452c4c 100644 --- a/app/views/trips/index.rb +++ b/app/views/trips/index.rb @@ -4,8 +4,10 @@ module Adamantium class Index < View include Deps["repos.trip_repo"] - expose :trips do - trip_repo.list + expose :trip_years do + trip_repo + .list + .group_by { |trip| trip.start_date.year } end end end diff --git a/config/routes.rb b/config/routes.rb index 8089ee2..44389c7 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -90,6 +90,7 @@ module Adamantium post "/trips", to: "trips.create" post "/trips/add_post", to: "trips.add_post" get "/trips/new", to: "trips.new" + post "/trips/:id", to: "trips.update" end end end diff --git a/db/migrate/20230510095407_add_subtitle_to_trips.rb b/db/migrate/20230510095407_add_subtitle_to_trips.rb new file mode 100644 index 0000000..53df6af --- /dev/null +++ b/db/migrate/20230510095407_add_subtitle_to_trips.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +ROM::SQL.migration do + change do + alter_table :trips do + add_column :subtitle, :text + end + end +end diff --git a/public/assets/index.css b/public/assets/index.css index fc8bea8..8b706d2 100644 --- a/public/assets/index.css +++ b/public/assets/index.css @@ -974,6 +974,22 @@ video { margin-bottom: 0; } +.absolute { + position: absolute; +} + +.relative { + position: relative; +} + +.-top-4 { + top: -1rem; +} + +.-top-2 { + top: -0.5rem; +} + .col-span-1 { grid-column: span 1 / span 1; } @@ -1036,10 +1052,6 @@ video { margin-bottom: 2rem; } -.ml-\[7\] { - margin-left: 7; -} - .mr-1 { margin-right: 0.25rem; } @@ -1064,10 +1076,6 @@ video { margin-top: 0.125rem; } -.mt-2 { - margin-top: 0.5rem; -} - .mt-4 { margin-top: 1rem; } @@ -1076,6 +1084,118 @@ video { margin-top: 1.5rem; } +.mt-2 { + margin-top: 0.5rem; +} + +.ml-4 { + margin-left: 1rem; +} + +.ml-8 { + margin-left: 2rem; +} + +.ml-2 { + margin-left: 0.5rem; +} + +.ml-1 { + margin-left: 0.25rem; +} + +.mb-1 { + margin-bottom: 0.25rem; +} + +.ml-3 { + margin-left: 0.75rem; +} + +.ml-1\.5 { + margin-left: 0.375rem; +} + +.ml-2\.5 { + margin-left: 0.625rem; +} + +.ml-\[2\.15\] { + margin-left: 2.15; +} + +.ml-\[2\.25\] { + margin-left: 2.25; +} + +.ml-\[2\.5\] { + margin-left: 2.5; +} + +.ml-\[3\.5\] { + margin-left: 3.5; +} + +.ml-\[4\.5\] { + margin-left: 4.5; +} + +.ml-\[6\.5\] { + margin-left: 6.5; +} + +.ml-\[6\] { + margin-left: 6; +} + +.ml-\[6\.25\] { + margin-left: 6.25; +} + +.ml-\[6\.75\] { + margin-left: 6.75; +} + +.ml-\[7\] { + margin-left: 7; +} + +.mt-8 { + margin-top: 2rem; +} + +.ml-\[8\] { + margin-left: 8; +} + +.ml-\[4\] { + margin-left: 4; +} + +.ml-\[5\] { + margin-left: 5; +} + +.mb-5 { + margin-bottom: 1.25rem; +} + +.mb-\[8\] { + margin-bottom: 8; +} + +.mb-\[12\] { + margin-bottom: 12; +} + +.mb-\[22\] { + margin-bottom: 22; +} + +.mb-\[20\] { + margin-bottom: 20; +} + .block { display: block; } @@ -1108,14 +1228,6 @@ video { height: 4rem; } -.h-2 { - height: 0.5rem; -} - -.h-4 { - height: 1rem; -} - .h-44 { height: 11rem; } @@ -1124,12 +1236,24 @@ video { height: 12rem; } -.max-h-12 { - max-height: 3rem; +.h-2 { + height: 0.5rem; } -.w-1 { - width: 0.25rem; +.h-4 { + height: 1rem; +} + +.h-1 { + height: 0.25rem; +} + +.h-8 { + height: 2rem; +} + +.max-h-12 { + max-height: 3rem; } .w-16 { @@ -1160,6 +1284,18 @@ video { width: 1.5rem; } +.w-3 { + width: 0.75rem; +} + +.w-1 { + width: 0.25rem; +} + +.w-8 { + width: 2rem; +} + .max-w-prose { max-width: 65ch; } @@ -1279,12 +1415,16 @@ video { border-bottom-width: 2px; } +.border-t-4 { + border-top-width: 4px; +} + .border-l-2 { border-left-width: 2px; } -.border-t-4 { - border-top-width: 4px; +.border-l-4 { + border-left-width: 4px; } .border-solid { @@ -1306,13 +1446,23 @@ video { border-color: rgb(217 249 157 / var(--tw-border-opacity)); } +.border-transparent { + border-color: transparent; +} + +.border-blue-100 { + --tw-border-opacity: 1; + border-color: rgb(219 234 254 / var(--tw-border-opacity)); +} + .border-orange-100 { --tw-border-opacity: 1; border-color: rgb(255 237 213 / var(--tw-border-opacity)); } -.border-transparent { - border-color: transparent; +.border-orange-200 { + --tw-border-opacity: 1; + border-color: rgb(254 215 170 / var(--tw-border-opacity)); } .bg-blue-100 { @@ -1345,11 +1495,6 @@ video { background-color: rgb(190 242 100 / var(--tw-bg-opacity)); } -.bg-orange-100 { - --tw-bg-opacity: 1; - background-color: rgb(255 237 213 / var(--tw-bg-opacity)); -} - .bg-pink-100 { --tw-bg-opacity: 1; background-color: rgb(252 231 243 / var(--tw-bg-opacity)); @@ -1364,6 +1509,16 @@ video { background-color: rgb(254 249 195 / 0.6); } +.bg-green-100 { + --tw-bg-opacity: 1; + background-color: rgb(220 252 231 / var(--tw-bg-opacity)); +} + +.bg-orange-100 { + --tw-bg-opacity: 1; + background-color: rgb(255 237 213 / var(--tw-bg-opacity)); +} + .fill-blue-100 { fill: #dbeafe; } @@ -1389,6 +1544,26 @@ video { padding: 0.5rem; } +.p-4 { + padding: 1rem; +} + +.p-\[1\.5\] { + padding: 1.5; +} + +.p-\[2\.5\] { + padding: 2.5; +} + +.p-\[3\.5\] { + padding: 3.5; +} + +.p-\[6\.5\] { + padding: 6.5; +} + .px-1 { padding-left: 0.25rem; padding-right: 0.25rem; @@ -1417,12 +1592,20 @@ video { padding-bottom: 2rem; } +.pt-4 { + padding-top: 1rem; +} + +.pl-8 { + padding-left: 2rem; +} + .pl-6 { padding-left: 1.5rem; } -.pt-4 { - padding-top: 1rem; +.pl-4 { + padding-left: 1rem; } .text-left { @@ -1461,6 +1644,10 @@ video { font-size: 0.75rem; } +.text-2xl { + font-size: 1.563rem; +} + .font-bold { font-weight: 700; } @@ -1684,6 +1871,11 @@ h1, h2, h3, h4, h5, h6, h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { border-color: rgb(30 64 175 / var(--tw-border-opacity)); } +.hover\:border-orange-600:hover { + --tw-border-opacity: 1; + border-color: rgb(234 88 12 / var(--tw-border-opacity)); +} + .hover\:bg-blue-100:hover { --tw-bg-opacity: 1; background-color: rgb(219 234 254 / var(--tw-bg-opacity)); @@ -1860,16 +2052,43 @@ h1, h2, h3, h4, h5, h6, h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { display: none; } + .dark\:border-0 { + border-width: 0px; + } + + .dark\:border-2 { + border-width: 2px; + } + + .dark\:border-none { + border-style: none; + } + .dark\:border-gray-600 { --tw-border-opacity: 1; border-color: rgb(75 85 99 / var(--tw-border-opacity)); } + .dark\:border-orange-600 { + --tw-border-opacity: 1; + border-color: rgb(234 88 12 / var(--tw-border-opacity)); + } + .dark\:border-orange-400 { --tw-border-opacity: 1; border-color: rgb(251 146 60 / var(--tw-border-opacity)); } + .dark\:border-orange-200 { + --tw-border-opacity: 1; + border-color: rgb(254 215 170 / var(--tw-border-opacity)); + } + + .dark\:border-orange-900 { + --tw-border-opacity: 1; + border-color: rgb(124 45 18 / var(--tw-border-opacity)); + } + .dark\:bg-black { --tw-bg-opacity: 1; background-color: rgb(0 0 0 / var(--tw-bg-opacity)); @@ -1899,16 +2118,6 @@ h1, h2, h3, h4, h5, h6, h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { background-color: rgb(112 26 117 / var(--tw-bg-opacity)); } - .dark\:bg-orange-400 { - --tw-bg-opacity: 1; - background-color: rgb(251 146 60 / var(--tw-bg-opacity)); - } - - .dark\:bg-orange-600 { - --tw-bg-opacity: 1; - background-color: rgb(234 88 12 / var(--tw-bg-opacity)); - } - .dark\:bg-pink-600 { --tw-bg-opacity: 1; background-color: rgb(219 39 119 / var(--tw-bg-opacity)); @@ -1919,6 +2128,31 @@ h1, h2, h3, h4, h5, h6, h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { background-color: rgb(250 204 21 / var(--tw-bg-opacity)); } + .dark\:bg-green-600 { + --tw-bg-opacity: 1; + background-color: rgb(22 163 74 / var(--tw-bg-opacity)); + } + + .dark\:bg-orange-600 { + --tw-bg-opacity: 1; + background-color: rgb(234 88 12 / var(--tw-bg-opacity)); + } + + .dark\:bg-orange-400 { + --tw-bg-opacity: 1; + background-color: rgb(251 146 60 / var(--tw-bg-opacity)); + } + + .dark\:bg-orange-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 215 170 / var(--tw-bg-opacity)); + } + + .dark\:bg-orange-300 { + --tw-bg-opacity: 1; + background-color: rgb(253 186 116 / var(--tw-bg-opacity)); + } + .dark\:text-blue-200 { --tw-text-opacity: 1; color: rgb(191 219 254 / var(--tw-text-opacity)); diff --git a/slices/admin/actions/trips/update.rb b/slices/admin/actions/trips/update.rb new file mode 100644 index 0000000..fc929fb --- /dev/null +++ b/slices/admin/actions/trips/update.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +module Admin + module Actions + module Trips + class Update < Admin::Action + + include Deps["commands.trips.update"] + + def handle(req, res) + id = req.params[:id] + trip = req.params[:trip] + + update.call(id: id, trip: trip) + + res.redirect_to "/admin/trips/#{id}" + end + end + end + end +end diff --git a/slices/admin/commands/trips/update.rb b/slices/admin/commands/trips/update.rb new file mode 100644 index 0000000..3aa41e2 --- /dev/null +++ b/slices/admin/commands/trips/update.rb @@ -0,0 +1,16 @@ +module Admin + module Commands + module Trips + class Update + include Dry::Monads[:result] + include Deps["repos.trip_repo"] + + def call(id:, trip:) + trip_repo.update(id, trip) + + Success() + end + end + end + end +end diff --git a/slices/admin/repos/trip_repo.rb b/slices/admin/repos/trip_repo.rb index c1e1d34..2a832ed 100644 --- a/slices/admin/repos/trip_repo.rb +++ b/slices/admin/repos/trip_repo.rb @@ -4,12 +4,20 @@ module Admin commands :create def list - trips.order(:start_date).to_a + trips + .order(:start_date) + .to_a end def fetch(id) trips.where(id: id).one end + + def update(id, trip) + trips + .where(id: id) + .update(trip) + end end end end diff --git a/slices/admin/templates/trips/show.html.slim b/slices/admin/templates/trips/show.html.slim index a5779e7..314c594 100644 --- a/slices/admin/templates/trips/show.html.slim +++ b/slices/admin/templates/trips/show.html.slim @@ -1,6 +1,22 @@ div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200" h1 Admin // Trips // #{trip.name} +div class="max-w-prose mx-auto mb-8 border-gray-400 border-b-4" + form action="/admin/trips/#{trip.id}" method="POST" + input type="hidden" name="method" value="_put" + + div class="mb-4" + label class="text-gray-800 dark:text-gray-200 mr-2" for="name" Name: + input class="text-gray-800 p-1 border border-gray-400" type="text" id="name" name="trip[name]" value=trip.name + + div class="mb-4" + label class="text-gray-800 dark:text-gray-200 mr-2" for="subtitle" Subtitle: + input class="text-gray-800 p-1 border border-gray-400" type="text" id="subtitle" name="trip[subtitle]" value=trip.subtitle + + div class="mb-4" + button class="rounded bg-blue-100 hover:bg-blue-200 text-blue-600 px-2 hover:cursor-pointer" type="submit" + = "Update" + div class="max-w-prose mx-auto" - posts.each do |post| == render "shared/post", post: post, trip_id: trip.id, added: post.trips.map(&:id).include?(trip.id)