Add highlights
This commit is contained in:
17
slices/admin/actions/posts/create_highlight.rb
Normal file
17
slices/admin/actions/posts/create_highlight.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Admin
|
||||
module Actions
|
||||
module Posts
|
||||
class CreateHighlight < Admin::Action
|
||||
include Deps["commands.highlight.create"]
|
||||
|
||||
def handle(req, res)
|
||||
create.call(post_id: req.params[:id], text: req.params[:text])
|
||||
|
||||
res.redirect_to "/admin/posts/#{req.params[:id]}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
17
slices/admin/actions/posts/delete_highlight.rb
Normal file
17
slices/admin/actions/posts/delete_highlight.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Admin
|
||||
module Actions
|
||||
module Posts
|
||||
class DeleteHighlight < Admin::Action
|
||||
include Deps["repos.highlight_repo"]
|
||||
|
||||
def handle(req, res)
|
||||
highlight_repo.delete(req.params[:highlight_id])
|
||||
|
||||
res.redirect_to "/admin/posts/#{req.params[:post_id]}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@@ -1,5 +1,4 @@
|
||||
body {
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@tailwind typography;
|
||||
|
@@ -6,5 +6,26 @@ import "../css/app.css";
|
||||
Alpine.magic('clipboard', () => {
|
||||
return subject => navigator.clipboard.writeText(subject)
|
||||
})
|
||||
|
||||
Alpine.magic('textHighlighter', (el, {Alpine}) => {
|
||||
return {
|
||||
isOpen: false,
|
||||
anchorX: "0px",
|
||||
anchorY: "0px",
|
||||
selection: null,
|
||||
text: "",
|
||||
highlightText() {
|
||||
this.isOpen = false
|
||||
// document.
|
||||
this.selection = document.getSelection()
|
||||
this.text = this.selection.toString()
|
||||
const anchor = this.selection.focusNode.parentElement.getBoundingClientRect()
|
||||
this.isOpen = el.contains(this.selection.focusNode) && this.selection.focusOffset != this.selection.anchorOffset;
|
||||
|
||||
this.anchorX = `${anchor.left - 170}px`
|
||||
this.anchorY = `${anchor.top + window.scrollY}px`
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})();
|
16
slices/admin/commands/highlight/create.rb
Normal file
16
slices/admin/commands/highlight/create.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
module Admin
|
||||
module Commands
|
||||
module Highlight
|
||||
class Create
|
||||
include Dry::Monads[:result]
|
||||
include Deps["repos.highlight_repo"]
|
||||
|
||||
def call(post_id:, text:)
|
||||
highlight_repo.create(post_id:, text:)
|
||||
|
||||
Success()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@@ -54,6 +54,8 @@ module Admin
|
||||
post "/posts/:id/de_syndicate/:target", to: Auth.call(action: "posts.de_syndicate")
|
||||
post "/posts/:id/syndicate/:target", to: Auth.call(action: "posts.syndicate")
|
||||
post "/post/:id/update", to: Auth.call(action: "posts.update")
|
||||
post "/post/:id/highlight", to: Auth.call(action: "posts.create_highlight")
|
||||
delete "/post/:post_id/highlight/:highlight_id", to: Auth.call(action: "posts.delete_highlight")
|
||||
|
||||
get "/media", to: Auth.call(action: "photos.index")
|
||||
delete "/media/public/media/:year/:path", to: Auth.call(action: "photos.delete")
|
||||
|
12
slices/admin/repos/highlight_repo.rb
Normal file
12
slices/admin/repos/highlight_repo.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
module Admin
|
||||
module Repos
|
||||
class HighlightRepo < Adamantium::Repo[:highlights]
|
||||
commands :create, delete: :by_pk
|
||||
|
||||
def list_all
|
||||
highlights
|
||||
.to_a
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@@ -71,7 +71,7 @@ module Admin
|
||||
|
||||
def find(id:)
|
||||
posts
|
||||
.combine(:tags)
|
||||
.combine(:tags, :highlights)
|
||||
.where(id: id).one!
|
||||
end
|
||||
|
||||
|
@@ -19,7 +19,7 @@ div class="max-w-prose mx-auto" x-data="{ activeTab: 0 }"
|
||||
tr id="bookmark-#{bookmark.id}"
|
||||
td
|
||||
div
|
||||
a href="/bookmark/#{bookmark.slug}"
|
||||
a href="/admin/posts/#{bookmark.id}"
|
||||
= bookmark.name
|
||||
a class="no-underline" href=bookmark.url
|
||||
small class="text-gray-400 dark:text-gray-600" = bookmark.url
|
||||
|
@@ -14,7 +14,8 @@ html
|
||||
= javascript_tag "app"
|
||||
|
||||
script src="https://unpkg.com/htmx.org@1.9.2/dist/htmx.min.js" integrity="sha384-L6OqL9pRWyyFU3+/bjdSri+iIphTN/bvYyM37tICVyOJkWZLpP2vGn6VUEXgzg6h" crossorigin="anonymous"
|
||||
script src="https://cdn.jsdelivr.net/npm/alpinejs@3.12.0/dist/cdn.min.js" defer="true"
|
||||
script src="https://cdn.jsdelivr.net/npm/@alpinejs/anchor@3.13.8/dist/cdn.min.js" defer="true"
|
||||
script src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.8/dist/cdn.min.js" defer="true"
|
||||
|
||||
- if Hanami.app.settings.micropub_pub_key
|
||||
link rel="pgpkey" href="/key"
|
||||
|
@@ -24,12 +24,18 @@ div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:
|
||||
button hx-post="/admin/posts/#{post.id}/syndicate/day_one" Send to Day One
|
||||
|
||||
// TODO: Add preview, fix sending to DayOne
|
||||
article class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200 prose-a:text-blue-600 prose-a:no-underline hover:prose-a:underline prose-img:rounded"
|
||||
a href="/post/#{post.slug}"
|
||||
h1= post.name || "💬"
|
||||
article x-data="$textHighlighter, {isOpen: false, anchorX: 0, anchorY: 0, text: ''}" class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:text-gray-200 prose-a:text-blue-600 prose-a:no-underline hover:prose-a:underline prose-img:rounded"
|
||||
- if post.post_type != "bookmark"
|
||||
a href="/post/#{post.slug}"
|
||||
h1= post.name || "💬"
|
||||
form action="/admin/post/#{post.id}/update" method="POST"
|
||||
textarea name="body" class="text-gray-800 w-full border-blue-200 border-2 rounded p-2 mb-4" x-data="{ resize: () => { $el.style.height = '5px'; $el.style.height = $el.scrollHeight + 'px' } }" x-init="resize()" @input="resize()"
|
||||
== markdown_body
|
||||
- if post.post_type != "bookmark"
|
||||
textarea name="body" class="text-gray-800 w-full border-blue-200 border-2 rounded p-2 mb-4" x-data="{ resize: () => { $el.style.height = '5px'; $el.style.height = $el.scrollHeight + 'px' } }" x-init="resize()" @input="resize()"
|
||||
== markdown_body
|
||||
- if post.post_type == "bookmark"
|
||||
div x-ref="bookmarkText" @mouseup.capture="highlightText()"
|
||||
== post.cached_content
|
||||
|
||||
fieldset class="mb-4 flex"
|
||||
label for="commentable" class="mr-2" Commentable?
|
||||
input class="mt-2" type="checkbox" value="true" id="commentable" name="commentable" switch="switch" checked=post.commentable
|
||||
@@ -38,3 +44,21 @@ article class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 d
|
||||
input type="text" name="tags" id="tags" class="w-full px-1 border rounded" value="#{post.tags.map(&:label).join(", ")}"
|
||||
button class="rounded bg-blue-100 hover:bg-blue-200 text-blue-600 px-2 hover:cursor-pointer" type="submit"
|
||||
= "Update"
|
||||
|
||||
- if post.highlights.count > 0
|
||||
table class="prose dark:prose-invert table-auto"
|
||||
- post.highlights.each_with_index do |highlight, idx|
|
||||
tr class="#{idx.even? ? 'bg-amber-50' : ''}"
|
||||
td class="p-2"
|
||||
= highlight.text
|
||||
td class="p-2"
|
||||
form method="POST" action="/admin/post/#{post.id}/highlight/#{highlight.id}"
|
||||
input type="hidden" name="_method" value="delete"
|
||||
button
|
||||
= "Delete"
|
||||
|
||||
div @click.outside="isOpen = false" class="p-2 bg-indigo-900 hover:bg-indigo-800 rounded text-white shadow-md shadow-indigo-500" x-show="isOpen" x-anchor.no-style="$refs.bookmarkText" :style="{ position: 'absolute', hidden: isOpen, top: isOpen ? anchorY : '0px', left: isOpen ? anchorX : '0px' }"
|
||||
form method="POST" class="p-0 m-0" action="/admin/post/#{post.id}/highlight"
|
||||
input type="hidden" name="post_id" value="#{post.id}"
|
||||
input class="text-gray-600" type="hidden" x-model="text" name="text"
|
||||
button = "Save highlight"
|
||||
|
@@ -184,7 +184,7 @@ module Main
|
||||
def fetch!(slug)
|
||||
posts
|
||||
.published
|
||||
.combine(:tags, :trips, :webmentions, :reactions)
|
||||
.combine(:tags, :trips, :webmentions, :reactions, :highlights)
|
||||
.node(:webmentions) { |webmention|
|
||||
webmention.published.where(type: "reply")
|
||||
}
|
||||
|
@@ -13,6 +13,13 @@ div class="mb-12 prose dark:prose-invert max-w-prose mx-auto text-gray-800 dark:
|
||||
|
||||
== bookmark.content
|
||||
|
||||
- if bookmark.highlights.count > 0
|
||||
h2 Highlights
|
||||
- bookmark.highlights.each do |highlight|
|
||||
div class="rounded p-2 bg-amber-100 dark:bg-amber-800 mb-4"
|
||||
= render "shared/quote", color: "fill-amber-200 dark:fill-amber-700"
|
||||
= highlight.text
|
||||
|
||||
- unless bookmark.cached_content.nil?
|
||||
button class="hover:text-gray-400" @click="open = ! open" Toggle cached version
|
||||
|
||||
|
@@ -31,9 +31,9 @@ html x-data="{darkMode: $persist(false)}" :class="{'dark' : darkMode === true}"
|
||||
script data-goatcounter="https://stats.dnitza.com/count" async="" src="//stats.dnitza.com/count.js"
|
||||
|
||||
script src="https://unpkg.com/htmx.org@1.9.2/dist/htmx.min.js" integrity="sha384-L6OqL9pRWyyFU3+/bjdSri+iIphTN/bvYyM37tICVyOJkWZLpP2vGn6VUEXgzg6h" crossorigin="anonymous"
|
||||
script src="https://cdn.jsdelivr.net/npm/@alpinejs/persist@3.13.3/dist/cdn.min.js"
|
||||
script src="https://cdn.jsdelivr.net/npm/@alpinejs/persist@3.13.8/dist/cdn.min.js"
|
||||
= javascript_tag "app"
|
||||
script src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.3/dist/cdn.min.js" defer=""
|
||||
script src="https://cdn.jsdelivr.net/npm/alpinejs@3.13.8/dist/cdn.min.js" defer=""
|
||||
|
||||
link rel="stylesheet" href="https://unpkg.com/@highlightjs/cdn-assets@11.8.0/styles/github-dark.min.css"
|
||||
script src="https://unpkg.com/@highlightjs/cdn-assets@11.8.0/highlight.min.js" defer=""
|
||||
|
12
slices/main/templates/shared/_quote.html.slim
Normal file
12
slices/main/templates/shared/_quote.html.slim
Normal file
@@ -0,0 +1,12 @@
|
||||
- color_class = defined?(color) ? color : "fill-gray-900"
|
||||
xml version="1.0" encoding="iso-8859-1"
|
||||
svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 57 57" xml:space="preserve" class="w-8"
|
||||
g
|
||||
circle class="#{color_class}" cx="18.5" cy="31.5" r="5.5"
|
||||
path class="#{color_class}" d="M18.5,38c-3.584,0-6.5-2.916-6.5-6.5s2.916-6.5,6.5-6.5s6.5,2.916,6.5,6.5S22.084,38,18.5,38z M18.5,27c-2.481,0-4.5,2.019-4.5,4.5s2.019,4.5,4.5,4.5s4.5-2.019,4.5-4.5S20.981,27,18.5,27z"
|
||||
|
||||
g
|
||||
circle class="#{color_class}" cx="35.5" cy="31.5" r="5.5"
|
||||
path class="#{color_class}" d="M35.5,38c-3.584,0-6.5-2.916-6.5-6.5s2.916-6.5,6.5-6.5s6.5,2.916,6.5,6.5S39.084,38,35.5,38z M35.5,27c-2.481,0-4.5,2.019-4.5,4.5s2.019,4.5,4.5,4.5s4.5-2.019,4.5-4.5S37.981,27,35.5,27z"
|
||||
path class="#{color_class}" d="M13,32c-0.553,0-1-0.447-1-1c0-7.72,6.28-14,14-14c0.553,0,1,0.447,1,1s-0.447,1-1,1 c-6.617,0-12,5.383-12,12C14,31.553,13.553,32,13,32z"
|
||||
path class="#{color_class}" d="M30,32c-0.553,0-1-0.447-1-1c0-7.72,6.28-14,14-14c0.553,0,1,0.447,1,1s-0.447,1-1,1 c-6.617,0-12,5.383-12,12C31,31.553,30.553,32,30,32z"
|
Reference in New Issue
Block a user