Skip to content

Onboarding components fixes #1393

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Apr 8, 2024
Merged
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 pgml-dashboard/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions pgml-dashboard/src/components/cards/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ pub mod marketing;
pub mod newsletter_subscribe;
pub use newsletter_subscribe::NewsletterSubscribe;

// src/components/cards/primary
pub mod primary;
pub use primary::Primary;

// src/components/cards/rgb
pub mod rgb;
pub use rgb::Rgb;

// src/components/cards/secondary
pub mod secondary;
pub use secondary::Secondary;
25 changes: 25 additions & 0 deletions pgml-dashboard/src/components/cards/primary/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use pgml_components::{component, Component};
use sailfish::TemplateOnce;

#[derive(TemplateOnce, Default)]
#[template(path = "cards/primary/template.html")]
pub struct Primary {
component: Component,
style: String,
}

impl Primary {
pub fn new(component: Component) -> Primary {
Primary {
component,
style: "".into(),
}
}

pub fn z_index(mut self, index: i64) -> Self {
self.style = format!("position: relative; z-index: {};", index);
self
}
Comment on lines +19 to +22
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing as the next comment, is it possible to solve this with a wrapper?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as above. The wrapper would have to modify the style of its child.

}

component!(Primary);
6 changes: 6 additions & 0 deletions pgml-dashboard/src/components/cards/primary/primary.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
div[data-controller="cards-primary"] {
border-radius: #{$card-border-radius};
padding: #{$card-spacer-y} #{$card-spacer-x};
box-shadow: #{$card-box-shadow};
background-color: #{$gray-800};
}
3 changes: 3 additions & 0 deletions pgml-dashboard/src/components/cards/primary/template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div data-controller="cards-primary" style="<%- style %>">
<%+ component %>
</div>
36 changes: 33 additions & 3 deletions pgml-dashboard/src/components/cards/rgb/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
use pgml_components::{component, Component};
use sailfish::TemplateOnce;

use crate::components::stimulus::StimulusAction;
use crate::types::CustomOption;

#[derive(TemplateOnce)]
#[template(path = "cards/rgb/template.html")]
pub struct Rgb {
value: Component,
active: bool,
link: Option<String>,
link_action: CustomOption<StimulusAction>,
controller_classes: Vec<String>,
card_classes: Vec<String>,
body_classes: Vec<String>,
}

