Compare commits

...

2 Commits

Author SHA1 Message Date
ab1490f472
Remove Kosmos name from wording
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
refs #222
2025-05-29 14:24:43 +04:00
6014134396
Finish MVP for content editing 2025-05-29 14:18:14 +04:00
21 changed files with 101 additions and 68 deletions

View File

@ -0,0 +1,30 @@
<div class="inline-block text-left" data-controller="modal" data-action="keydown.esc->modal#close">
<button class="btn-md btn-outline text-red-600" data-action="click->modal#open" title="Edit">
<%= content || "Edit" %>
</button>
<%= render ModalComponent.new(show_close_button: false) do %>
<%= form_with model: [:admin, @editable_content],
html: { autocomplete: "off" } do |form| %>
<%= form.hidden_field :redirect_to, value: @redirect_to %>
<p class="mb-2">
<%= form.label :content, @editable_content.key.capitalize, class: 'font-bold' %>
</p>
<% if @editable_content.rich_text %>
<p>
<%= form.textarea :content, class: "md:w-[56rem] md:h-[28rem]" %>
</p>
<p class="text-right">
<%= form.submit "Save", class: "ml-2 btn-md btn-blue" %>
</p>
<% else %>
<p class="">
<%= form.text_field :content, class: "w-80" %>
</p>
<p>
<%= form.submit "Save", class: "btn-md btn-blue w-full" %>
</p>
<% end %>
<% end %>
<% end %>
</div>

View File

@ -0,0 +1,6 @@
class EditContentButtonComponent < ViewComponent::Base
def initialize(context:, key:, rich_text: false, redirect_to: nil)
@editable_content = EditableContent.find_or_create_by(context:, key:, rich_text:)
@redirect_to = redirect_to
end
end

View File

@ -0,0 +1,9 @@
<% if @editable_content.has_content? %>
<% if @editable_content.rich_text %>
<%= helpers.markdown_to_html @editable_content.content %>
<% else %>
<%= @editable_content.content %>
<% end %>
<% else %>
<%= @default %>
<% end %>

View File

@ -0,0 +1,6 @@
class EditableContentComponent < ViewComponent::Base
def initialize(context:, key:, rich_text: false, default: nil)
@editable_content = EditableContent.find_or_create_by(context:, key:, rich_text:)
@default = default
end
end

View File

@ -16,8 +16,14 @@ class Admin::EditableContentsController < Admin::BaseController
end
def update
return_to = params[:editable_content][:redirect_to].presence
if @editable_content.update(content_params)
render json: { status: "success", message: "Content updated" }, status: :ok
if return_to
redirect_to return_to
else
render status: :ok
end
else
render :edit, status: :unprocessable_entity
end

View File

@ -4,12 +4,6 @@ class Contributions::OtherController < ApplicationController
# GET /contributions/other
def index
@content_title = EditableContent.find_or_create_by(
path: "contributions/other", key: "title"
)
@content_body = EditableContent.find_or_create_by(
path: "contributions/other", key: "body", rich_text: true
)
@current_section = :contributions
end

View File

@ -15,6 +15,10 @@ module ApplicationHelper
tag.span text, class: "inline-flex items-center rounded-full bg-#{color}-100 px-2.5 py-0.5 text-xs font-medium text-#{color}-800"
end
def markdown_to_html(string)
raw Kramdown::Document.new(string, { input: "GFM" }).to_html
end
def image_url_for(attachment)
return s3_image_url(attachment) if Setting.s3_enabled?

View File

@ -1,10 +0,0 @@
module EditableContentHelper
def editable_content_for(path, key, default: nil, create_rich: false)
@content = EditableContent.find_by(path: "contributions/other", key: key)
@content.content.present? ? @content.content : default
end
def markdown_to_html(string)
raw Kramdown::Document.new(string, { input: "GFM" }).to_html
end
end

View File

@ -1,4 +1,12 @@
class EditableContent < ApplicationRecord
validates :key, presence: true,
uniqueness: { scope: :path }
uniqueness: { scope: :context }
def has_content?
content.present?
end
def is_empty?
content.blank?
end
end

View File

@ -3,7 +3,7 @@
<%= render MainWithTabnavComponent.new(tabnav_partial: "shared/tabnav_contributions") do %>
<section>
<p class="mb-12">
Your financial contributions to the development and upkeep of Kosmos
Your financial contributions to the development and upkeep of our
software and services.
</p>
</section>

View File

