Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/assets/builds/alchemy/admin.css

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions app/components/alchemy/admin/list_filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ module Admin
class ListFilter < ViewComponent::Base
erb_template <<~ERB
<alchemy-list-filter items-selector="<%= items_selector %>" name-attribute="<%= name_attribute %>">
<input type="text" class="js_filter_field" />
<input type="search" class="js_filter_field" />
<alchemy-icon name="search"></alchemy-icon>
<button type="button" class="js_filter_field_clear icon_button">
<button type="reset" class="js_filter_field_clear icon_button">
<alchemy-icon name="close" size="1x"></alchemy-icon>
</button>
</alchemy-list-filter>
Expand Down
15 changes: 15 additions & 0 deletions app/controllers/alchemy/admin/page_definitions_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Alchemy
module Admin
class PageDefinitionsController < ResourcesController
def index
@page_definitions = PageDefinition.all
end

private

def resource_handler
@_resource_handler ||= ::Alchemy::Resource.new(controller_path, alchemy_module, PageDefinition)
end
end
end
end
4 changes: 2 additions & 2 deletions app/javascript/alchemy_admin/components/list_filter.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ class ListFilter extends HTMLElement {
}

get clearButton() {
return this.querySelector('button[type="button"]')
return this.querySelector('button[type="reset"]')
}

get filterField() {
return this.querySelector('input[type="text"]')
return this.querySelector('input[type="search"]')
}

get items() {
Expand Down
1 change: 1 addition & 0 deletions app/models/alchemy/page_definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class PageDefinition
extend ActiveModel::Translation

attribute :name, :string
attribute :image, :string
attribute :elements, default: []
attribute :autogenerate, default: []
attribute :layoutpage, :boolean, default: false
Expand Down
4 changes: 3 additions & 1 deletion app/models/alchemy/permissions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ def alchemy_author_rules
:alchemy_admin_pages,
:alchemy_admin_pictures,
:alchemy_admin_tags,
:alchemy_admin_users
:alchemy_admin_users,
:alchemy_admin_page_definitions
]

