Skip to content

Commit 9f4c09a

Browse files
Util components (#582)
* Added back UI styles * Forgot another file
1 parent a983d8a commit 9f4c09a

1 file changed

Lines changed: 336 additions & 0 deletions

File tree

Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
#' UI Component Factory Functions for cOmicsArt
2+
#'
3+
#' This file contains reusable UI component builders with consistent styling.
4+
#' These functions eliminate duplication and ensure visual consistency.
5+
#'
6+
#' @author cOmicsArt Development Team
7+
#' @date 2026-06-14
8+
9+
# Button Components ------------------------------------------------------------
10+
11+
#' Create a primary action button with cOmicsArt styling
12+
#'
13+
#' Primary buttons have the green background and are used for main actions.
14+
#'
15+
#' @param inputId Character. Button ID
16+
#' @param label Character. Button label
17+
#' @param icon_name Character. Font Awesome icon name (optional)
18+
#' @param full_width Logical. Make button 100% width (default: FALSE)
19+
#' @param width Character. Custom width (default: NULL, uses full_width if TRUE)
20+
#' @param ... Additional arguments passed to actionButton()
21+
#'
22+
#' @return Shiny action button with primary styling
23+
#'
24+
#' @examples
25+
#' \dontrun{
26+
#' primary_action_button(
27+
#' inputId = "start_analysis",
28+
#' label = "Start Analysis",
29+
#' icon_name = "rocket",
30+
#' full_width = TRUE
31+
#' )
32+
#' }
33+
#'
34+
#' @export
35+
primary_action_button <- function(inputId, label, icon_name = NULL,
36+
full_width = FALSE, width = NULL, ...) {
37+
icon_obj <- if (!is.null(icon_name)) icon(icon_name) else NULL
38+
39+
# Determine width
40+
if (is.null(width)) {
41+
width <- if (full_width) "100%" else NULL
42+
}
43+
44+
actionButton(
45+
inputId = inputId,
46+
label = label,
47+
icon = icon_obj,
48+
width = width,
49+
style = STYLE_PRIMARY_BUTTON,
50+
...
51+
)
52+
}
53+
54+
#' Create a secondary action button with cOmicsArt styling
55+
#'
56+
#' Secondary buttons have white background and are used for less prominent actions.
57+
#'
58+
#' @inheritParams primary_action_button
59+
#' @export
60+
secondary_action_button <- function(inputId, label, icon_name = NULL,
61+
full_width = FALSE, width = NULL, ...) {
62+
icon_obj <- if (!is.null(icon_name)) icon(icon_name) else NULL
63+
64+
# Determine width
65+
if (is.null(width)) {
66+
width <- if (full_width) "100%" else NULL
67+
}
68+
69+
actionButton(
70+
inputId = inputId,
71+
label = label,
72+
icon = icon_obj,
73+
width = width,
74+
style = STYLE_SECONDARY_BUTTON,
75+
...
76+
)
77+
}
78+
79+
#' Create a transparent action button with cOmicsArt styling
80+
#'
81+
#' Transparent buttons have no background and are used for toggles or minimal actions.
82+
#'
83+
#' @inheritParams primary_action_button
84+
#' @export
85+
transparent_action_button <- function(inputId, label, icon_name = NULL,
86+
full_width = FALSE, width = NULL, ...) {
87+
icon_obj <- if (!is.null(icon_name)) icon(icon_name) else NULL
88+
89+
# Determine width
90+
if (is.null(width)) {
91+
width <- if (full_width) "100%" else NULL
92+
}
93+
94+
actionButton(
95+
inputId = inputId,
96+
label = label,
97+
icon = icon_obj,
98+
width = width,
99+
style = STYLE_TRANSPARENT_BUTTON,
100+
...
101+
)
102+
}
103+
104+
# Download Components ----------------------------------------------------------
105+
106+
#' Create a download button with optional helper
107+
#'
108+
#' Creates a download button with consistent styling and optional help tooltip.
109+
#'
110+
#' @param outputId Character. Download handler ID
111+
#' @param label Character. Button label
112+
#' @param help_content Character. Markdown help content ID (optional)
113+
#' @param class Character. CSS class (default: "btn-default")
114+
#' @param ... Additional arguments passed to downloadButton()
115+
#'
116+
#' @return Download button with optional helper
117+
#'
118+
#' @examples
119+
#' \dontrun{
120+
#' download_button_with_help(
121+
#' outputId = "download_results",
122+
#' label = "Download Results",
123+
#' help_content = "download_help"
124+
#' )
125+
#' }
126+
#'
127+
#' @export
128+
download_button_with_help <- function(outputId, label, help_content = NULL,
129+
class = "btn-default", ...) {
130+
btn <- downloadButton(
131+
outputId = outputId,
132+
label = label,
133+
class = class,
134+
...
135+
)
136+
137+
if (!is.null(help_content)) {
138+
# Attach helper if shinyhelper is available
139+
if (requireNamespace("shinyhelper", quietly = TRUE)) {
140+
btn <- btn %>% shinyhelper::helper(type = "markdown", content = help_content)
141+
} else {
142+
warning("shinyhelper package not available. Helper not attached to download button.")
143+
}
144+
}
145+
146+
btn
147+
}
148+
149+
# Input Components -------------------------------------------------------------
150+
151+
#' Create a select input with standard width
152+
#'
153+
#' Creates a selectInput with the standard 80% width used throughout cOmicsArt.
154+
#'
155+
#' @param inputId Character. Input ID
156+
#' @param label Character. Label
157+
#' @param choices Vector. Choices
158+
#' @param selected Character. Selected value (default: "")
159+
#' @param width Character. Width (default: "80%")
160+
#' @param multiple Logical. Allow multiple selections (default: FALSE)
161+
#' @param ... Additional arguments passed to selectInput()
162+
#'
163+
#' @return Select input with standard width
164+
#'
165+
#' @examples
166+
#' \dontrun{
167+
#' standard_select_input(
168+
#' inputId = "omic_type",
169+
#' label = "Omic Type",
170+
#' choices = c("Transcriptomics", "Lipidomics", "Metabolomics")
171+
#' )
172+
#' }
173+
#'
174+
#' @export
175+
standard_select_input <- function(inputId, label, choices, selected = "",
176+
width = "80%", multiple = FALSE, ...) {
177+
selectInput(
178+
inputId = inputId,
179+
label = label,
180+
choices = choices,
181+
selected = selected,
182+
width = width,
183+
multiple = multiple,
184+
...
185+
)
186+
}
187+
188+
#' Create a file input with standard width
189+
#'
190+
#' Creates a fileInput with the standard 80% width.
191+
#'
192+
#' @param inputId Character. Input ID
193+
#' @param label Character or HTML. Label (can include HTML for links)
194+
#' @param accept Character vector. Accepted file types (default: c(".csv"))
195+
#' @param width Character. Width (default: "80%")
196+
#' @param ... Additional arguments passed to fileInput()
197+
#'
198+
#' @return File input with standard width
199+
#'
200+
#' @examples
201+
#' \dontrun{
202+
#' standard_file_input(
203+
#' inputId = "data_matrix",
204+
#' label = "Upload Data Matrix",
205+
#' accept = c(".csv", ".xlsx")
206+
#' )
207+
#' }
208+
#'
209+
#' @export
210+
standard_file_input <- function(inputId, label, accept = c(".csv"),
211+
width = "80%", ...) {
212+
shiny::fileInput(
213+
inputId = inputId,
214+
label = label,
215+
accept = accept,
216+
width = width,
217+
...
218+
)
219+
}
220+
221+
# Layout Components ------------------------------------------------------------
222+
223+
#' Create a triple split layout with identical buttons
224+
#'
225+
#' Creates a splitLayout with 3 identical buttons (action or download).
226+
#' Commonly used in volcano plot controls.
227+
#'
228+
#' @param ids Character vector of length 3. Button IDs
229+
#' @param label Character. Button label (same for all 3)
230+
#' @param class Character. Button class (default: "btn-default")
231+
#' @param type Character. "action" or "download" (default: "action")
232+
#' @param ... Additional arguments passed to button function
233+
#'
234+
#' @return Split layout with 3 buttons
235+
#'
236+
#' @examples
237+
#' \dontrun{
238+
#' triple_button_layout(
239+
#' ids = c("copy_adj", "copy_raw", "copy_both"),
240+
#' label = "Copy to Clipboard",
241+
#' type = "action"
242+
#' )
243+
#' }
244+
#'
245+
#' @export
246+
triple_button_layout <- function(ids, label, class = "btn-default",
247+
type = "action", ...) {
248+
if (length(ids) != 3) {
249+
stop("ids must be a vector of length 3")
250+
}
251+
252+
if (type == "download") {
253+
# Download buttons use outputId
254+
button_fn <- function(id) {
255+
downloadButton(outputId = id, label = label, class = class, ...)
256+
}
257+
} else {
258+
# Action buttons use inputId
259+
button_fn <- function(id) {
260+
actionButton(inputId = id, label = label, class = class, ...)
261+
}
262+
}
263+
264+
splitLayout(
265+
button_fn(ids[1]),
266+
button_fn(ids[2]),
267+
button_fn(ids[3])
268+
)
269+
}
270+
271+
# Clipboard Button Components --------------------------------------------------
272+
273+
#' Create an action button with clipboard data attribute
274+
#'
275+
#' Creates an action button that automatically works with the generic
276+
#' JavaScript clipboard handler (no need to add JS code).
277+
#'
278+
#' @param inputId Character. Button ID
279+
#' @param label Character. Button label
280+
#' @param plot_id Character. ID of the plot to copy (for data-clipboard-plot attribute)
281+
#' @param icon_name Character. Font Awesome icon (default: "clipboard")
282+
#' @param class Character. CSS class (default: "btn-default")
283+
#' @param ... Additional arguments passed to actionButton()
284+
#'
285+
#' @return Action button with data-clipboard-plot attribute
286+
#'
287+
#' @examples
288+
#' \dontrun{
289+
#' clipboard_button(
290+
#' inputId = "copy_pca_btn",
291+
#' label = "Copy PCA Plot",
292+
#' plot_id = "PCA_plot"
293+
#' )
294+
#' }
295+
#'
296+
#' @export
297+
clipboard_button <- function(inputId, label = "Copy to Clipboard", plot_id,
298+
icon_name = "clipboard", class = "btn-default", ...) {
299+
actionButton(
300+
inputId = inputId,
301+
label = label,
302+
icon = icon(icon_name),
303+
class = class,
304+
`data-clipboard-plot` = plot_id, # This attribute triggers JS handler
305+
...
306+
)
307+
}
308+
309+
# Helper Attachment ------------------------------------------------------------
310+
311+
#' Attach helper to any UI element
312+
#'
313+
#' Convenience wrapper for shinyhelper::helper that checks if package is available.
314+
#'
315+
#' @param ui_element Shiny UI element
316+
#' @param content Character. Markdown file name (without .md extension)
317+
#' @param type Character. Helper type (default: "markdown")
318+
#' @param ... Additional arguments passed to shinyhelper::helper()
319+
#'
320+
#' @return UI element with helper attached, or original element if shinyhelper unavailable
321+
#'
322+
#' @examples
323+
#' \dontrun{
324+
#' selectInput("my_input", "Label", choices = c("A", "B")) %>%
325+
#' attach_helper("my_input_help")
326+
#' }
327+
#'
328+
#' @export
329+
attach_helper <- function(ui_element, content, type = "markdown", ...) {
330+
if (requireNamespace("shinyhelper", quietly = TRUE)) {
331+
ui_element %>% shinyhelper::helper(type = type, content = content, ...)
332+
} else {
333+
warning("shinyhelper package not available. Helper not attached.")
334+
ui_element
335+
}
336+
}

0 commit comments

Comments
 (0)