Add Markdown editor to admin area

This commit is contained in:
Daniel Nitsikopoulos
2024-09-29 17:09:23 +10:00
parent 37a4508ec4
commit be63fb49c7
12 changed files with 2039 additions and 60 deletions

View File

@@ -2,7 +2,7 @@
source "https://rubygems.org" source "https://rubygems.org"
ruby "3.3.0" ruby "3.3.5"
gem "hanami", "~> 2.2.0.beta" gem "hanami", "~> 2.2.0.beta"
gem "hanami-router", "~> 2.2.0.beta" gem "hanami-router", "~> 2.2.0.beta"
@@ -57,7 +57,6 @@ gem "mail"
gem "que" gem "que"
gem "connection_pool" gem "connection_pool"
gem "image_processing", "~> 1.0" gem "image_processing", "~> 1.0"
gem "mini_magick"
gem "unicode-emoji" gem "unicode-emoji"
gem "mail_room", github: "dNitza/mail_room", branch: "master" gem "mail_room", github: "dNitza/mail_room", branch: "master"
@@ -83,7 +82,7 @@ group :development do
gem "bcrypt_pbkdf" gem "bcrypt_pbkdf"
gem "hanami-webconsole", "~> 2.2.0.beta" gem "hanami-webconsole", "~> 2.2.0.beta"
gem "guard-puma" gem "guard-puma"
gem "standardrb" gem "standard", ">= 1.35.1"
gem "capistrano", "~> 3.7", require: false gem "capistrano", "~> 3.7", require: false
gem "capistrano-bundler" gem "capistrano-bundler"
gem "capistrano-systemd-multiservice" gem "capistrano-systemd-multiservice"
@@ -98,3 +97,7 @@ group :test do
gem "database_cleaner-sequel" gem "database_cleaner-sequel"
gem "timecop" gem "timecop"
end end
gem "phlex", github: "phlex-ruby/phlex", branch: "main"
gem "mini_magick", "~> 4.13"

View File