impl Default for Rgb {
Expand All @@ -19,20 +25,44 @@ impl Rgb {
pub fn new(value: Component) -> Rgb {
Rgb {
value,
active: false,
link: None,
link_action: CustomOption::default(),
controller_classes: vec![],
card_classes: vec![],
body_classes: vec![],
}
}

pub fn active(mut self) -> Self {
self.active = true;
self.card_classes.push("active".into());
self.card_classes.push("main-gradient-border-card-1".into());
self
}

pub fn is_active(mut self, active: bool) -> Self {
if active {
self.card_classes.push("active".into());
self.card_classes.push("main-gradient-border-card-1".into());
}

self
}

pub fn link(mut self, link: &str) -> Self {
self.link = Some(link.to_string());
self
}

pub fn link_action(mut self, action: StimulusAction) -> Self {
self.link_action = action.into();
self
}

pub fn h_100(mut self) -> Self {
self.controller_classes.push("h-100".into());
self.card_classes.push("h-100".into());
self
Comment on lines +61 to +64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for something like this is it possible to just always have the h-100 on and for instances where you need to limit the height, place it in a wrapper that does not have h-100? Just brainstorming, this could turn into a slippery slope of having a function for every specific situation. I think if it is possible to solve problems like this with wrappers, we should.

Copy link
Contributor Author

@levkk levkk Apr 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default, the card occupies as much space as it needs to render its contents. The .h-100 here helps cards look uniform when placed inside a grid. Our cards don't have the same contents, so their heights will vary when placed inside a grid like .row or .d-flex. If we have .h-100 by default, the card will always occupy the full height of its container which is not desired when the card is used by itself inside something like a <div class="container">. So .h-100 is a special case that we just happen to use quite often, but not always.

A wrapper can't make its child occupy 100% of its space unless we add additional CSS to the wrapper knowing that the child needs to do this. For example, here we could do something like:

.card-wrapper-h-100 {
    @extend .h-100

    .card {
          @extend .h-100
          
          .card-body {
                @extend .h-100
          }
    }
}

which now that I'm writing this isn't too bad. One issue with this is more of a theoretical technicality, where a component "reaches inside" another component and modifies its state which could cause weird bugs later on. It's typically best to have the component use public methods to modify its state in a predicable way.

Maybe if we name this slightly differently, it could be better? I'm not leaning strongly one way or the other.

}
}

component!(Rgb);
14 changes: 9 additions & 5 deletions pgml-dashboard/src/components/cards/rgb/template.html
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
<% let active = if active { "main-gradient-border-card-1 active" } else { "" }; %>
<div data-controller="cards-rgb">
<div class="card <%= active %>">
<div class="card-body">
<%
let controller_classes = controller_classes.join(" ");
let card_classes = card_classes.join(" ");
let body_classes = body_classes.join(" ");
%>
<div data-controller="cards-rgb" class="<%= controller_classes %>">
<div class="card <%= card_classes %>">
<div class="card-body <%= body_classes %>">
<%+ value %>
<% if let Some(link) = link { %>
<a href="<%= link %>" class="stretched-link"></a>
<a href="<%= link %>" class="stretched-link" data-action="<%= link_action %>"></a>
<% } %>
</div>
</div>
Expand Down
16 changes: 16 additions & 0 deletions pgml-dashboard/src/components/cards/secondary/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use pgml_components::{component, Component};
use sailfish::TemplateOnce;

#[derive(TemplateOnce, Default)]
#[template(path = "cards/secondary/template.html")]
pub struct Secondary {
value: Component,
}

impl Secondary {
pub fn new(value: Component) -> Secondary {
Secondary { value }
}
}

component!(Secondary);
6 changes: 6 additions & 0 deletions pgml-dashboard/src/components/cards/secondary/secondary.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
div[data-controller="cards-secondary"] {
.card {
--bs-card-bg: transparent;
--bs-card-border-color: #{$neon-tint-100};
}
}
7 changes: 7 additions & 0 deletions pgml-dashboard/src/components/cards/secondary/template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<div data-controller="cards-secondary">
<div class="card">
<div class="card-body">
<%+ value %>
</div>
</div>
</div>
3 changes: 3 additions & 0 deletions pgml-dashboard/src/components/headings/gray/gray.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
span[data-controller="headings-gray"] {
color: #{$gray-400};
}
Comment on lines +1 to +3
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could add color = gray-400 to the typography.scss file and just use the class here. Utility classes for the gray scale is always nice.

18 changes: 18 additions & 0 deletions pgml-dashboard/src/components/headings/gray/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use pgml_components::component;
use sailfish::TemplateOnce;

#[derive(TemplateOnce, Default)]
#[template(path = "headings/gray/template.html")]
pub struct Gray {
value: String,
}

impl Gray {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to go down this road, maybe one heading that takes a color, or has a setter function for the desired color, rather than a new component for every header.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I agree, these are too small to be individual components.

pub fn new(value: impl ToString) -> Gray {
Gray {
value: value.to_string(),
}
}
}

component!(Gray);
4 changes: 4 additions & 0 deletions pgml-dashboard/src/components/headings/gray/template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<span
data-controller="headings-gray">
<%= value %>
</span>
4 changes: 4 additions & 0 deletions pgml-dashboard/src/components/headings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
pub mod blue;
pub use blue::Blue;

// src/components/headings/gray
pub mod gray;
pub use gray::Gray;

// src/components/headings/green
pub mod green;
pub use green::Green;
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export default class extends Controller {

e.currentTarget.classList.add("active");
e.currentTarget.ariaPressed = true;
e.currentTarget.querySelector("input").checked = true;

const input = e.currentTarget.querySelector("input");

input.checked = true;
input.dispatchEvent(new Event("change"));
}
}
40 changes: 38 additions & 2 deletions pgml-dashboard/src/components/inputs/range_group_v_2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use pgml_components::component;
use sailfish::TemplateOnce;

