-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(brand): Add example app and brand
- Loading branch information
Showing
2 changed files
with
378 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
meta: | ||
name: | ||
full: "Retro Arcade Brand" | ||
short: "RetroArc" | ||
link: | ||
home: https://retroarc.example.com | ||
mastodon: https://mastodon.social/@retroarc | ||
github: https://github.com/retroarc | ||
linkedin: https://linkedin.com/company/retroarc | ||
twitter: https://twitter.com/retroarc | ||
facebook: https://facebook.com/retroarc | ||
|
||
# logo: | ||
# images: | ||
# icon-light: logos/retroarc-icon-light.png | ||
# icon-dark: logos/retroarc-icon-dark.png | ||
# wide-light: logos/retroarc-wide-light.png | ||
# wide-dark: logos/retroarc-wide-dark.png | ||
# tall-light: logos/retroarc-tall-light.png | ||
# tall-dark: logos/retroarc-tall-dark.png | ||
# small: | ||
# light: logos/retroarc-icon-light.png | ||
# dark: logos/retroarc-icon-dark.png | ||
# medium: | ||
# light: logos/retroarc-wide-light.png | ||
# dark: logos/retroarc-wide-dark.png | ||
# large: | ||
# light: logos/retroarc-tall-light.png | ||
# dark: logos/retroarc-tall-dark.png | ||
|
||
color: | ||
palette: | ||
pink: "#E83E8C" | ||
blue: "#007BFF" | ||
cyan: "#17A2B8" | ||
teal: "#20C997" | ||
green: "#28A745" | ||
yellow: "#FFD700" | ||
orange: "#FF7F50" | ||
red: "#FF3333" | ||
purple: "#6F42C1" | ||
indigo: "#6610F2" | ||
black: "#1A1A1A" | ||
white: "#F8F8F8" | ||
foreground: black | ||
background: white | ||
primary: purple | ||
success: green | ||
info: cyan | ||
warning: yellow | ||
danger: orange | ||
light: white | ||
dark: black | ||
|
||
typography: | ||
fonts: | ||
- family: "Quantico" | ||
source: google | ||
weight: [700] | ||
style: [normal] | ||
display: swap | ||
- family: "Monda" | ||
source: google | ||
weight: 400..700 | ||
style: [normal, italic] | ||
display: swap | ||
- family: "Courier Prime" | ||
source: google | ||
weight: [400, 700] | ||
style: [normal, italic] | ||
display: swap | ||
base: | ||
family: "Monda" | ||
size: "1em" | ||
weight: 400 | ||
line-height: 1.5 | ||
headings: | ||
family: "Quantico" | ||
weight: 400 | ||
line-height: 1.2 | ||
style: normal | ||
monospace: | ||
family: "Courier Prime" | ||
size: "0.9em" | ||
weight: 400 | ||
monospace-inline: | ||
family: "Courier Prime" | ||
size: "0.9em" | ||
weight: 400 | ||
color: yellow | ||
background-color: "#1a1a1add" | ||
monospace-block: | ||
family: "Courier Prime" | ||
size: "0.9em" | ||
weight: 400 | ||
color: green | ||
background-color: black | ||
line-height: 1.4 | ||
link: | ||
weight: 400 | ||
background-color: purple | ||
color: white | ||
decoration: "underline" | ||
|
||
defaults: | ||
shiny: | ||
theme: | ||
navbar-bg: $brand-purple |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,270 @@ | ||
import os | ||
|
||
import matplotlib.pyplot as plt | ||
import numpy as np | ||
|
||
from shiny import App, render, ui | ||
|
||
# TODO: Move this into the test that runs this app | ||
os.environ["SHINY_BRAND_YML_RAISE_UNMAPPED"] = "true" | ||
|
||
theme = ui.Theme.from_brand(__file__) | ||
|
||
app_ui = ui.page_navbar( | ||
ui.nav_panel( | ||
"Input Output Demo", | ||
ui.page_sidebar( | ||
ui.sidebar( | ||
ui.input_slider("slider1", "Numeric Slider Input", 0, 11, 11), | ||
ui.input_numeric("numeric1", "Numeric Input Widget", 30), | ||
ui.input_date("date1", "Date Input Component", value="2024-01-01"), | ||
ui.input_switch("switch1", "Binary Switch Input", True), | ||
ui.input_radio_buttons( | ||
"radio1", | ||
"Radio Button Group", | ||
choices=["Option A", "Option B", "Option C", "Option D"], | ||
), | ||
ui.input_action_button("action1", "Action Button"), | ||
), | ||
ui.layout_column_wrap( | ||
ui.value_box( | ||
"Metric 1", | ||
"100", | ||
theme="primary", | ||
), | ||
ui.value_box( | ||
"Metric 2", | ||
"200", | ||
theme="secondary", | ||
), | ||
ui.value_box( | ||
"Metric 3", | ||
"300", | ||
theme="info", | ||
), | ||
), | ||
ui.card( | ||
ui.card_header("Plot Output"), | ||
ui.output_plot("plot1"), | ||
), | ||
ui.card( | ||
ui.card_header("Text Output"), | ||
ui.output_text_verbatim("out_text1"), | ||
), | ||
), | ||
), | ||
ui.nav_panel( | ||
"Widget Gallery", | ||
ui.layout_column_wrap( | ||
ui.card( | ||
ui.card_header("Button Variants"), | ||
ui.input_action_button("btn1", "Default"), | ||
ui.input_action_button("btn2", "Primary", class_="btn-primary"), | ||
ui.input_action_button("btn3", "Secondary", class_="btn-secondary"), | ||
ui.input_action_button("btn4", "Info", class_="btn-info"), | ||
ui.input_action_button("btn5", "Success", class_="btn-success"), | ||
ui.input_action_button("btn6", "Warning", class_="btn-warning"), | ||
ui.input_action_button("btn7", "Danger", class_="btn-danger"), | ||
), | ||
ui.card( | ||
ui.card_header("Radio Button Examples"), | ||
ui.input_radio_buttons( | ||
"radio2", | ||
"Standard Radio Group", | ||
["Selection 1", "Selection 2", "Selection 3"], | ||
), | ||
ui.input_radio_buttons( | ||
"radio3", | ||
"Inline Radio Group", | ||
["Option 1", "Option 2", "Option 3"], | ||
inline=True, | ||
), | ||
), | ||
ui.card( | ||
ui.card_header("Checkbox Examples"), | ||
ui.input_checkbox_group( | ||
"check1", | ||
"Standard Checkbox Group", | ||
["Item 1", "Item 2", "Item 3"], | ||
), | ||
ui.input_checkbox_group( | ||
"check2", | ||
"Inline Checkbox Group", | ||
["Choice A", "Choice B", "Choice C"], | ||
inline=True, | ||
), | ||
), | ||
ui.card( | ||
ui.card_header("Select Input Widgets"), | ||
ui.input_selectize( | ||
"select1", | ||
"Selectize Input", | ||
["Selection A", "Selection B", "Selection C"], | ||
), | ||
ui.input_select( | ||
"select2", | ||
"Multiple Select Input", | ||
["Item X", "Item Y", "Item Z"], | ||
multiple=True, | ||
), | ||
), | ||
ui.card( | ||
ui.card_header("Text Input Widgets"), | ||
ui.input_text("text1", "Text Input"), | ||
ui.input_text_area( | ||
"textarea1", | ||
"Text Area Input", | ||
"Default text content for the text area widget", | ||
), | ||
ui.input_password("password1", "Password Input"), | ||
), | ||
width=400, | ||
heights_equal=False, | ||
), | ||
), | ||
ui.nav_panel( | ||
"Documentation", | ||
ui.div( | ||
ui.markdown( | ||
""" | ||
_Just in case it isn't obvious, this text (and most of this app) was written by an LLM._ | ||
# Component Documentation | ||
The Shiny for Python framework, available at [shiny.posit.co/py](https://shiny.posit.co/py/), | ||
provides a comprehensive set of UI components for building interactive web applications. These | ||
components are designed with **consistency and usability** in mind, making it easier for | ||
developers to create professional-grade applications. | ||
Our framework implements the `ui.page_navbar()` component as the primary navigation structure, | ||
allowing for intuitive organization of content across multiple views. Each view can contain | ||
various input and output elements, managed through the `ui.card()` container system. | ||
## Component Architecture | ||
*The architecture of our application framework* emphasizes modularity and reusability. Key | ||
components like `ui.value_box()` and `ui.layout_column_wrap()` work together to create | ||
structured, responsive layouts that adapt to different screen sizes. | ||
<table class="table table-striped"> | ||
<thead> | ||
<tr> | ||
<th>Component</th> | ||
<th>Implementation</th> | ||
<th>Use Case</th> | ||
<th>Status</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
<tr> | ||
<td>Value Box</td> | ||
<td><code>ui.value_box()</code></td> | ||
<td>Metric Display</td> | ||
<td>Production Ready</td> | ||
</tr> | ||
<tr> | ||
<td>Card</td> | ||
<td><code>ui.card()</code></td> | ||
<td>Content Container</td> | ||
<td>Production Ready</td> | ||
</tr> | ||
<tr> | ||
<td>Layout</td> | ||
<td><code>ui.layout_column_wrap()</code></td> | ||
<td>Component Organization</td> | ||
<td>Production Ready</td> | ||
</tr> | ||
<tr> | ||
<td>Navigation</td> | ||
<td><code>ui.page_navbar()</code></td> | ||
<td>Page Structure</td> | ||
<td>Production Ready</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
## Implementation Best Practices | ||
When implementing components, maintain consistent patterns in your code. Use the | ||
`@render` decorators for output functions and follow the reactive programming model | ||
with `@reactive.effect` for side effects. | ||
Error handling should be implemented at both the UI and server levels. For input | ||
validation, use the `req()` function to ensure all required values are present | ||
before processing. | ||
## Corporate Brand Guidelines | ||
Effective corporate brand guidelines should accomplish several key objectives: | ||
1. **Visual Consistency**: Establish a clear color palette using our theming system. | ||
Primary colors should be defined using `class_="btn-primary"` and similar Bootstrap | ||
classes. | ||
2. *Typography Standards*: Maintain consistent font usage across all text elements. | ||
Headers should use the built-in styling provided by the `ui.card_header()` component. | ||
3. `Component Styling`: Apply consistent styling to UI elements such as buttons, | ||
cards, and value boxes. Use the theme parameter in components like | ||
`ui.value_box(theme="primary")`. | ||
4. **Layout Principles**: Follow a grid-based layout system using | ||
`ui.layout_column_wrap()` with appropriate width parameters to ensure consistent | ||
spacing and alignment. | ||
5. *Responsive Design*: Implement layouts that adapt gracefully to different screen | ||
sizes using the `fillable` parameter in page components. | ||
Remember that brand guidelines should serve as a framework for consistency while | ||
remaining flexible enough to accommodate future updates and modifications to the | ||
application interface. | ||
""" | ||
), | ||
class_="container-sm", | ||
), | ||
), | ||
ui.nav_spacer(), | ||
ui.nav_control(ui.input_dark_mode(id="color_mode")), | ||
title="brand.yml Demo", | ||
fillable=["Input Output Demo", "Widget Gallery"], | ||
theme=theme, | ||
) | ||
|
||
|
||
def server(input, output, session): | ||
@render.plot | ||
def plot1(): | ||
colors = { | ||
"foreground": "#000000", | ||
"background": "#FFFFFF", | ||
"primary": "#4463ff", | ||
} | ||
|
||
if theme.brand.color: | ||
colors.update(theme.brand.color.to_dict("theme")) | ||
|
||
if input.color_mode() == "dark": | ||
bg = colors["foreground"] | ||
fg = colors["background"] | ||
colors.update({"foreground": fg, "background": bg}) | ||
|
||
x = np.linspace(0, input.numeric1(), 100) | ||
y = np.sin(x) * input.slider1() | ||
fig, ax = plt.subplots(facecolor=colors["background"]) | ||
ax.plot(x, y, color=colors["primary"]) | ||
ax.set_title("Sine Wave Output", color=colors["foreground"]) | ||
ax.set_facecolor(colors["background"]) | ||
ax.tick_params(colors=colors["foreground"]) | ||
for spine in ax.spines.values(): | ||
spine.set_edgecolor(colors["foreground"]) | ||
spine.set_alpha(0.25) | ||
return fig | ||
|
||
@render.text | ||
def out_text1(): | ||
return "\n".join( | ||
["def example_function():", ' return "Function output text"'] | ||
) | ||
|
||
|
||
app = App(app_ui, server) |