mirror of
https://github.com/hugo-fixit/FixIt.git
synced 2026-08-24 07:18:57 +00:00
20c0997cc5
- Restructure SCSS pages directory and rename shared to content - Ensure hr overflow visible for awesome-hr icon - Restore position relative on .page for absolute children
632 lines
13 KiB
SCSS
632 lines
13 KiB
SCSS
// ========================================
|
|
// Tabs shortcode - Multiple Design Styles
|
|
// ========================================
|
|
@use "core/functions" as *;
|
|
@use "core/mixins" as *;
|
|
@use "variables" as *;
|
|
|
|
@mixin tab-button-size($padding-inline: 1.25rem, $padding-block: 0.75rem) {
|
|
@if $padding-inline != 0 {
|
|
padding-inline: $padding-inline;
|
|
}
|
|
|
|
@if $padding-block != 0 {
|
|
padding-block: $padding-block;
|
|
}
|
|
}
|
|
|
|
tab-container {
|
|
display: flex;
|
|
gap: 0.75rem;
|
|
margin-block: 0.5rem 1rem;
|
|
position: relative;
|
|
|
|
// loading before defined
|
|
&:not(:defined) {
|
|
&::before {
|
|
@include loading;
|
|
}
|
|
}
|
|
|
|
tab-container {
|
|
margin-block: 1rem;
|
|
}
|
|
|
|
> .tab-button {
|
|
position: relative;
|
|
display: block;
|
|
border: none;
|
|
color: inherit;
|
|
background-color: transparent;
|
|
font-size: 0.9em;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
flex-shrink: 0;
|
|
transition: all 0.3s ease;
|
|
}
|
|
|
|
> .tab-panel {
|
|
&[hidden] {
|
|
display: none;
|
|
}
|
|
> *:first-child {
|
|
margin-top: 0;
|
|
}
|
|
}
|
|
|
|
&::part(tablist-tab-wrapper) {
|
|
flex: 1 0 auto;
|
|
}
|
|
|
|
&::part(tablist) {
|
|
display: flex;
|
|
}
|
|
|
|
&[placement='top'],
|
|
&[placement='bottom'] {
|
|
&::part(tablist-wrapper) {
|
|
max-width: 100%;
|
|
}
|
|
|
|
&::part(tablist) {
|
|
gap: 1rem;
|
|
}
|
|
}
|
|
|
|
&[placement='left'],
|
|
&[placement='right'] {
|
|
max-width: 100%;
|
|
|
|
&::part(tablist-wrapper) {
|
|
min-height: 100px;
|
|
}
|
|
|
|
&::part(tablist) {
|
|
flex-direction: column;
|
|
}
|
|
|
|
> .tab-button {
|
|
max-width: 300px;
|
|
}
|
|
|
|
> .tab-panel {
|
|
flex: 1;
|
|
min-width: 0;
|
|
}
|
|
}
|
|
|
|
&[placement='top'] {
|
|
flex-direction: column;
|
|
}
|
|
|
|
&[placement='bottom'] {
|
|
flex-direction: column-reverse;
|
|
}
|
|
|
|
&[placement='right'] {
|
|
flex-direction: row-reverse;
|
|
}
|
|
|
|
// ========================================
|
|
// Style 1: Underline Style (Default)
|
|
// Clean, minimal with sliding indicator
|
|
// ========================================
|
|
&[type='underline'] {
|
|
> .tab-button {
|
|
@include tab-button-size(0);
|
|
|
|
&[aria-selected='true'],
|
|
&[aria-selected='false']:hover {
|
|
color: fi-var(primary);
|
|
}
|
|
|
|
&[aria-selected='false']:hover {
|
|
opacity: 0.7;
|
|
}
|
|
}
|
|
|
|
// Anchor tracking: follows hover, rests on active tab
|
|
&:not(:has(> .tab-button:hover)) > .tab-button[aria-selected='true'],
|
|
> .tab-button:hover {
|
|
anchor-name: #{$rootPrefix}tab-underline-active;
|
|
}
|
|
|
|
&::part(tablist-wrapper) {
|
|
position: relative;
|
|
|
|
// Sliding box-shadow indicator via anchor positioning
|
|
&::before {
|
|
content: '';
|
|
position: absolute;
|
|
position-anchor: #{$rootPrefix}tab-underline-active;
|
|
inset: anchor(inside);
|
|
pointer-events: none;
|
|
}
|
|
}
|
|
|
|
&:has(> .tab-button[aria-selected='false']:hover)::part(tablist-wrapper)::before {
|
|
opacity: 0.7;
|
|
}
|
|
|
|
&[placement='top'],
|
|
&[placement='bottom'] {
|
|
gap: 0.5rem;
|
|
|
|
> .tab-button {
|
|
@include tab-button-size(1.5rem, 0);
|
|
}
|
|
|
|
&::part(tablist-wrapper) {
|
|
overflow-x: auto;
|
|
overflow-y: hidden;
|
|
}
|
|
|
|
&::part(tablist-wrapper)::before {
|
|
transition: all 0.3s ease-in-out, top, bottom 0s;
|
|
}
|
|
}
|
|
|
|
&[placement='left'],
|
|
&[placement='right'] {
|
|
> .tab-button {
|
|
@include tab-button-size(1rem, 0);
|
|
}
|
|
|
|
&::part(tablist-wrapper)::before {
|
|
transition: all 0.3s ease-in-out, left, right 0s;
|
|
}
|
|
}
|
|
|
|
// Top placement
|
|
&[placement='top'] {
|
|
&::part(tablist-tab-wrapper) {
|
|
border-bottom: 2px solid fi-var(global-border-color);
|
|
}
|
|
|
|
&::part(tablist-wrapper)::before {
|
|
box-shadow: inset 0 -2px 0 fi-var(primary);
|
|
translate: 0 2px;
|
|
}
|
|
}
|
|
|
|
// Bottom placement
|
|
&[placement='bottom'] {
|
|
&::part(tablist-tab-wrapper) {
|
|
border-top: 2px solid fi-var(global-border-color);
|
|
}
|
|
|
|
&::part(tablist-wrapper)::before {
|
|
box-shadow: inset 0 2px 0 fi-var(primary);
|
|
translate: 0 -2px;
|
|
}
|
|
}
|
|
|
|
// Left placement
|
|
&[placement='left'] {
|
|
&::part(tablist-tab-wrapper) {
|
|
border-right: 2px solid fi-var(global-border-color);
|
|
}
|
|
|
|
&::part(tablist-wrapper)::before {
|
|
box-shadow: inset -2px 0 0 fi-var(primary);
|
|
translate: 2px 0;
|
|
}
|
|
|
|
> .tab-button {
|
|
text-align: right;
|
|
}
|
|
}
|
|
|
|
// Right placement
|
|
&[placement='right'] {
|
|
&::part(tablist-tab-wrapper) {
|
|
border-left: 2px solid fi-var(global-border-color);
|
|
}
|
|
|
|
&::part(tablist-wrapper)::before {
|
|
box-shadow: inset 2px 0 0 fi-var(primary);
|
|
translate: -2px 0;
|
|
}
|
|
|
|
> .tab-button {
|
|
text-align: left;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ========================================
|
|
// Style 2: Pill Style
|
|
// Rounded buttons with background
|
|
// ========================================
|
|
&[type='pill'] {
|
|
> .tab-button {
|
|
background-color: fi-var(code-inline-background-color);
|
|
@include tab-button-size;
|
|
@include border-radius(full);
|
|
|
|
&[aria-selected='true'] {
|
|
color: #ffffff;
|
|
background-color: fi-var(primary);
|
|
box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.3);
|
|
box-shadow: 0 0.125rem 0.5rem light-dark(rgba(0, 0, 0, 0.3), rgba(255, 255, 255, 0.3));
|
|
}
|
|
|
|
&[aria-selected='false']:hover {
|
|
background-color: light-dark(rgba(175, 184, 193, 0.4), rgba(99, 110, 123, 0.6));
|
|
}
|
|
}
|
|
|
|
&[placement='top'],
|
|
&[placement='bottom'] {
|
|
&::part(tablist-tab-wrapper) {
|
|
max-width: 100%;
|
|
}
|
|
|
|
&::part(tablist) {
|
|
flex-wrap: wrap;
|
|
row-gap: 0.5rem;
|
|
}
|
|
}
|
|
|
|
&[placement='left'],
|
|
&[placement='right'] {
|
|
padding-bottom: 0.5rem;
|
|
|
|
&::part(tablist) {
|
|
gap: 0.75rem;
|
|
}
|
|
}
|
|
|
|
// Top placement
|
|
&[placement='top'] {
|
|
> .tab-button {
|
|
&:hover {
|
|
translate: 0 2px;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Bottom placement
|
|
&[placement='bottom'] {
|
|
> .tab-button {
|
|
&:hover {
|
|
translate: 0 -2px;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Left placement
|
|
&[placement='left'] {
|
|
&::part(tablist) {
|
|
margin-left: 0.5rem;
|
|
}
|
|
|
|
> .tab-button {
|
|
&:hover {
|
|
translate: 2px 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Right placement
|
|
&[placement='right'] {
|
|
&::part(tablist) {
|
|
margin-right: 0.5rem;
|
|
}
|
|
|
|
> .tab-button {
|
|
&:hover {
|
|
translate: -2px 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ========================================
|
|
// Style 3: Card Style
|
|
// Card-like appearance with borders
|
|
// ========================================
|
|
&[type='card'] {
|
|
gap: 0;
|
|
|
|
&::part(tablist) {
|
|
gap: 0.25rem;
|
|
}
|
|
|
|
> .tab-button {
|
|
border: 1px solid fi-var(global-border-color);
|
|
background-color: fi-var(code-block-background-color);
|
|
@include tab-button-size(1.5rem);
|
|
|
|
&[aria-selected='true'],
|
|
&[aria-selected='false']:hover {
|
|
background-color: fi-var(global-background-color);
|
|
color: fi-var(global-link-color);
|
|
@include z-index(base);
|
|
}
|
|
}
|
|
|
|
> .tab-panel {
|
|
padding: 0.75rem;
|
|
background-color: fi-var(global-background-color);
|
|
border: 1px solid fi-var(global-border-color);
|
|
}
|
|
|
|
&[placement='top'],
|
|
&[placement='bottom'] {
|
|
&::part(tablist-wrapper) {
|
|
overflow-x: auto;
|
|
overflow-y: hidden;
|
|
}
|
|
|
|
> .tab-button {
|
|
&:first-of-type {
|
|
position: sticky;
|
|
left: 0;
|
|
@include z-index(base, 1);
|
|
}
|
|
|
|
&:last-of-type {
|
|
position: sticky;
|
|
right: 0;
|
|
@include z-index(base, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Top placement
|
|
&[placement='top'] {
|
|
&::part(tablist-tab-wrapper) {
|
|
border-bottom: 1px solid fi-var(global-border-color);
|
|
}
|
|
|
|
> .tab-button {
|
|
translate: 0 1px;
|
|
@include border-radius(top);
|
|
|
|
&[aria-selected='true'] {
|
|
border-bottom-color: fi-var(global-background-color);
|
|
}
|
|
}
|
|
|
|
> .tab-panel {
|
|
border-top: none;
|
|
@include border-radius(bottom);
|
|
}
|
|
}
|
|
|
|
// Bottom placement
|
|
&[placement='bottom'] {
|
|
&::part(tablist-tab-wrapper) {
|
|
border-top: 1px solid fi-var(global-border-color);
|
|
}
|
|
|
|
> .tab-button {
|
|
translate: 0 -1px;
|
|
@include border-radius(bottom);
|
|
|
|
&[aria-selected='true'] {
|
|
border-top-color: fi-var(global-background-color);
|
|
}
|
|
}
|
|
|
|
> .tab-panel {
|
|
border-bottom: none;
|
|
@include border-radius(top);
|
|
}
|
|
}
|
|
|
|
// Left placement
|
|
&[placement='left'] {
|
|
&::part(tablist-tab-wrapper) {
|
|
border-right: 1px solid fi-var(global-border-color);
|
|
}
|
|
|
|
> .tab-button {
|
|
translate: 1px 0;
|
|
@include border-radius(left);
|
|
|
|
&[aria-selected='true'] {
|
|
border-right-color: fi-var(global-background-color);
|
|
}
|
|
}
|
|
|
|
> .tab-panel {
|
|
border-left: none;
|
|
@include border-radius(right);
|
|
}
|
|
}
|
|
|
|
// Right placement
|
|
&[placement='right'] {
|
|
&::part(tablist-tab-wrapper) {
|
|
border-left: 1px solid fi-var(global-border-color);
|
|
}
|
|
|
|
> .tab-button {
|
|
translate: -1px 0;
|
|
@include border-radius(right);
|
|
|
|
&[aria-selected='true'] {
|
|
border-left-color: fi-var(global-background-color);
|
|
}
|
|
}
|
|
|
|
> .tab-panel {
|
|
border-right: none;
|
|
@include border-radius(left);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ========================================
|
|
// Style 4: Segment Style
|
|
// only top placement support
|
|
// ========================================
|
|
&[type='segment'] {
|
|
&::part(tablist-wrapper) {
|
|
overflow-x: auto;
|
|
overflow-y: hidden;
|
|
}
|
|
|
|
&::part(tablist-tab-wrapper) {
|
|
position: relative;
|
|
padding: 0.25rem;
|
|
background-color: fi-var(code-block-background-color);
|
|
@include border-radius;
|
|
}
|
|
|
|
&::part(tablist) {
|
|
gap: 0;
|
|
}
|
|
|
|
> .tab-button {
|
|
position: relative;
|
|
font-weight: 400;
|
|
flex-grow: 1;
|
|
@include z-index(base);
|
|
@include tab-button-size;
|
|
@include border-radius;
|
|
|
|
&[aria-selected='true'],
|
|
&:hover {
|
|
font-weight: 500;
|
|
}
|
|
|
|
&[aria-selected='true'] {
|
|
box-shadow: none;
|
|
}
|
|
}
|
|
|
|
&:not(:has(> .tab-button:hover)) > .tab-button[aria-selected='true'],
|
|
> .tab-button:hover {
|
|
anchor-name: #{$rootPrefix}tab-segment-active;
|
|
}
|
|
|
|
// Sliding active indicator via anchor positioning
|
|
&::part(tablist-tab-wrapper)::before {
|
|
content: '';
|
|
position: absolute;
|
|
pointer-events: none;
|
|
position-anchor: #{$rootPrefix}tab-segment-active;
|
|
top: anchor(top);
|
|
left: anchor(left);
|
|
width: anchor-size(width);
|
|
height: anchor-size(height);
|
|
background-color: fi-var(global-background-color);
|
|
transition:
|
|
top 0.3s ease,
|
|
left 0.3s ease,
|
|
width 0.3s ease,
|
|
height 0.3s ease;
|
|
box-shadow: 0 0.125rem 0.25rem light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1));
|
|
@include border-radius;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ========================================
|
|
// Responsive design for smaller screens
|
|
// ========================================
|
|
@include media('xs') {
|
|
tab-container {
|
|
&[type='underline'] {
|
|
&[placement='top'],
|
|
&[placement='bottom'] {
|
|
> .tab-button {
|
|
@include tab-button-size(0.875rem, 0);
|
|
}
|
|
|
|
&::part(tablist) {
|
|
gap: 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
&[type='pill'] {
|
|
&[placement='top'],
|
|
&[placement='bottom'] {
|
|
> .tab-button {
|
|
@include tab-button-size(1rem, 0);
|
|
}
|
|
|
|
&::part(tablist) {
|
|
gap: 0.375rem 0.5rem;
|
|
}
|
|
}
|
|
}
|
|
|
|
&[type='card'] {
|
|
> .tab-button {
|
|
@include tab-button-size(1rem);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ========================================
|
|
// Smooth animations
|
|
// ========================================
|
|
@keyframes tabSlideIn {
|
|
from {
|
|
opacity: 0;
|
|
translate: 0 10px;
|
|
}
|
|
|
|
to {
|
|
opacity: 1;
|
|
translate: 0 0;
|
|
}
|
|
}
|
|
|
|
tab-container .tab-panel:not([hidden]) {
|
|
animation: tabSlideIn 0.3s ease-out;
|
|
}
|
|
|
|
// Firefox fallback: `::part(...)::before` is not supported.
|
|
// We use a CSS variable to control the border color of the active tab button,
|
|
// and apply the sliding effect directly on the button itself.
|
|
@supports (-moz-appearance: none) {
|
|
tab-container {
|
|
&[type='underline'] {
|
|
> .tab-button {
|
|
@include set-fi-var(tab-button-border-color, transparent);
|
|
|
|
&[aria-selected='true'],
|
|
&[aria-selected='false']:hover {
|
|
@include set-fi-var(tab-button-border-color, fi-var(primary));
|
|
}
|
|
}
|
|
|
|
&[placement='top'] > .tab-button {
|
|
translate: 0 2px;
|
|
border-bottom: 2px solid fi-var(tab-button-border-color);
|
|
}
|
|
|
|
&[placement='bottom'] > .tab-button {
|
|
translate: 0 -2px;
|
|
border-top: 2px solid fi-var(tab-button-border-color);
|
|
}
|
|
|
|
&[placement='left'] > .tab-button {
|
|
translate: 2px 0;
|
|
border-right: 2px solid fi-var(tab-button-border-color);
|
|
}
|
|
|
|
&[placement='right'] > .tab-button {
|
|
translate: -2px 0;
|
|
border-left: 2px solid fi-var(tab-button-border-color);
|
|
}
|
|
}
|
|
|
|
&[type='segment'] {
|
|
> .tab-button {
|
|
&[aria-selected='true'] {
|
|
background-color: fi-var(global-background-color);
|
|
box-shadow: 0 0.125rem 0.25rem light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|