@@ -24,6 +24,13 @@ GIT
specs: specs:
ruby-filemagic (0.7.3) ruby-filemagic (0.7.3)
GIT
remote: https://github.com/phlex-ruby/phlex.git
revision: 739cb8df74e5b5f5a2d119f699f8ece8f098c133
branch: main
specs:
phlex (2.0.0.beta2)
GIT GIT
remote: https://github.com/seuros/capistrano-puma.git remote: https://github.com/seuros/capistrano-puma.git
revision: 9cd5e5df4dec324d75493d24b498d91285ddea9e revision: 9cd5e5df4dec324d75493d24b498d91285ddea9e
@@ -49,7 +56,7 @@ GEM
tzinfo (~> 2.0, >= 2.0.5) tzinfo (~> 2.0, >= 2.0.5)
addressable (2.8.7) addressable (2.8.7)
public_suffix (>= 2.0.2, < 7.0) public_suffix (>= 2.0.2, < 7.0)
airbrussh (1.5.2) airbrussh (1.5.3)
sshkit (>= 1.6.1, != 1.7.0) sshkit (>= 1.6.1, != 1.7.0)
ast (2.4.2) ast (2.4.2)
babosa (2.0.0) babosa (2.0.0)
@@ -97,7 +104,7 @@ GEM
debug_inspector (1.2.0) debug_inspector (1.2.0)
diff-lcs (1.5.1) diff-lcs (1.5.1)
domain_name (0.6.20240107) domain_name (0.6.20240107)
dotenv (3.1.2) dotenv (3.1.4)
down (5.4.2) down (5.4.2)
addressable (~> 2.8) addressable (~> 2.8)
drb (2.2.1) drb (2.2.1)
@@ -145,7 +152,7 @@ GEM
dry-types (>= 1.7, < 2) dry-types (>= 1.7, < 2)
ice_nine (~> 0.11) ice_nine (~> 0.11)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
dry-system (1.1.0.beta1) dry-system (1.1.0.beta2)
dry-auto_inject (~> 1.0) dry-auto_inject (~> 1.0)
dry-configurable (~> 1.0) dry-configurable (~> 1.0)
dry-core (~> 1.0) dry-core (~> 1.0)
@@ -169,7 +176,7 @@ GEM
erubi (1.13.0) erubi (1.13.0)
faker (3.4.2) faker (3.4.2)
i18n (>= 1.8.11, < 2) i18n (>= 1.8.11, < 2)
faraday (1.10.3) faraday (1.10.4)
faraday-em_http (~> 1.0) faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0) faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1) faraday-excon (~> 1.1)
@@ -216,40 +223,40 @@ GEM
guard-compat (~> 1.2) guard-compat (~> 1.2)
puma (>= 4.0, < 7) puma (>= 4.0, < 7)
guess_html_encoding (0.0.11) guess_html_encoding (0.0.11)
hanami (2.2.0.beta1) hanami (2.2.0.beta2)
bundler (>= 1.16, < 3) bundler (>= 1.16, < 3)
dry-configurable (~> 1.0, >= 1.2.0, < 2) dry-configurable (~> 1.0, >= 1.2.0, < 2)
dry-core (~> 1.0, < 2) dry-core (~> 1.0, < 2)
dry-inflector (~> 1.0, >= 1.1.0, < 2) dry-inflector (~> 1.0, >= 1.1.0, < 2)
dry-logger (~> 1.0, < 2) dry-logger (~> 1.0, < 2)
dry-monitor (~> 1.0, >= 1.0.1, < 2) dry-monitor (~> 1.0, >= 1.0.1, < 2)
dry-system (= 1.1.0.beta1) dry-system (= 1.1.0.beta2)
hanami-cli (= 2.2.0.beta1) hanami-cli (= 2.2.0.beta2)
hanami-utils (~> 2.2.beta) hanami-utils (~> 2.2.beta)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
hanami-assets (2.2.0.beta1) hanami-assets (2.2.0.beta2)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
hanami-cli (2.2.0.beta1) hanami-cli (2.2.0.beta2)
bundler (~> 2.1) bundler (~> 2.1)
dry-cli (~> 1.0, >= 1.1.0) dry-cli (~> 1.0, >= 1.1.0)
dry-files (~> 1.0, >= 1.0.2, < 2) dry-files (~> 1.0, >= 1.0.2, < 2)
dry-inflector (~> 1.0, < 2) dry-inflector (~> 1.0, < 2)
rake (~> 13.0) rake (~> 13.0)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
hanami-controller (2.2.0.beta1) hanami-controller (2.2.0.beta2)
dry-configurable (~> 1.0, < 2) dry-configurable (~> 1.0, < 2)
dry-core (~> 1.0) dry-core (~> 1.0)
hanami-utils (~> 2.2.beta) hanami-utils (~> 2.2.beta)
rack (~> 2.0) rack (~> 2.0)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
hanami-db (2.2.0.beta1) hanami-db (2.2.0.beta2)
rom (~> 5.3) rom (~> 5.3)
rom-sql (~> 3.6, >= 3.6.4) rom-sql (~> 3.6, >= 3.6.4)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
hanami-reloader (2.2.0.beta1) hanami-reloader (2.2.0.beta2)
hanami-cli (~> 2.2.beta) hanami-cli (~> 2.2.beta)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
hanami-router (2.2.0.beta1) hanami-router (2.2.0.beta2)
mustermann (~> 3.0) mustermann (~> 3.0)
mustermann-contrib (~> 3.0) mustermann-contrib (~> 3.0)
rack (~> 2.0) rack (~> 2.0)
@@ -258,21 +265,20 @@ GEM
rake (~> 13.0) rake (~> 13.0)
rspec (~> 3.12) rspec (~> 3.12)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
hanami-utils (2.2.0.beta1) hanami-utils (2.2.0.beta2)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
dry-core (~> 1.0, < 2) dry-core (~> 1.0, < 2)
dry-transformer (~> 1.0, < 2) dry-transformer (~> 1.0, < 2)
hanami-validations (2.2.0.beta1) hanami-validations (2.2.0.beta2)
dry-validation (>= 1.10, < 2) dry-validation (>= 1.10, < 2)
zeitwerk (~> 2.6.0) hanami-view (2.2.0.beta2)
hanami-view (2.2.0.beta1)
dry-configurable (~> 1.0) dry-configurable (~> 1.0)
dry-core (~> 1.0) dry-core (~> 1.0)
dry-inflector (~> 1.0, < 2) dry-inflector (~> 1.0, < 2)
temple (~> 0.10.0, >= 0.10.2) temple (~> 0.10.0, >= 0.10.2)
tilt (~> 2.3) tilt (~> 2.3)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
hanami-webconsole (2.2.0.beta1) hanami-webconsole (2.2.0.beta2)
better_errors (~> 2.10, >= 2.10.1) better_errors (~> 2.10, >= 2.10.1)
binding_of_caller (~> 1.0) binding_of_caller (~> 1.0)
hansi (0.2.1) hansi (0.2.1)
@@ -284,18 +290,18 @@ GEM
csv csv
mini_mime (>= 1.0.0) mini_mime (>= 1.0.0)
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
i18n (1.14.5) i18n (1.14.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
ice_nine (0.11.2) ice_nine (0.11.2)
image_processing (1.13.0) image_processing (1.13.0)
mini_magick (>= 4.9.5, < 5) mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3) ruby-vips (>= 2.0.17, < 3)
io-console (0.7.2) io-console (0.7.2)
irb (1.14.0) irb (1.14.1)
rdoc (>= 4.0.0) rdoc (>= 4.0.0)
reline (>= 0.4.2) reline (>= 0.4.2)
json (2.7.2) json (2.7.2)
jwt (2.8.2) jwt (2.9.1)
base64 base64
language_server-protocol (3.17.0.3) language_server-protocol (3.17.0.3)
lastfm (1.27.4) lastfm (1.27.4)
@@ -305,7 +311,7 @@ GEM
listen (3.9.0) listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3) rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10) rb-inotify (~> 0.9, >= 0.9.10)
logger (1.6.0) logger (1.6.1)
lumberjack (1.2.10) lumberjack (1.2.10)
mail (2.8.1) mail (2.8.1)
mini_mime (>= 0.1.1) mini_mime (>= 0.1.1)
@@ -316,20 +322,20 @@ GEM
method_source (1.1.0) method_source (1.1.0)
mime-types (3.5.2) mime-types (3.5.2)
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2024.0820) mime-types-data (3.2024.0903)
mini_magick (4.13.2) mini_magick (4.13.2)
mini_mime (1.1.5) mini_mime (1.1.5)
minitest (5.25.1) minitest (5.25.1)
multi_xml (0.7.1) multi_xml (0.7.1)
bigdecimal (~> 3.1) bigdecimal (~> 3.1)
multipart-post (2.4.1) multipart-post (2.4.1)
mustermann (3.0.2) mustermann (3.0.3)
ruby2_keywords (~> 0.0.1) ruby2_keywords (~> 0.0.1)
mustermann-contrib (3.0.2) mustermann-contrib (3.0.3)
hansi (~> 0.2.0) hansi (~> 0.2.0)
mustermann (= 3.0.2) mustermann (= 3.0.3)
nenv (0.3.0) nenv (0.3.0)
net-imap (0.4.14) net-imap (0.4.16)
date date
net-protocol net-protocol
net-pop (0.1.2) net-pop (0.1.2)
@@ -367,18 +373,19 @@ GEM
omdb-api (1.4.3) omdb-api (1.4.3)
activesupport activesupport
httparty httparty
ostruct (0.6.0)
parallel (1.26.3) parallel (1.26.3)
parser (3.3.4.2) parser (3.3.5.0)
ast (~> 2.4.1) ast (~> 2.4.1)
racc racc
pg (1.5.7) pg (1.5.8)
pry (0.14.2) pry (0.14.2)
coderay (~> 1.1) coderay (~> 1.1)
method_source (~> 1.0) method_source (~> 1.0)
psych (5.1.2) psych (5.1.2)
stringio stringio
public_suffix (6.0.1) public_suffix (6.0.1)
puma (6.4.2) puma (6.4.3)
nio4r (~> 2.0) nio4r (~> 2.0)
que (2.4.0) que (2.4.0)
racc (1.8.1) racc (1.8.1)
@@ -405,7 +412,7 @@ GEM
redis-client (0.22.2) redis-client (0.22.2)
connection_pool connection_pool
regexp_parser (2.9.2) regexp_parser (2.9.2)
reline (0.5.9) reline (0.5.10)
io-console (~> 0.5) io-console (~> 0.5)
rest-client (2.1.0) rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0) http-accept (>= 1.7.0, < 2.0)
@@ -414,8 +421,7 @@ GEM
netrc (~> 0.8) netrc (~> 0.8)
reverse_markdown (2.1.1) reverse_markdown (2.1.1)
nokogiri nokogiri
rexml (3.3.6) rexml (3.3.8)
strscan
rom (5.3.2) rom (5.3.2)
rom-changeset (~> 5.3, >= 5.3.0) rom-changeset (~> 5.3, >= 5.3.0)
rom-core (~> 5.3, >= 5.3.2) rom-core (~> 5.3, >= 5.3.2)
@@ -448,14 +454,14 @@ GEM
dry-types (~> 1.0) dry-types (~> 1.0)
rom (~> 5.2, >= 5.2.1) rom (~> 5.2, >= 5.2.1)
sequel (>= 4.49) sequel (>= 4.49)
rouge (4.3.0) rouge (4.4.0)
rspec (3.13.0) rspec (3.13.0)
rspec-core (~> 3.13.0) rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0) rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0) rspec-mocks (~> 3.13.0)
rspec-core (3.13.0) rspec-core (3.13.1)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
rspec-expectations (3.13.2) rspec-expectations (3.13.3)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
rspec-mocks (3.13.1) rspec-mocks (3.13.1)
@@ -473,13 +479,13 @@ GEM
rubocop-ast (>= 1.31.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0) unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.32.1) rubocop-ast (1.32.3)
parser (>= 3.3.1.0) parser (>= 3.3.1.0)
rubocop-performance (1.21.1) rubocop-performance (1.21.1)
rubocop (>= 1.48.1, < 2.0) rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.31.1, < 2.0) rubocop-ast (>= 1.31.1, < 2.0)
ruby-progressbar (1.13.0) ruby-progressbar (1.13.0)
ruby-readability (0.7.1) ruby-readability (0.7.2)
guess_html_encoding (>= 0.0.4) guess_html_encoding (>= 0.0.4)
nokogiri (>= 1.6.0) nokogiri (>= 1.6.0)
ruby-vips (2.2.2) ruby-vips (2.2.2)
@@ -490,7 +496,7 @@ GEM
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.12.0) nokogiri (>= 1.12.0)
securerandom (0.3.1) securerandom (0.3.1)
sequel (5.83.1) sequel (5.84.0)
bigdecimal bigdecimal
shellany (0.0.1) shellany (0.0.1)
simple-rss (1.3.3) simple-rss (1.3.3)
@@ -500,11 +506,12 @@ GEM
snaky_hash (2.0.1) snaky_hash (2.0.1)
hashie hashie
version_gem (~> 1.1, >= 1.1.1) version_gem (~> 1.1, >= 1.1.1)
sshkit (1.23.0) sshkit (1.23.1)
base64 base64
net-scp (>= 1.1.2) net-scp (>= 1.1.2)
net-sftp (>= 2.1.2) net-sftp (>= 2.1.2)
net-ssh (>= 2.8.0) net-ssh (>= 2.8.0)
ostruct
standard (1.40.0) standard (1.40.0)
language_server-protocol (~> 3.17.0.2) language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.0) lint_roller (~> 1.0)
@@ -517,14 +524,11 @@ GEM
standard-performance (1.4.0) standard-performance (1.4.0)
lint_roller (~> 1.1) lint_roller (~> 1.1)
rubocop-performance (~> 1.21.0) rubocop-performance (~> 1.21.0)
standardrb (1.0.1)
standard
steam-api (1.2.0) steam-api (1.2.0)
faraday (~> 1.0) faraday (~> 1.0)
stringio (3.1.1) stringio (3.1.1)
strscan (3.1.0)
temple (0.10.3) temple (0.10.3)
thor (1.3.1) thor (1.3.2)
tilt (2.4.0) tilt (2.4.0)
time_math2 (0.1.1) time_math2 (0.1.1)
timecop (0.9.10) timecop (0.9.10)
@@ -532,11 +536,11 @@ GEM
transproc (1.1.1) transproc (1.1.1)
tzinfo (2.0.6) tzinfo (2.0.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
unicode-display_width (2.5.0) unicode-display_width (2.6.0)
unicode-emoji (3.4.0) unicode-emoji (3.5.0)
unicode-version (~> 1.0) unicode-version (~> 1.0)
unicode-version (1.4.0) unicode-version (1.4.0)
vernier (1.1.2) vernier (1.2.1)
version_gem (1.1.4) version_gem (1.1.4)
warning (1.4.0) warning (1.4.0)
whenever (1.0.0) whenever (1.0.0)
@@ -547,7 +551,7 @@ GEM
date date
httparty httparty
json (>= 2.0) json (>= 2.0)
zeitwerk (2.6.17) zeitwerk (2.6.18)
PLATFORMS PLATFORMS
arm64-darwin-23 arm64-darwin-23
@@ -597,10 +601,11 @@ DEPENDENCIES
mail mail
mail_room! mail_room!
matrix matrix
mini_magick mini_magick (~> 4.13)
ogpr ogpr
omdb-api (= 1.4.3) omdb-api (= 1.4.3)
pg pg
phlex!
puma puma
que que
rack-attack (~> 6.7) rack-attack (~> 6.7)
@@ -621,7 +626,7 @@ DEPENDENCIES
sanitize sanitize
scraperd! scraperd!
slim slim
standardrb standard (>= 1.35.1)
steam-api steam-api
time_math2 time_math2
timecop timecop
@@ -631,7 +636,7 @@ DEPENDENCIES
whenever whenever
RUBY VERSION RUBY VERSION
ruby 3.3.0p0 ruby 3.3.5p100
BUNDLED WITH BUNDLED WITH
2.3.22 2.5.18

View File

@@ -0,0 +1,13 @@
module Admin
module Actions
module Posts
class New < Action
include Deps["views.posts.new"]
def handle(req, res)
res.render new
end
end
end
end
end

View File

@@ -0,0 +1,3 @@
.milkdown .ProseMirror {
padding: 0 !important;
}

View File

@@ -3,6 +3,36 @@ import "@main/css/app.css";
import "@app/builds/tailwind.css"; import "@app/builds/tailwind.css";
import "../css/app.css"; import "../css/app.css";
import { Crepe } from "@milkdown/crepe";
import { listener, listenerCtx } from "@milkdown/kit/plugin/listener";
import "@milkdown/crepe/theme/common/style.css";
// We have some themes for you to choose
import "@milkdown/crepe/theme/frame.css";
async function uploadImage(file: File) {
const formData = new FormData();
formData.append("file", file); // Append the file to the FormData object
try {
const response = await fetch("/micropub/media", {
method: "POST",
body: formData,
});
if (response.ok) {
const jsonResponse = await response.json();
return jsonResponse["url"];
} else {
alert("File upload failed.");
}
} catch (error) {
console.error("Error:", error);
alert("An error occurred during the upload.");
return null;
}
}
(function () { (function () {
document.addEventListener("alpine:init", () => { document.addEventListener("alpine:init", () => {
Alpine.magic("clipboard", () => { Alpine.magic("clipboard", () => {
@@ -32,5 +62,31 @@ import "../css/app.css";
}, },
}; };
}); });
let editor = document.getElementById("editor");
const crepe = new Crepe({
root: editor,
defaultValue: editor.dataset.postText,
featureConfigs: {
[Crepe.Feature.ImageBlock]: {
onUpload: async (file: File) => {
return uploadImage(file);
},
},
},
});
crepe.editor.config((ctx) => {
const bodyText = document.getElementById("body");
bodyText.hidden = true;
ctx.get(listenerCtx).markdownUpdated((ctx, markdown, prevMarkdown) => {
bodyText.innerHTML = markdown;
});
});
crepe.editor.use(listener);
crepe.create();
}); });
})(); })();

