From 6abbe07ad84ba4a2a67b771fe8e07049d64c2d3b Mon Sep 17 00:00:00 2001 From: Mattia Roccoberton Date: Thu, 27 Apr 2023 16:54:36 +0200 Subject: [PATCH 1/2] feat: content pages --- README.md | 20 ++++++++++++++++++-- lib/tiny_admin/router.rb | 10 ++++++---- lib/tiny_admin/settings.rb | 24 +++++++++++++++++------- lib/tiny_admin/views/basic_layout.rb | 2 ++ lib/tiny_admin/views/pages/content.rb | 17 +++++++++++++++++ spec/dummy_rails/config/tiny_admin.yml | 6 ++++++ spec/features/pages/content_spec.rb | 17 +++++++++++++++++ 7 files changed, 83 insertions(+), 13 deletions(-) create mode 100644 lib/tiny_admin/views/pages/content.rb create mode 100644 spec/features/pages/content_spec.rb diff --git a/README.md b/README.md index 77397cd..2951101 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Tiny Admin -[![Gem Version](https://badge.fury.io/rb/tiny_admin.svg)](https://badge.fury.io/rb/tiny_admin) [![Linters](https://github.com/blocknotes/tiny_admin/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/tiny_admin/actions/workflows/linters.yml) [![Specs Rails 7.0](https://github.com/blocknotes/tiny_admin/actions/workflows/specs_rails_70.yml/badge.svg)](https://github.com/blocknotes/tiny_admin/actions/workflows/specs_rails_70.yml) +[![Gem Version](https://badge.fury.io/rb/tiny_admin.svg)](https://badge.fury.io/rb/tiny_admin) [![Linters](https://github.com/blocknotes/tiny_admin/actions/workflows/linters.yml/badge.svg)](https://github.com/blocknotes/tiny_admin/actions/workflows/linters.yml) [![Specs](https://github.com/blocknotes/tiny_admin/actions/workflows/specs.yml/badge.svg)](https://github.com/blocknotes/tiny_admin/actions/workflows/specs.yml) A compact and composable dashboard component for Ruby. @@ -51,6 +51,7 @@ Plugin available: Pages available: - **Root**: define how to present the content in the main page of the interface; +- **Content**: define how to present page with inline content; - **PageNotFound**: define how to present pages not found; - **RecordNotFound**: define how to present record not found page; - **SimpleAuthLogin**: define how to present the login form for SimpleAuth plugin; @@ -122,9 +123,24 @@ authentication: - `slug` (String): section reference identifier; - `name` (String): section's title; -- `type` (String): the type of section: `url`, `page` or `resource`; +- `type` (String): the type of section: `content`, `page`, `resource` or `url`; - other properties depends on the section's type. +For _content_ sections: + +- `content` (String): the HTML content to present. + +Example: + +```yml +slug: test-content +name: Test content +type: content +content: > +

Test content!

+

Some test content

+``` + For _url_ sections: - `url` (String): the URL to load when clicking on the section's menu item; diff --git a/lib/tiny_admin/router.rb b/lib/tiny_admin/router.rb index 496f002..02fd63c 100644 --- a/lib/tiny_admin/router.rb +++ b/lib/tiny_admin/router.rb @@ -29,8 +29,8 @@ class Router < BasicApp r.redirect settings.root_path end - context.pages.each do |slug, data| - setup_page_route(r, slug, data) + context.pages.each do |slug, page_data| + setup_page_route(r, slug, page_data) end context.resources.each do |slug, options| @@ -60,10 +60,12 @@ def root_route(router) end end - def setup_page_route(router, slug, page_class) + def setup_page_route(router, slug, page_data) router.get slug do context.slug = slug - render_page prepare_page(page_class) + page = prepare_page(page_data[:class]) + page.update_attributes(content: page_data[:content]) if page_data[:content] + render_page page end end diff --git a/lib/tiny_admin/settings.rb b/lib/tiny_admin/settings.rb index fb91b12..57589b2 100644 --- a/lib/tiny_admin/settings.rb +++ b/lib/tiny_admin/settings.rb @@ -12,6 +12,7 @@ class Settings %i[components head] => Views::Components::Head, %i[components navbar] => Views::Components::Navbar, %i[components pagination] => Views::Components::Pagination, + %i[content_page] => Views::Pages::Content, %i[helper_class] => Support, %i[page_not_found] => Views::Pages::PageNotFound, %i[record_not_found] => Views::Pages::RecordNotFound, @@ -23,6 +24,7 @@ class Settings attr_accessor :authentication, :components, + :content_page, :extra_styles, :helper_class, :page_not_found, @@ -83,7 +85,7 @@ def convert_value(key, value) def prepare_navbar(sections, logout:) items = sections.each_with_object({}) do |section, list| unless section.is_a?(Hash) - section_class = Object.const_get(section) + section_class = section.is_a?(String) ? Object.const_get(section) : section next unless section_class.respond_to?(:to_h) section = section_class.to_h @@ -91,26 +93,30 @@ def prepare_navbar(sections, logout:) slug = section[:slug].to_s case section[:type]&.to_sym - when :url - list[slug] = add_url_section(slug, section) + when :content + list[slug] = add_content_section(slug, section) when :page list[slug] = add_page_section(slug, section) when :resource list[slug] = add_resource_section(slug, section) + when :url + list[slug] = add_url_section(slug, section) end end items['auth/logout'] = logout if logout items end - def add_url_section(_slug, section) - section.slice(:name, :options).tap { _1[:path] = section[:url] } + def add_content_section(slug, section) + context.pages[slug] = { class: content_page, content: section[:content] } + { name: section[:name], path: route_for(slug), class: content_page } end def add_page_section(slug, section) page = section[:page] - context.pages[slug] = page.is_a?(String) ? Object.const_get(page) : page - { name: section[:name], path: route_for(slug), class: context.pages[slug] } + page_class = page.is_a?(String) ? Object.const_get(page) : page + context.pages[slug] = { class: page_class } + { name: section[:name], path: route_for(slug), class: page_class } end def add_resource_section(slug, section) @@ -125,5 +131,9 @@ def add_resource_section(slug, section) hidden = section[:options] && (section[:options].include?(:hidden) || section[:options].include?('hidden')) { name: section[:name], path: route_for(slug) } unless hidden end + + def add_url_section(_slug, section) + section.slice(:name, :options).tap { _1[:path] = section[:url] } + end end end diff --git a/lib/tiny_admin/views/basic_layout.rb b/lib/tiny_admin/views/basic_layout.rb index aeef8e3..21fc0fe 100644 --- a/lib/tiny_admin/views/basic_layout.rb +++ b/lib/tiny_admin/views/basic_layout.rb @@ -5,6 +5,8 @@ module Views class BasicLayout < Phlex::HTML include Utils + attr_accessor :content + def update_attributes(attributes) attributes.each do |key, value| send("#{key}=", value) diff --git a/lib/tiny_admin/views/pages/content.rb b/lib/tiny_admin/views/pages/content.rb new file mode 100644 index 0000000..e8cf913 --- /dev/null +++ b/lib/tiny_admin/views/pages/content.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module TinyAdmin + module Views + module Pages + class Content < DefaultLayout + def template + super do + div(class: 'content') { + unsafe_raw(content) + } + end + end + end + end + end +end diff --git a/spec/dummy_rails/config/tiny_admin.yml b/spec/dummy_rails/config/tiny_admin.yml index e06d0df..57029ac 100644 --- a/spec/dummy_rails/config/tiny_admin.yml +++ b/spec/dummy_rails/config/tiny_admin.yml @@ -20,6 +20,12 @@ sections: name: Sample page type: page page: SamplePage + - slug: test-content + name: Test content + type: content + content: > +

Test content!

+

Some test content

- slug: authors name: Authors type: resource diff --git a/spec/features/pages/content_spec.rb b/spec/features/pages/content_spec.rb new file mode 100644 index 0000000..458b183 --- /dev/null +++ b/spec/features/pages/content_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'dummy_rails_app' +require 'rails_helper' + +RSpec.describe 'Content', type: :feature do + before do + visit '/admin' + log_in + end + + it 'loads a test content page', :aggregate_failures do + click_link('Test content') + expect(page).to have_current_path('/admin/test-content') + expect(page).to have_css('p', text: 'Some test content') + end +end From ce3865d6c4488df1277d7ca55e175b12c82118c3 Mon Sep 17 00:00:00 2001 From: Mattia Roccoberton Date: Thu, 27 Apr 2023 17:00:39 +0200 Subject: [PATCH 2/2] doc: improve sample features extra app --- extra/sample_features_app/admin/items.rb | 22 +++++++++++++------ .../admin/sample_content_page.rb | 10 +++++++++ .../sample_features_app/admin/sample_page.rb | 20 ++++++++++++----- .../sample_features_app/admin/sample_page2.rb | 20 ++++++++++++----- extra/sample_features_app/tiny_admin.yml | 2 ++ 5 files changed, 55 insertions(+), 19 deletions(-) create mode 100644 extra/sample_features_app/admin/sample_content_page.rb diff --git a/extra/sample_features_app/admin/items.rb b/extra/sample_features_app/admin/items.rb index 908a524..190a1a0 100644 --- a/extra/sample_features_app/admin/items.rb +++ b/extra/sample_features_app/admin/items.rb @@ -47,14 +47,22 @@ def show_title(_record) "Item" end end + + module ItemSection + def to_h + { + slug: 'items', + name: 'Items', + type: :resource, + model: Item, + repository: ItemsRepo + } + end + + module_function :to_h + end end TinyAdmin.configure do |settings| - (settings.sections ||= []).push( - slug: 'items', - name: 'Items', - type: :resource, - model: Admin::Item, - repository: Admin::ItemsRepo - ) + (settings.sections ||= []).push(Admin::ItemSection) end diff --git a/extra/sample_features_app/admin/sample_content_page.rb b/extra/sample_features_app/admin/sample_content_page.rb new file mode 100644 index 0000000..96fa8b3 --- /dev/null +++ b/extra/sample_features_app/admin/sample_content_page.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +TinyAdmin.configure do |settings| + (settings.sections ||= []).push( + slug: 'test-content', + name: 'Test content', + type: :content, + content: 'This is a test content page' + ) +end diff --git a/extra/sample_features_app/admin/sample_page.rb b/extra/sample_features_app/admin/sample_page.rb index 51e9362..087b6ef 100644 --- a/extra/sample_features_app/admin/sample_page.rb +++ b/extra/sample_features_app/admin/sample_page.rb @@ -9,13 +9,21 @@ def template end end end + + module SampleSection + def to_h + { + slug: 'sample-page', + name: 'Sample Page', + type: :page, + page: SamplePage + } + end + + module_function :to_h + end end TinyAdmin.configure do |settings| - (settings.sections ||= []).push( - slug: 'sample-page', - name: 'Sample Page', - type: :page, - page: Admin::SamplePage - ) + (settings.sections ||= []).push(Admin::SampleSection) end diff --git a/extra/sample_features_app/admin/sample_page2.rb b/extra/sample_features_app/admin/sample_page2.rb index 47d57c0..e7ae3d3 100644 --- a/extra/sample_features_app/admin/sample_page2.rb +++ b/extra/sample_features_app/admin/sample_page2.rb @@ -9,13 +9,21 @@ def template end end end + + module SampleSection2 + def to_h + { + slug: 'sample-page-2', + name: 'Sample Page 2', + type: :page, + page: SamplePage2 + } + end + + module_function :to_h + end end TinyAdmin.configure do |settings| - (settings.sections ||= []).push( - slug: 'sample-page-2', - name: 'Sample Page 2', - type: :page, - page: Admin::SamplePage2 - ) + (settings.sections ||= []).push(Admin::SampleSection2) end diff --git a/extra/sample_features_app/tiny_admin.yml b/extra/sample_features_app/tiny_admin.yml index 2f2b71f..58be31a 100644 --- a/extra/sample_features_app/tiny_admin.yml +++ b/extra/sample_features_app/tiny_admin.yml @@ -2,6 +2,8 @@ root_path: '/' root: redirect: sample-page +scripts: + - src: https://cdn.jsdelivr.net/npm/chart.js extra_styles: > .navbar { background-color: var(--bs-teal);