@ -1,42 +1,20 @@
<%= render HeaderComponent.new(title: "Contributions") %>
<%= render MainWithTabnavComponent.new(tabnav_partial: "shared/tabnav_contributions") do %>
<% if @edit_content %>
<section>
<%= form_with model: [:admin, @content_title] do |form| %>
<p class="mb-2">
<%= form.label :content, @content_title.key.capitalize, class: 'font-bold' %>
</p>
<p class="flex gap-1">
<%= form.text_field :content %>
<%# <%= form.submit "Save", class: "btn-md btn-blue" %>
<%= button_tag type: 'submit', name: nil, title: "Save", class: 'btn-md btn-icon btn-outline' do %>
<%= render partial: "icons/save", locals: { custom_class: "text-blue-600 h-4 w-4 inline" } %>
<% end %>
</p>
<%= render EditableContentComponent.new(
context: "contributions/other", key: "body", rich_text: true,
default: "No content yet") %>
<% if current_user.is_admin? %>
<div class="mt-8 pt-6 border-t border-gray-200 text-right">
<%= render EditContentButtonComponent.new(
context: "contributions/other", key: "title",
redirect_to: request.path) do %>Edit title<% end %>
<%= render EditContentButtonComponent.new(
context: "contributions/other", key: "body", rich_text: true,
redirect_to: request.path) do %>Edit content<% end %>
</div>
<% end %>
</section>
<section>
<%= form_with model: [:admin, @content_body] do |form| %>
<p class="mb-2">
<%= form.label :content, @content_body.key.capitalize, class: 'font-bold' %>
</p>
<p>
<%= form.textarea :content, class: "w-full h-96" %>
</p>
<p class="text-right">
<%= link_to 'Cancel', request.path, class: 'btn-md btn-gray' %>
<%= form.submit "Save", class: "ml-2 btn-md btn-blue" %>
</p>
<% end %>
</section>
<% else %>
<section>
<% if @content_body.content.present? %>
<%= markdown_to_html @content_body.content %>
<% else %>
No content yet
<% end %>
</section>
<% end %>
<% end %>

View File

@ -115,7 +115,7 @@
class: "block h-full px-6 py-6 rounded-md" do %>
<h3 class="mb-3.5">Wiki</h3>
<p class="text-gray-600">
Kosmos documentation and knowledge base
Documentation and knowledge base
</p>
<% end %>
</div>

View File

@ -4,7 +4,7 @@
<section>
<% if @invitations_unused.any? %>
<p class="mb-8">
Invite your friends to a Kosmos account by sharing an invitation URL with them:
Invite your friends to register an account by sharing an invitation URL with them:
</p>
<ul class="md:w-3/4">
<% @invitations_unused.each do |invitation| %>

View File

@ -1,6 +1,6 @@
Hi <%= @user.display_name.presence || @user.cn %>,
New invitations have just been added to your Kosmos account, so you can invite more people to our cooperative services:
New invitations have just been added to your account, so you can invite more people to our cooperative services:
<%= invitations_url %>

View File

@ -1,6 +1,6 @@
Hi <%= @user.display_name.presence || @user.cn %>,
You have just granted '<%= @auth.client_id %>' access to your Kosmos Storage, with the following permissions:
You have just granted '<%= @auth.client_id %>' access to your remote storage, with the following permissions:
<% @permissions.each do |p| %>
* <%= p %>

View File

@ -8,7 +8,7 @@
<section>
<h3>Lightning Address</h3>
<p class="mb-6">
Your Kosmos user address is also a
Your user address is also a
<a class="ks-text-link" href="https://lightningaddress.com/" target="_blank">Lightning Address</a>!
The easiest way to receive sats is by just giving out your address:
</p>
@ -32,7 +32,7 @@
<section data-controller="modal" data-action="keydown.esc->modal#close">
<h3>Wallet Apps</h3>
<p>
You can connect various wallet apps to your Kosmos account. This allows
You can connect various wallet apps to your account. This allows
you to both receive and send sats. Any wallet that supports
<a href="https://bluewallet.io/lndhub/" class="ks-text-link" target="_blank">LNDHub</a>
accounts should be able to add/import your account using our setup

View File

@ -3,7 +3,7 @@
<%= render MainSimpleComponent.new do %>
<section>
<p class="mb-6">
Follow and interact with anyone on the open social web, from your Kosmos Mastodon account.
Follow and interact with anyone on the open social web from your Mastodon account.
</p>
</section>
<section data-controller="modal" data-action="keydown.esc->modal#close">

View File

@ -6,7 +6,9 @@
active: current_page?(contributions_donations_path)
) %>
<%= render TabnavLinkComponent.new(
name: editable_content_for("contributions/other", "title", default: "Other"),
name: render(EditableContentComponent.new(
context: "contributions/other", key: "title", default: "Other"
)),
path: contributions_other_path,
active: current_page?(contributions_other_path)
) %>

View File

@ -2,7 +2,7 @@
<%= render MainCompactComponent.new do %>
<p>
Hey there! You were invited to sign up for a Kosmos account by
Hey there! You were invited to sign up for an account by
<strong><%= @invited_by_name %></strong>.
</p>
<p>

View File

@ -1,7 +1,7 @@
class CreateEditableContents < ActiveRecord::Migration[8.0]
def change
create_table :editable_contents do |t|
t.string :path
t.string :context
t.string :key
t.string :lang, default: "en"
t.text :content

View File

@ -65,7 +65,7 @@ ActiveRecord::Schema[8.0].define(version: 2025_05_28_092931) do
end
create_table "editable_contents", force: :cascade do |t|
t.string "path"
t.string "context"
t.string "key"
t.string "lang", default: "en"
t.text "content"