View File

@@ -46,6 +46,8 @@ module Admin
post "/bookmarks/:id/mark_unread", to: Auth.call(action: "bookmarks.mark_unread") post "/bookmarks/:id/mark_unread", to: Auth.call(action: "bookmarks.mark_unread")
get "/posts", to: Auth.call(action: "posts.index") get "/posts", to: Auth.call(action: "posts.index")
get "/posts/new", to: Auth.call(action: "posts.new")
post "/posts/create", to: Auth.call(action: "posts.create")
delete "/posts/:id", to: Auth.call(action: "posts.delete") delete "/posts/:id", to: Auth.call(action: "posts.delete")
post "/posts/:id/archive", to: Auth.call(action: "posts.archive") post "/posts/:id/archive", to: Auth.call(action: "posts.archive")
post "/posts/:id/publish", to: Auth.call(action: "posts.publish") post "/posts/:id/publish", to: Auth.call(action: "posts.publish")

View File

@@ -5,6 +5,8 @@ div class="max-w-prose mx-auto" x-data="{ activeTab: 0 }"
div class="flex" div class="flex"
a href="#" class="text-gray-200 cursor-pointer p-2 border-2 mr-2 rounded border-blue-400" :class="{ 'bg-blue-400 text-blue-900': activeTab === 0 }" @click="activeTab = 0" class="tab-control" Published a href="#" class="text-gray-200 cursor-pointer p-2 border-2 mr-2 rounded border-blue-400" :class="{ 'bg-blue-400 text-blue-900': activeTab === 0 }" @click="activeTab = 0" class="tab-control" Published
a href="#" class="text-gray-200 cursor-pointer p-2 border-2 rounded border-blue-400" :class="{ 'bg-blue-400 text-blue-900': activeTab === 1 }" @click="activeTab = 1" class="tab-control" Un published a href="#" class="text-gray-200 cursor-pointer p-2 border-2 rounded border-blue-400" :class="{ 'bg-blue-400 text-blue-900': activeTab === 1 }" @click="activeTab = 1" class="tab-control" Un published
div class="flex-1"
a href="/admin/posts/new" class="text-gray-200 cursor-pointer p-2 border-2 rounded border-blue-400 bg-blue-400 text-blue-900" New Post
table class="prose dark:prose-invert table-auto prose-a:text-blue-600 prose-a:no-underline" table class="prose dark:prose-invert table-auto prose-a:text-blue-600 prose-a:no-underline"
thead thead
th Details th Details
@@ -54,6 +56,3 @@ div class="max-w-prose mx-auto" x-data="{ activeTab: 0 }"
button hx-post="/admin/posts/#{post.id}/publish" publish button hx-post="/admin/posts/#{post.id}/publish" publish
div class="max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600" div class="max-w-screen-md mx-auto border-t border-solid border-gray-200 dark:border-gray-600"

