Skip to content

Commit 127457f

Browse files
committed
Add page definitions module
1 parent 2b0b699 commit 127457f

File tree

19 files changed

+432
-6
lines changed

19 files changed

+432
-6
lines changed

app/assets/builds/alchemy/admin.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/components/alchemy/admin/list_filter.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ module Admin
2121
class ListFilter < ViewComponent::Base
2222
erb_template <<~ERB
2323
<alchemy-list-filter items-selector="<%= items_selector %>" name-attribute="<%= name_attribute %>">
24-
<input type="text" class="js_filter_field" />
24+
<input type="search" class="js_filter_field" />
2525
<alchemy-icon name="search"></alchemy-icon>
26-
<button type="button" class="js_filter_field_clear icon_button">
26+
<button type="reset" class="js_filter_field_clear icon_button">
2727
<alchemy-icon name="close" size="1x"></alchemy-icon>
2828
</button>
2929
</alchemy-list-filter>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module Alchemy
2+
module Admin
3+
class PageDefinitionsController < ResourcesController
4+
def index
5+
@page_definitions = PageDefinition.all
6+
end
7+
8+
private
9+
10+
def resource_handler
11+
@_resource_handler ||= ::Alchemy::Resource.new(controller_path, alchemy_module, PageDefinition)
12+
end
13+
end
14+
end
15+
end

app/javascript/alchemy_admin/components/list_filter.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,11 @@ class ListFilter extends HTMLElement {
4949
}
5050

5151
get clearButton() {
52-
return this.querySelector('button[type="button"]')
52+
return this.querySelector('button[type="reset"]')
5353
}
5454

5555
get filterField() {
56-
return this.querySelector('input[type="text"]')
56+
return this.querySelector('input[type="search"]')
5757
}
5858

5959
get items() {

app/models/alchemy/permissions.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,8 @@ def alchemy_author_rules
8989
:alchemy_admin_pages,
9090
:alchemy_admin_pictures,
9191
:alchemy_admin_tags,
92-
:alchemy_admin_users
92+
:alchemy_admin_users,
93+
:alchemy_admin_page_definitions
9394
]
9495

9596
# Controller actions
@@ -108,6 +109,7 @@ def alchemy_author_rules
108109
can :manage, Alchemy::Node
109110
can [:read, :url], Alchemy::Picture
110111
can [:read, :autocomplete], Alchemy::Tag
112+
can :read, Alchemy::PageDefinition
111113
can :edit_content, Alchemy::Page, Alchemy::Page.all do |page|
112114
page.editable_by?(@user)
113115
end

app/stylesheets/alchemy/admin.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
@use "admin/nodes";
3030
@use "admin/notices";
3131
@use "admin/pagination";
32+
@use "admin/page_definitions";
3233
@use "admin/preview_window";
3334
@use "admin/resource_info";
3435
@use "admin/search";

