Skip to content

Enhancements for dropdowns: animations, open at initial state, and chevron indicators #675

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

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
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
131 changes: 119 additions & 12 deletions assets/theme-css/sphinx-design/_dropdown.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,35 @@ details.sd-dropdown {
font-weight: 700;
// don't overlap the chevron
padding-right: 3em !important;
-moz-user-select: none;
-ms-user-select: none;
-webkit-user-select: none;
Comment on lines -8 to -10
Copy link
Contributor Author

Choose a reason for hiding this comment

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

My text editor warns that these attributes are non-standard and should be avoided, and user-select is baseline already. The same warnings occur in a few other places below, and I removed the browser-engine-specific styling there as well.

user-select: none;
display: inline-flex;
justify-content: space-between;
align-items: center;
width: 100%;

.sd-summary-text {
flex-grow: 1;
line-height: 1.5;
padding-right: 0.5rem;
}

.sd-summary-state-marker {
position: absolute;
right: 1em;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
display: inline-flex;
align-items: center;
justify-content: center;
width: 0.75em;
}

// The hover effect should only change opacity, not transform.
// We are transforming the chevron elements instead, see below.
&:hover .sd-summary-state-marker svg {
opacity: 1;
}
}

&:hover {
Expand Down Expand Up @@ -54,7 +79,6 @@ details.sd-dropdown {
summary:hover .sd-summary-up svg,
summary:hover .sd-summary-down svg {
opacity: 1;
transform: scale(1.1);
}

.sd-summary-up svg,
Expand All @@ -79,6 +103,61 @@ details.sd-dropdown {
visibility: hidden;
}

// Chevron transitions
.sd-summary-chevron-right i,
.sd-summary-chevron-down i {
display: inline-block;
transform-origin: center;
opacity: 0.6;
}

// The chevron rotation animations are applied to
// the icon inside the dropdown title div
&[open] > .sd-summary-title .sd-summary-chevron-right i {
transform: rotate(90deg);
animation: rotate-to-90 0.25s ease-in-out;
}

&[open] > .sd-summary-title .sd-summary-chevron-down i {
transform: rotate(-180deg);
animation: rotate-to-negative-180 0.25s ease-in-out;
}

&:not([open]) > .sd-summary-title .sd-summary-chevron-right i {
transform: rotate(0deg);
animation: rotate-to-0-from-90 0.25s ease-in-out;
}

&:not([open]) > .sd-summary-title .sd-summary-chevron-down i {
transform: rotate(0deg);
animation: rotate-to-0-from-negative-180 0.25s ease-in-out;
}

> .sd-summary-title:hover .sd-summary-chevron-right i,
> .sd-summary-title:hover .sd-summary-chevron-down i {
opacity: 1;
}

// Combined transforms for each state with hover. These cover
// the cases where the chevron is rotated, say, when the dropdown
// is open or if the chevron starts rotated (e.g. in the down-up
// state).
&:not([open]) > .sd-summary-title:hover .sd-summary-chevron-right i {
transform: scale(1.1);
}

&:not([open]) > .sd-summary-title:hover .sd-summary-chevron-down i {
transform: scale(1.1);
}

&[open] > .sd-summary-title:hover .sd-summary-chevron-right i {
transform: rotate(90deg) scale(1.1);
}

&[open] > .sd-summary-title:hover .sd-summary-chevron-down i {
transform: rotate(-180deg) scale(1.1);
}
Comment on lines +145 to +159
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the earlier commit I pushed today, I changed this to .sd-summary-title:hover as we want to increase the chevron sizes only when hovering over the dropdown bars and not when hovering over the content inside them (this is the same as PST).

In particular, these lines address the cases where you hover over the chevrons and click on them – we don't want the chevrons to transition from a 1.1x scale to a 1.0x scale while rotating and then back to a 1.1x scale, but rather stay at a 1.1x scale throughout the transition.


// Hide the card body border when not open
&:not([open]).sd-card {
border: none;
Expand All @@ -90,18 +169,10 @@ details.sd-dropdown {

// Transition animation
&.sd-fade-in[open] summary ~ * {
-moz-animation: sd-fade-in 0.5s ease-in-out;
-webkit-animation: sd-fade-in 0.5s ease-in-out;
Comment on lines -93 to -94
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 as above – these are non-standard attributes and are best avoided. I can also clean these up from everywhere in a separate PR and reduce the diff here if you want me to.

animation: sd-fade-in 0.5s ease-in-out;
}

&.sd-fade-in-slide-down[open] summary ~ * {
-moz-animation:
sd-fade-in 0.5s ease-in-out,
sd-slide-down 0.5s ease-in-out;
-webkit-animation:
sd-fade-in 0.5s ease-in-out,
sd-slide-down 0.5s ease-in-out;
animation:
sd-fade-in 0.5s ease-in-out,
sd-slide-down 0.5s ease-in-out;
Expand Down Expand Up @@ -135,3 +206,39 @@ details.sd-dropdown {
transform: translate(0, 0);
}
}

@keyframes rotate-to-90 {
from {
transform: rotate(0deg) scale(1.1);
}
to {
transform: rotate(90deg) scale(1.1);
}
}

@keyframes rotate-to-negative-180 {
from {
transform: rotate(0deg) scale(1.1);
}
to {
transform: rotate(-180deg) scale(1.1);
}
}

@keyframes rotate-to-0-from-90 {
from {
transform: rotate(90deg) scale(1.1);
}
to {
transform: rotate(0deg) scale(1.1);
}
}

@keyframes rotate-to-0-from-negative-180 {
from {
transform: rotate(-180deg) scale(1.1);
}
to {
transform: rotate(0deg) scale(1.1);
}
}
157 changes: 143 additions & 14 deletions layouts/shortcodes/dropdown.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,23 +31,152 @@
body = 'And some content and an icon!'
{{< /dropdown >}}

{{< dropdown >}}
title = 'A success color dropdown'
icon = 'fa-solid fa-check'
color = 'success'
body = 'And some content and an icon!'
{{< /dropdown >}}

{{< dropdown >}}
title = 'A warning color dropdown'
icon = 'fa-solid fa-exclamation'
color = 'warning'
body = 'And some content and an icon!'
{{< /dropdown >}}

{{< dropdown >}}
title = 'A danger color dropdown'
icon = 'fa-solid fa-exclamation-triangle'
color = 'danger'
body = 'And some content and an icon!'
{{< /dropdown >}}

{{< dropdown >}}
title = 'Open dropdown by default'
icon = 'fa-solid fa-eye'
color = 'info'
open = true
body = 'This dropdown is open by default!'
{{< /dropdown >}}

{{< dropdown >}}
title = 'Fade in animation'
icon = 'fa-solid fa-magic'
animate = 'fade-in'
body = 'This dropdown fades in when opened!'
{{< /dropdown >}}

{{< dropdown >}}
title = 'Fade in and slide down animation'
icon = 'fa-solid fa-chart-line'
animate = 'fade-in-slide-down'
body = 'This dropdown fades in and slides down when opened!'
{{< /dropdown >}}

{{< dropdown >}}
title = 'Using chevron: down-up'
icon = 'fa-solid fa-cog'
chevron = 'down-up'
body = 'Notice the different chevron direction!'
{{< /dropdown >}}

{{< dropdown >}}
title = 'Custom chevron with animation'
icon = 'fa-solid fa-star'
chevron = 'down-up'
animate = 'fade-in'
color = 'warning'
body = 'Combining different features!'
{{< /dropdown >}}

{{< dropdown >}}
title = 'Multi-line content'
icon = 'fa-solid fa-align-left'
body = '''
This is multi-line content.

It can include **markdown** and multiple paragraphs.
And even lists:

- Item 1
- Item 2
- Item 3
'''
{{< /dropdown >}}

{{< dropdown >}}
title = 'Dropdown with code'
icon = 'fa-solid fa-code'
color = 'success'
body = '''
Here's some code inside a dropdown:

```python
def hello_world():
print("Hello from a dropdown!")
return 42
```

And more content after the code.
'''
{{< /dropdown >}}

{{< dropdown >}}
title = 'Nested dropdowns'
icon = 'fa-solid fa-folder'
body = '''
This is a dropdown with a dropdown inside it.

{{< dropdown >}}
title = 'Inner dropdown'
icon = 'fa-solid fa-code'
body = '''
I'm inside a dropdown in a dropdown!
'''
{{< /dropdown >}}

And here is some more content after the inner dropdown.
'''
{{< /dropdown >}}

*/}}

{{- $data := .Inner | transform.Unmarshal -}}
<details class="sd-card sd-dropdown sd-mb-3">
{{- with $data.color }}
<summary class="sd-summary-title sd-card-header sd-bg-{{ . }} sd-bg-text-{{ . }}">
{{- else }}
<summary class="sd-summary-title sd-card-header">
{{- end }}
{{- with $data.icon }}
<span class="sd-summary-icon"><i class="fa {{ . }}"></i></span>
{{- end }}
{{- with $data.title }}
{{- . }}
{{- else }}
<i class="fas fa-ellipsis-h"></i>&nbsp;
{{- end }}

{{- $chevronClass := "sd-summary-chevron-right" -}}
{{- $chevronIcon := "fa-chevron-right" -}}
{{- if eq $data.chevron "down-up" -}}
{{- $chevronClass = "sd-summary-chevron-down" -}}
{{- $chevronIcon = "fa-chevron-down" -}}
{{- end -}}

{{- $detailsClasses := slice "sd-sphinx-override" "sd-dropdown" "sd-card" "sd-mb-3" -}}
{{- with $data.animate -}}
{{- $detailsClasses = $detailsClasses | append (printf "sd-%s" .) -}}
{{- end -}}

<details class="{{ delimit $detailsClasses " " }}"{{ if $data.open }} open="open"{{ end }}>
{{- $summaryClasses := slice "sd-summary-title" "sd-card-header" -}}
{{- with $data.color -}}
{{- $summaryClasses = $summaryClasses | append (printf "sd-bg-%s" .) -}}
{{- $summaryClasses = $summaryClasses | append (printf "sd-bg-text-%s" .) -}}
{{- end -}}

<summary class="{{ delimit $summaryClasses " " }}">
{{- with $data.icon }}
<span class="sd-summary-icon"><i class="fa {{ . }}"></i></span>
{{- end }}
<span class="sd-summary-text">
{{- with $data.title }}
{{- . }}
{{- else }}
<i class="fas fa-ellipsis-h no-title sd-octicon"></i>
{{- end }}
</span>
<span class="sd-summary-state-marker {{ $chevronClass }}">
<i class="fas {{ $chevronIcon }}"></i>
</span>
Comment on lines +177 to +179
Copy link
Contributor Author

Choose a reason for hiding this comment

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

.sd-summary-state-marker is a separate element that makes it easier for us to style where the chevrons are placed (at the end of the dropdown bars).

</summary>
<div class="sd-summary-content sd-card-body">
{{- with (trim $data.body "\n") }}
Expand Down