View File

@@ -0,0 +1,26 @@
article x-data="{postTitle: 'Post title', postSlug: 'post-title', slugify(event) {
var str = event.target.value.replace(/^\s+|\s+$/g, '');
str = str.toLowerCase();
str = str.replace(/[^a-z0-9 -]/g, '')
.replace(/\s+/g, '-')
.replace(/-+/g, '-');
this.postSlug = str;
}}" 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"
form hx-post="/micropub"
fieldset class="mb-4 flex"
label for="name" class="mr-2"
input type="text" name="name" id="name" class="text-3xl w-full" x-on:change.debounce="slugify($event)" x-model="postTitle"
fieldset class="mb-4 flex"
label for="slug" class="mr-2" Slug:
input type="text" name="slug" id="slug" class="w-full px-1 border rounded" x-model="postSlug"
div id="editor" data-post-text=""
textarea id="body" name="content" 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()"
// 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=true
fieldset class="mb-4 flex"
label for="tags" class="mr-2" Tags:
input type="text" name="category" id="tags" class="w-full px-1 border rounded" value=""
button class="rounded bg-blue-100 hover:bg-blue-200 text-blue-600 px-2 hover:cursor-pointer" type="submit"
= "Create"

View File

@@ -30,8 +30,12 @@ article x-data="$textHighlighter, {isOpen: false, anchorX: 0, anchorY: 0, text:
h1= post.name || "💬" h1= post.name || "💬"
form action="/admin/post/#{post.id}/update" method="POST" form action="/admin/post/#{post.id}/update" method="POST"
- if post.post_type != "bookmark" - 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()" fieldset class="mb-4 flex"
== markdown_body label for="slug" class="mr-2" Slug:
input type="text" name="slug" id="slug" class="w-full px-1 border rounded" value="#{post.slug}"
div id="editor" data-post-text="#{markdown_body}"
textarea id="body" 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" - if post.post_type == "bookmark"
div x-ref="bookmarkText" @mouseup.capture="highlightText()" div x-ref="bookmarkText" @mouseup.capture="highlightText()"
== post.cached_content == post.cached_content

View File

@@ -0,0 +1,21 @@
module Admin
module Views
module Posts
class New < Admin::View
include Deps["repos.post_repo"]
expose :published_posts do |posts|
posts[0]
end
expose :unpublished_posts do |posts|
posts[1]
end
expose :posts do
post_repo.list.partition { |p| p.published_at }
end
end
end
end
end

View File

@@ -38,6 +38,7 @@ module Micropub
m.success do |post| m.success do |post|
post_type = (post.value!.post_type == :bookmark) ? :bookmark : :post post_type = (post.value!.post_type == :bookmark) ? :bookmark : :post
res.headers["Location"] = "#{settings.micropub_site_url}/#{post_type}/#{post.value!.slug}" res.headers["Location"] = "#{settings.micropub_site_url}/#{post_type}/#{post.value!.slug}"
res.headers["HX-Redirect"] = "#{settings.micropub_site_url}/#{post_type}/#{post.value!.slug}"
res.status = 201 res.status = 201
end end

1846
yarn.lock

File diff suppressed because it is too large Load Diff