app/stylesheets/alchemy/admin/base.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ html {
44
box-sizing: border-box;
55
height: 100%;
66
font-size: var(--font-size_medium);
7+
scroll-padding-top: calc(var(--top-menu-height) + var(--spacing-2));
8+
scroll-behavior: smooth;
79

810
&.turbo-progress-bar::before,
911
.turbo-progress-bar {

app/stylesheets/alchemy/admin/list_filter.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ alchemy-list-filter {
99
transform: translateY(-50%);
1010
}
1111

12+
input[type="search"],
1213
.js_filter_field {
1314
width: 100%;
1415
padding-left: var(--spacing-7);
@@ -21,6 +22,7 @@ alchemy-list-filter {
2122
}
2223
}
2324

25+
button[type="reset"],
2426
.js_filter_field_clear {
2527
display: flex;
2628
visibility: hidden;
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
.page-definitions {
2+
align-items: self-start;
3+
position: relative;
4+
display: grid;
5+
grid-template-columns: 400px 1fr;
6+
gap: var(--spacing-2);
7+
grid-template-rows: auto;
8+
9+
h2 {
10+
display: flex;
11+
justify-content: space-between;
12+
align-items: center;
13+
margin: 0;
14+
border-bottom: 2px solid var(--body-background-color);
15+
padding: var(--spacing-4);
16+
17+
small {
18+
font-weight: normal;
19+
font-size: var(--font-size_medium);
20+
}
21+
}
22+
23+
aside {
24+
position: sticky;
25+
top: calc(var(--top-menu-height) + var(--spacing-2));
26+
background-color: var(--panel-background-color);
27+
border-radius: var(--border-radius_medium);
28+
padding: 0;
29+
margin-bottom: var(--spacing-2);
30+
31+
ol {
32+
display: flex;
33+
flex-direction: column;
34+
gap: var(--spacing-2);
35+
list-style-position: outside;
36+
margin: var(--spacing-4);
37+
}
38+
39+
li {
40+
margin: var(--spacing-1) 0;
41+
padding: var(--spacing-1);
42+
}
43+
}
44+
45+
details {
46+
padding: var(--spacing-2) var(--spacing-2);
47+
margin: var(--spacing-2) 0;
48+
background-color: var(--element-header-bg-color);
49+
border-radius: var(--border-radius_medium);
50+
border: 1px solid hsla(0, 0%, 45%, 0.15);
51+
52+
&:last-child {
53+
margin-bottom: var(--spacing-4);
54+
}
55+
56+
summary {
57+
display: flex;
58+
align-items: center;
59+
justify-content: start;
60+
padding: var(--spacing-1) 0;
61+
gap: var(--spacing-1);
62+
transition: margin var(--transition-duration) ease-out;
63+
64+
header {
65+
display: flex;
66+
width: 100%;
67+
align-items: center;
68+
justify-content: space-between;
69+
gap: var(--spacing-1);
70+
71+
.label {
72+
margin-left: auto;
73+
font-weight: normal;
74+
75+
&.usage:before {
76+
content: "x";
77+
}
78+
}
79+
}
80+
81+
&:before {
82+
content: "";
83+
display: flex;
84+
align-items: center;
85+
justify-content: center;
86+
width: var(--spacing-4);
87+
height: var(--spacing-4);
88+
}
89+
}
90+
91+
&[open] {
92+
> summary {
93+
&:before {
94+
content: "";
95+
}
96+
97+
margin-bottom: var(
98+
--spacing-1
99+
); // necessary for the detail opening transition to work
100+
}
101+
}
102+
103+
> div {
104+
padding: var(--spacing-1) 0 var(--spacing-1) var(--spacing-5);
105+
}
106+
107+
ol {
108+
list-style-type: square;
109+
margin: var(--spacing-4) 0;
110+
padding-left: var(--spacing-3);
111+
112+
li {
113+
margin: var(--spacing-6) 0;
114+
115+
&:only-child {
116+
margin-top: 0;
117+
margin-bottom: 0;
118+
}
119+
120+
header {
121+
gap: var(--spacing-2);
122+
}
123+
124+
p.description {
125+
margin: var(--spacing-2) 0;
126+
padding: var(--spacing-2);
127+
}
128+
}
129+
}
130+
131+
details {
132+
padding-left: var(--spacing-1);
133+
background-color: hsla(0, 0%, 45%, 0.05);
134+
}
135+
}
136+
137+
.page-definition {
138+
display: flex;
139+
flex-direction: column;
140+
justify-content: space-between;
141+
gap: var(--spacing-4);
142+
margin-bottom: var(--spacing-2);
143+
background-color: var(--panel-background-color);
144+
border-radius: var(--border-radius_medium);
145+
146+
> alchemy-message,
147+
> .labels,
148+
> .elements,
149+
> p {
150+
display: block;
151+
margin: 0 var(--spacing-4);
152+
}
153+
154+
h3 {
155+
margin-top: var(--spacing-2);
156+
margin-bottom: var(--spacing-4);
157+
padding-left: var(--spacing-1);
158+
font-weight: var(--font-weight_normal);
159+
}
160+
161+
.elements {
162+
display: flex;
163+
flex-direction: column;
164+
margin-bottom: 0;
165+
}
166+
167+
p {
168+
padding: var(--spacing-4);
169+
background-color: hsla(0, 0%, 45%, 0.05);
170+
border-radius: var(--border-radius_medium);
171+
}
172+
173+
.label {
174+
padding: var(--spacing-0) var(--spacing-2);
175+
background-color: hsla(0, 0%, 45%, 0.15);
176+
}
177+
}
178+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<% element = Alchemy::ElementDefinition.get(element_name) %>
2+
<% if element %>
3+
<details>
4+
<summary>
5+
<header>
6+
<span class="icon element">
7+
<%= element.icon_file %>
8+
</span>
9+
<%= Alchemy::Element.display_name_for(element.name) %>
10+
<small class="label usage">
11+
<%= Alchemy::Element.named(element.name).count %>
12+
</small>
13+
</header>
14+
</summary>
15+
<div>
16+
<% if element.unique %>
17+
<sl-tooltip content="<%= Alchemy.t(:unique, scope: ["admin", "hints", Alchemy::ElementDefinition.model_name.i18n_key]) %>">
18+
<small class="label">
19+
<%= Alchemy::Element.human_attribute_name(:unique) %>
20+
</small>
21+
</sl-tooltip>
22+
<% end %>
23+
<% if element.fixed %>
24+
<sl-tooltip content="<%= Alchemy.t(:fixed, scope: ["admin", "hints", Alchemy::ElementDefinition.model_name.i18n_key]) %>">
25+
<small class="label">
26+
<%= Alchemy::Element.human_attribute_name(:fixed) %>
27+
</small>
28+
</sl-tooltip>
29+
<% end %>
30+
<% if element.deprecated %>
31+
<alchemy-message type="info">
32+
<%= element.deprecation_notice %>
33+
</alchemy-message>
34+
<% end %>
35+
<% if element.has_hint? %>
36+
<p class="description"><%= element.hint %></p>
37+
<% end %>
38+
<% if element.ingredients.any? %>
39+
<ol>
40+
<%= render collection: element.ingredients.select { !_1.group }, partial: "ingredient_definition", locals: {element_name: element_name} %>
41+
42+
<% element.ingredients.select { _1.group }.group_by { _1.group }.each do |group, ingredients| %>
43+
<h3>
44+
<%= Alchemy.t(
45+
group,
46+
scope: "element_groups.#{element.name}",
47+
default: Alchemy.t("element_groups.#{group}", default: group.humanize)
48+
) %>
49+
</h3>
50+
<ol>
51+
<%= render collection: ingredients, partial: "ingredient_definition", locals: {element_name: element_name} %>
52+
</ol>
53+
<% end %>
54+
</ol>
55+
<% end %>
56+
<%= render collection: element.nestable_elements, partial: "element_definition", as: "element_name" %>
57+
</div>
58+
</details>
59+
<% end %>

0 commit comments

Comments
 (0)