PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.9.5
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.9.5
4.9.5 4.9.4 4.9.3 4.9.2 4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 All 203 releases
betterdocs / react-src / gutenberg / blocks / reading-time / src / cssProperties.js

cssProperties.js in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.9.5, at react-src/gutenberg/blocks/reading-time/src/cssProperties.js

235 lines 11.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { addProperty } from "../../../helpers/helper";
2 import {
3 WRAPPER_MARGIN,
4 WRAPPER_BACKGROUND,
5 WRAPPER_BORDER,
6 WRAPPER_PADDING,
7 READING_TIME_SIZE,
8 AI_ACTIONS_PADDING,
9 AI_ACTIONS_BACKGROUND,
10 AI_ACTIONS_BORDER,
11 AI_ACTIONS_ICON_SIZE,
12 LISTEN_PADDING,
13 LISTEN_BACKGROUND,
14 LISTEN_BORDER,
15 LISTEN_ICON_SIZE
16 } from "./constants";
17 import { typoPrefix_reading_time, typoPrefix_ai_actions, typoPrefix_listen } from "./typographyPrefixConstants";
18
19 export default ( { blockId } ) => {
20 const wrapperSelector = `.${blockId} .reading-time.betterdocs`;
21 const readingTimeSelector = `.${blockId} .reading-time.betterdocs p`;
22 const readingTimeIconSelector = `.${blockId} .reading-time p svg`;
23
24 // Margin is the one Wrapper control that moved off the pill and onto the meta
25 // row. Inside the row `.betterdocs-doc-meta-start > *` zeroes child block
26 // margins with !important — it has to, or a pill with a bottom margin inflates
27 // the flex line and knocks the button 12px off centre — so a margin left on
28 // the pill would silently do nothing. On the row it still means what it always
29 // did: the gap between this block and the article body.
30 const metaRowSelector = `.${blockId} .betterdocs-doc-meta`;
31
32 // Both halves of the split button, so background, padding and border stay
33 // symmetrical across the divider between them.
34 //
35 // The `.betterdocs-ai-actions` in the middle is not decoration — it is the
36 // third class that wins the cascade. The Customizer now ships real defaults
37 // for this button (Admin/Customizer/Defaults.php) and writes them at two
38 // classes, `.betterdocs-content-area .betterdocs-ai-actions-primary`. Its
39 // stylesheet prints on `wp_head` at 10, after the file this block's CSS is
40 // enqueued into, so at equal specificity the site-wide value would win and
41 // every per-instance control here would look broken inside a classic
42 // single-doc template. Three classes settles it without !important.
43 const aiWrapperSelector = `.${blockId} .betterdocs-ai-actions`;
44 // The wrapper element itself, at three classes. The block's root div and the
45 // button wrapper both carry `blockId` (Blocks\ReadingTime appends it to the
46 // button's class list), so `.id .id.betterdocs-ai-actions` matches the same
47 // single element `.id .betterdocs-ai-actions` would — but outranks the
48 // Customizer's two-class site-wide rules, which otherwise win on order.
49 const aiWrapperSelectorOwn = `.${blockId} .${blockId}.betterdocs-ai-actions`;
50 const aiButtonSelector = `${aiWrapperSelector} .betterdocs-ai-actions-primary, ${aiWrapperSelector} .betterdocs-ai-actions-toggle`;
51 const aiLabelSelector = `${aiWrapperSelector} .betterdocs-ai-actions-label`;
52 const aiIconSelector = `${aiWrapperSelector} .betterdocs-ai-actions-primary svg, ${aiWrapperSelector} .betterdocs-ai-actions-toggle svg`;
53
54 // The Listen pill. One element rather than two halves, so background, border
55 // and radius have one home — but the same three-class rule applies for the same
56 // reason: the Customizer ships real defaults for this pill
57 // (Admin/Customizer/Defaults.php) and writes them at two classes, in a
58 // stylesheet that prints on `wp_head` at 10 — after the file this block's CSS
59 // is enqueued into. At equal specificity the site-wide value would win and
60 // every per-instance control here would look broken inside a classic
61 // single-doc template.
62 //
63 // The block's root div and the pill both carry `blockId`
64 // (Blocks\ReadingTime appends it to the pill's class list), so
65 // `.id .id.betterdocs-listen` matches the same single element
66 // `.id .betterdocs-listen` would — while outranking those two-class rules.
67 const listenSelector = `.${blockId} .betterdocs-listen`;
68 const listenSelectorOwn = `.${blockId} .${blockId}.betterdocs-listen`;
69 // Padding, background and the corner all land on the trigger: it is the only
70 // element in flow, so it is what gives the pill its size. The player is
71 // absolutely positioned with `inset-block: 0` and inherits that height, which
72 // is what keeps the design's promise that nothing below the pill moves.
73 const listenTriggerSelector = `${listenSelector} .betterdocs-listen-trigger`;
74 const listenLabelSelector = `${listenSelector} .betterdocs-listen-label`;
75 const listenIconSelector = `${listenSelector} .betterdocs-listen-trigger svg`;
76 // The accent is a custom property on the player, inherited by the play button,
77 // the progress fill and the scrubber's ring. Its own selector, with nothing
78 // else written to it: the helper that emits a custom property omits the
79 // trailing semicolon, so a second declaration joined after it would run into
80 // the value and both would be dropped.
81 const listenAccentSelector = `${listenSelector} .betterdocs-listen-player`;
82
83 return [
84 addProperty('dimension', WRAPPER_PADDING, {
85 args: { styleFor: "padding" },
86 cssSelector: wrapperSelector
87 }),
88 addProperty('dimension', WRAPPER_MARGIN, {
89 args: { styleFor: "margin" },
90 cssSelector: metaRowSelector
91 }),
92 addProperty('background', WRAPPER_BACKGROUND, {
93 args: { noOverlay: true },
94 cssSelector: wrapperSelector
95 }),
96 addProperty('border', WRAPPER_BORDER, {
97 args: { noShadow: true },
98 cssSelector:wrapperSelector
99 }),
100 addProperty('color', 'readingTimeTextColor', {
101 cssSelector:readingTimeSelector
102 }),
103 addProperty('typography', typoPrefix_reading_time, {
104 args: {
105 defaultFontSize: 14,
106 prefixConstant: typoPrefix_reading_time,
107 },
108 cssSelector: readingTimeSelector
109 }),
110 addProperty('responsive', READING_TIME_SIZE, {
111 args: { property: "height", controlName: READING_TIME_SIZE },
112 cssSelector: readingTimeIconSelector
113 }),
114
115 addProperty('dimension', AI_ACTIONS_PADDING, {
116 args: { styleFor: "padding" },
117 cssSelector: aiButtonSelector
118 }),
119 addProperty('background', AI_ACTIONS_BACKGROUND, {
120 args: { noOverlay: true },
121 cssSelector: aiButtonSelector
122 }),
123 // Border on the WRAPPER, not on the halves. A border drawn on each half
124 // meets its neighbour at the divider and reads as a double line down the
125 // middle of the pill — the stylesheet paints the surface on the wrapper
126 // and leaves both halves `border: 0` for exactly that reason.
127 addProperty('border', AI_ACTIONS_BORDER, {
128 args: { noShadow: true },
129 cssSelector: aiWrapperSelectorOwn
130 }),
131 // …but the radius still has to reach the halves. The wrapper cannot clip
132 // them (the dropdown is absolutely positioned, so `overflow: hidden`
133 // would cut it off), so each half carries its own outer corners and a
134 // radius set only on the wrapper leaves the pill's ends square. Same
135 // attributes, second selector — the stylesheet pins the two inner
136 // corners to 0, so only the outer pair actually moves.
137 addProperty('dimension', `${AI_ACTIONS_BORDER}Rds_`, {
138 id: `${AI_ACTIONS_BORDER}Rds_halves`,
139 args: { styleFor: 'border-radius' },
140 cssSelector: aiButtonSelector
141 }),
142 addProperty('color', 'aiActionsTextColor', {
143 cssSelector: aiLabelSelector
144 }),
145 // Same two selectors the icon-size control uses: every icon is stroked
146 // with currentColor, so `color` on the svg is the whole job.
147 addProperty('color', 'aiActionsIconColor', {
148 cssSelector: aiIconSelector
149 }),
150 addProperty('typography', typoPrefix_ai_actions, {
151 args: {
152 defaultFontSize: 14,
153 prefixConstant: typoPrefix_ai_actions,
154 },
155 cssSelector: aiLabelSelector
156 }),
157 // One control, two declarations. The stylesheet sizes these icons on both
158 // axes, so setting height alone would stretch them. useStyleSheets keys
159 // the property list by `id`, so the second entry needs its own — while
160 // `args.controlName` keeps both reading the same attribute.
161 addProperty('responsive', AI_ACTIONS_ICON_SIZE, {
162 args: { property: "height", controlName: AI_ACTIONS_ICON_SIZE },
163 cssSelector: aiIconSelector
164 }),
165 addProperty('responsive', AI_ACTIONS_ICON_SIZE, {
166 id: `${AI_ACTIONS_ICON_SIZE}_width`,
167 args: { property: "width", controlName: AI_ACTIONS_ICON_SIZE },
168 cssSelector: aiIconSelector
169 }),
170
171 addProperty('dimension', LISTEN_PADDING, {
172 args: { styleFor: "padding" },
173 cssSelector: listenTriggerSelector
174 }),
175 // Background on the PILL, not on the trigger — unlike padding above, and
176 // matching what Elementor and dynamic.css.php both do. The trigger goes to
177 // `opacity: 0` the instant the player opens, so a fill painted there is
178 // visible only while collapsed and the expanded player would ignore the
179 // author's colour entirely.
180 addProperty('background', LISTEN_BACKGROUND, {
181 args: { noOverlay: true },
182 cssSelector: listenSelectorOwn
183 }),
184 // Border on the PILL, not on the trigger: the trigger fills the pill, and a
185 // border on both would be drawn twice at the same place — once under the
186 // `overflow: hidden` clip and once on top of it, which on a subpixel
187 // boundary shows as a doubled edge.
188 addProperty('border', LISTEN_BORDER, {
189 args: { noShadow: true },
190 cssSelector: listenSelectorOwn
191 }),
192 // …and the radius also has to reach the trigger, which states its own
193 // corner so a theme's `button { border-radius }` cannot square it off. Same
194 // attributes, second selector; useStyleSheets keys the property list by
195 // `id`, so this needs one of its own.
196 addProperty('dimension', `${LISTEN_BORDER}Rds_`, {
197 id: `${LISTEN_BORDER}Rds_trigger`,
198 args: { styleFor: 'border-radius' },
199 cssSelector: listenTriggerSelector
200 }),
201 addProperty('color', 'listenTextColor', {
202 cssSelector: listenLabelSelector
203 }),
204 addProperty('color', 'listenIconColor', {
205 cssSelector: listenIconSelector
206 }),
207 addProperty('color', 'listenAccentColor', {
208 args: { customProperty: '--bd-listen-accent' },
209 cssSelector: listenAccentSelector
210 }),
211 // On the pill, not on the label: the player's readout is sized in `em`, so
212 // this is what scales the pill and the player together. A font-size on the
213 // label alone would leave the clock behind at 12.6px.
214 addProperty('typography', typoPrefix_listen, {
215 args: {
216 defaultFontSize: 14,
217 prefixConstant: typoPrefix_listen,
218 },
219 cssSelector: listenSelectorOwn
220 }),
221 // The headset glyph on the collapsed pill. Two declarations from one
222 // control, for the reason the AI Actions pair above gives: the stylesheet
223 // sizes these on both axes, so height alone would stretch them.
224 addProperty('responsive', LISTEN_ICON_SIZE, {
225 args: { property: "height", controlName: LISTEN_ICON_SIZE },
226 cssSelector: listenIconSelector
227 }),
228 addProperty('responsive', LISTEN_ICON_SIZE, {
229 id: `${LISTEN_ICON_SIZE}_width`,
230 args: { property: "width", controlName: LISTEN_ICON_SIZE },
231 cssSelector: listenIconSelector
232 }),
233 ];
234 }
235