# Controller actions
Expand All @@ -108,6 +109,7 @@ def alchemy_author_rules
can :manage, Alchemy::Node
can [:read, :url], Alchemy::Picture
can [:read, :autocomplete], Alchemy::Tag
can :read, Alchemy::PageDefinition
can :edit_content, Alchemy::Page, Alchemy::Page.all do |page|
page.editable_by?(@user)
end
Expand Down
1 change: 1 addition & 0 deletions app/stylesheets/alchemy/admin.scss
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
@use "admin/nodes";
@use "admin/notices";
@use "admin/pagination";
@use "admin/page_definitions";
@use "admin/preview_window";
@use "admin/resource_info";
@use "admin/search";
Expand Down
2 changes: 2 additions & 0 deletions app/stylesheets/alchemy/admin/base.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ html {
box-sizing: border-box;
height: 100%;
font-size: var(--font-size_medium);
scroll-padding-top: calc(var(--top-menu-height) + var(--spacing-2));
scroll-behavior: smooth;

&.turbo-progress-bar::before,
.turbo-progress-bar {
Expand Down
2 changes: 2 additions & 0 deletions app/stylesheets/alchemy/admin/list_filter.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ alchemy-list-filter {
transform: translateY(-50%);
}

input[type="search"],
.js_filter_field {
width: 100%;
padding-left: var(--spacing-7);
Expand All @@ -21,6 +22,7 @@ alchemy-list-filter {
}
}

button[type="reset"],
.js_filter_field_clear {
display: flex;
visibility: hidden;
Expand Down
186 changes: 186 additions & 0 deletions app/stylesheets/alchemy/admin/page_definitions.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
.page-definitions {
align-items: self-start;
position: relative;
display: grid;
grid-template-columns: 400px 1fr;
gap: var(--spacing-2);
grid-template-rows: auto;

h2 {
display: flex;
justify-content: space-between;
align-items: center;
margin: 0;
border-bottom: 2px solid var(--body-background-color);
padding: var(--spacing-4);

small {
font-weight: normal;
font-size: var(--font-size_medium);
}
}

aside {
position: sticky;
top: calc(var(--top-menu-height) + var(--spacing-2));
background-color: var(--panel-background-color);
border-radius: var(--border-radius_medium);
padding: 0;
margin-bottom: var(--spacing-2);

ol {
display: flex;
flex-direction: column;
gap: var(--spacing-2);
list-style-position: outside;
margin: var(--spacing-4);
}

li {
margin: var(--spacing-1) 0;
padding: var(--spacing-1);
}
}

details {
padding: var(--spacing-2) var(--spacing-2);
margin: var(--spacing-2) 0;
background-color: var(--element-header-bg-color);
border-radius: var(--border-radius_medium);
border: 1px solid hsla(0, 0%, 45%, 0.15);

&:last-child {
margin-bottom: var(--spacing-4);
}

summary {
display: flex;
align-items: center;
justify-content: start;
padding: var(--spacing-1) 0;
gap: var(--spacing-1);
transition: margin var(--transition-duration) ease-out;

header {
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
gap: var(--spacing-1);

.label {
margin-left: auto;
font-weight: normal;

&.usage:before {
content: "x";
}
}
}

&:before {
content: "▸";
display: flex;
align-items: center;
justify-content: center;
width: var(--spacing-4);
height: var(--spacing-4);
}
}

&[open] {
> summary {
&:before {
content: "▾";
}

margin-bottom: var(
--spacing-1
); // necessary for the detail opening transition to work
}
}

> div {
padding: var(--spacing-1) 0 var(--spacing-1) var(--spacing-5);
}

ol {
list-style-type: square;
margin: var(--spacing-4) 0;
padding-left: var(--spacing-3);

li {
margin: var(--spacing-6) 0;

&:only-child {
margin-top: 0;
margin-bottom: 0;
}

header {
gap: var(--spacing-2);
}

p.description {
margin: var(--spacing-2) 0;
padding: var(--spacing-2);
}
}
}

details {
padding-left: var(--spacing-1);
background-color: hsla(0, 0%, 45%, 0.05);
}
}

.page-definition {
display: flex;
flex-direction: column;
justify-content: space-between;
gap: var(--spacing-4);
margin-bottom: var(--spacing-2);
background-color: var(--panel-background-color);
border-radius: var(--border-radius_medium);

> alchemy-message,
> .labels,
> .image,
> .elements,
> p {
display: block;
margin: 0 var(--spacing-4);
}

h3 {
margin-top: var(--spacing-2);
margin-bottom: var(--spacing-4);
padding-left: var(--spacing-1);
font-weight: var(--font-weight_normal);
}

.image img {
width: auto;
max-width: 100%;
max-height: 160px;
border-radius: var(--border-radius_medium);
}

.elements {
display: flex;
flex-direction: column;
margin-bottom: 0;
}

p {
padding: var(--spacing-4);
background-color: hsla(0, 0%, 45%, 0.05);
border-radius: var(--border-radius_medium);
}

.label {
padding: var(--spacing-0) var(--spacing-2);
background-color: hsla(0, 0%, 45%, 0.15);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<% element = Alchemy::ElementDefinition.get(element_name) %>
<% if element %>
<details>
<summary>
<header>
<span class="icon element">
<%= element.icon_file %>
</span>
<%= Alchemy::Element.display_name_for(element.name) %>
<small class="label usage">
<%= Alchemy::Element.named(element.name).count %>
</small>
</header>
</summary>
<div>
<% if element.unique %>
<sl-tooltip content="<%= Alchemy.t(:unique, scope: ["admin", "hints", Alchemy::ElementDefinition.model_name.i18n_key]) %>">
<small class="label">
<%= Alchemy::Element.human_attribute_name(:unique) %>
</small>
</sl-tooltip>
<% end %>
<% if element.fixed %>
<sl-tooltip content="<%= Alchemy.t(:fixed, scope: ["admin", "hints", Alchemy::ElementDefinition.model_name.i18n_key]) %>">
<small class="label">
<%= Alchemy::Element.human_attribute_name(:fixed) %>
</small>
</sl-tooltip>
<% end %>
<% if element.deprecated %>
<alchemy-message type="info">
<%= element.deprecation_notice %>
</alchemy-message>
<% end %>
<% if element.has_hint? %>
<p class="description"><%= element.hint %></p>
<% end %>
<% if element.ingredients.any? %>
<ol>
<%= render collection: element.ingredients.select { !_1.group }, partial: "ingredient_definition", locals: {element_name: element_name} %>

<% element.ingredients.select { _1.group }.group_by { _1.group }.each do |group, ingredients| %>
<h3>
<%= Alchemy.t(
group,
scope: "element_groups.#{element.name}",
default: Alchemy.t("element_groups.#{group}", default: group.humanize)
) %>
</h3>
<ol>
<%= render collection: ingredients, partial: "ingredient_definition", locals: {element_name: element_name} %>
</ol>
<% end %>
</ol>
<% end %>
<%= render collection: element.nestable_elements, partial: "element_definition", as: "element_name" %>
</div>
</details>
<% end %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<li>
<header>
<strong><%= Alchemy::Ingredient.translated_label_for(ingredient_definition.role, element_name) %></strong>
<small><%= Alchemy::Ingredient.normalize_type(ingredient_definition.type).constantize.model_name.human %></small>

Check warning

Code scanning / Brakeman

Unsafe reflection method constantize called on model attribute. Warning

Unsafe reflection method constantize called on model attribute.
</header>
<% if ingredient_definition.has_hint? %>
<p class="description"><%= sanitize ingredient_definition.hint %></p>
<% end %>
</li>
Loading
Loading