use crate::components::stimulus::{stimulus_action::StimulusActions, StimulusAction};
use std::collections::BTreeSet;

#[derive(TemplateOnce, Default)]
#[template(path = "inputs/range_group_v_2/template.html")]
Expand All @@ -12,14 +13,26 @@ pub struct RangeGroupV2 {
step: String,
value: String,
unit: String,
input_unit: String,
input_classes: BTreeSet<String>,
cost_per_unit: String,
cost_frequency: String,

actions: StimulusActions,
}

impl RangeGroupV2 {
pub fn new() -> RangeGroupV2 {
Self::default()
Self {
input_classes: BTreeSet::from_iter(vec!["form-control".to_string()].into_iter()),
..Default::default()
}
.min("40")
.max("16000")
.unit("GB")
.cost_per_unit("0.20")
.value("40")
.cost_frequency("h")
}

pub fn name(mut self, name: impl ToString) -> Self {
Expand Down Expand Up @@ -49,18 +62,41 @@ impl RangeGroupV2 {

pub fn unit(mut self, unit: impl ToString) -> Self {
self.unit = unit.to_string();
self
self.input_unit = unit.to_string();

self.with_input_classes()
}

pub fn input_unit(mut self, input_unit: impl ToString) -> Self {
self.input_unit = input_unit.to_string();
self.with_input_classes()
}

pub fn cost_per_unit(mut self, cost_per_unit: impl ToString) -> Self {
self.cost_per_unit = cost_per_unit.to_string();
self
}

pub fn cost_frequency(mut self, cost_frequency: impl ToString) -> Self {
self.cost_frequency = cost_frequency.to_string();
self
}

pub fn action(mut self, action: StimulusAction) -> Self {
self.actions.push(action);
self
}

fn with_input_classes(mut self) -> Self {
if !self.input_unit.is_empty() {
self.input_classes
.insert("inputs-range-group-v-2-with-unit".to_string());
} else {
self.input_classes.remove("inputs-range-group-v-2-with-unit");
}

self
}
}

component!(RangeGroupV2);
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,33 @@ div[data-controller="inputs-range-group-v-2"] {
}

input[type="text"] {
padding-right: 30px;
&.inputs-range-group-v-2-with-unit {
padding-right: 0;
border-right: 0;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
}

.inputs-range-group-v-2-unit {
margin-left: -33px;
span.inputs-range-group-v-2-unit {
color: #{$gray-400};
background: #{$input-bg};
height: 100%;
padding: #{$input-padding-y} #{$input-padding-x};
border: #{$input-border-width} solid #{$input-border-color};

border-top-right-radius: var(--bs-border-radius);
border-bottom-right-radius: var(--bs-border-radius);
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-left: 0;
transition: #{$input-transition};

&.focused {
background: #{$input-focus-bg};
box-shadow: #{$input-focus-box-shadow};
border-color: #{$input-focus-border-color};
border-width: #{$input-border-width};
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
static targets = ["input", "range"];
static targets = ["input", "range", "unit"];

onInputInput(e) {
const value = parseInt(e.currentTarget.value);
Expand All @@ -14,6 +14,22 @@ export default class extends Controller {
}
}

onInputFocusIn(e) {
if (this.hasUnitTarget) {
this.unitTarget.classList.add("focused");
}
}

onInputBlur(e) {
if (this.hasUnitTarget) {
this.unitTarget.classList.remove("focused");
}
}

onUnitClick(e) {
this.inputTarget.focus();
}

onRangeInput(e) {
this.inputTarget.value = e.currentTarget.value;
}
Expand Down
Loading