Skip to content
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
99 changes: 99 additions & 0 deletions src/components/slider/Example.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { useState } from "react";
import { Slider } from "./Slider";

export function SliderExamples() {
const [continuousValue, setContinuousValue] = useState(50);
const [discreteValue, setDiscreteValue] = useState(5);
const [intensityValue, setIntensityValue] = useState(7);
const [weightValue, setWeightValue] = useState(70);

return (
<div
style={{
width: "50%",
display: "flex",
flexDirection: "column",
gap: "2rem",
}}
>
{/* Example 1: Basic Continuous Slider */}
<section>
<Slider
min={0}
max={100}
value={continuousValue}
onChange={setContinuousValue}
label="Medium"
type="continuous"
/>
<p className={`caption`}>Selected: {continuousValue.toFixed(1)}</p>
</section>

{/* Example 2: Discrete Slider */}
<section>
<Slider
min={0}
max={10}
value={discreteValue}
onChange={setDiscreteValue}
label="Medium"
type="discrete"
step={1}
/>
<p className={`caption`}>Selected: {discreteValue}</p>
</section>

{/* Example 3: Small Size */}
<section>
<Slider
min={1}
max={10}
value={intensityValue}
onChange={setIntensityValue}
label="Small"
type="discrete"
step={1}
size="small"
/>
</section>

{/* Example 4: Large Size */}
<section>
<Slider
min={0}
max={100}
value={weightValue}
onChange={setWeightValue}
label="Large"
type="discrete"
step={10}
size="large"
/>
</section>
</div>
);
}

/**
* COMMON USE CASES IN PEAKFIT:
*
* 1. Workout Intensity Selection
* - 1-10 scale for perceived exertion
*
* 2. Rep/Set Ranges
* - Set target reps for exercises
*
* 3. Weight Selection
* - Choose working weight for exercises
*
* 4. Rest Time
* - Set rest periods between sets
*
* 5. Progress Tracking
* - Visual representation of goal completion
*
* 6. Nutrition Macros
* - Adjust protein/carb/fat ratios
*/

export default SliderExamples;
262 changes: 262 additions & 0 deletions src/components/slider/Slider.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
/* Slider.module.css - Uses PeakFit Theme System */

.container {
width: 100%;
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
}

.label {
display: block;
margin-bottom: 1rem;
color: var(--text-primary);
}

.sliderWrapper {
display: flex;
align-items: center;
gap: 1rem;
}

.value {
font-family: var(--font-ui);
font-size: 0.875rem;
font-weight: 500;
color: var(--text-secondary);
min-width: 2.5rem;
text-align: center;
}

.minValue {
text-align: right;
}

.maxValue {
text-align: left;
}

/* ===============================
Slider Track
=============================== */
.sliderTrack {
position: relative;
flex: 1;
background: var(--surface-tertiary);
border: 1px solid var(--border-default);
width: 100px;
border-radius: 100px;
cursor: pointer;
transition: all 0.2s ease;
}

/* Sizes */
.sliderTrack.small {
height: 8px;
}

.sliderTrack.medium {
height: 12px;
}

.sliderTrack.large {
height: 16px;
}

.sliderTrack:hover {
background: var(--surface-hover);
}

.sliderTrack.disabled {
opacity: 0.5;
cursor: not-allowed;
}

.sliderTrack.disabled:hover {
background: var(--surface-tertiary);
}

/* ===============================
Filled Track
=============================== */
.sliderFill {
position: absolute;
top: 0;
left: 0;
height: 100%;
background: var(--gradient-primary);
border-radius: 100px;
pointer-events: none;
/* No transition - instant response */
}

/* ===============================
Thumb
=============================== */
.thumb {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
background: var(--surface-primary);
border: 3px solid var(--primary-500);
border-radius: 50%;
box-shadow: var(--shadow-md);
transition: all 0.2s ease;
z-index: 2;
}

/* Thumb sizes based on track size */
.small .thumb {
width: 18px;
height: 18px;
}

.medium .thumb {
width: 22px;
height: 22px;
}

.large .thumb {
width: 26px;
height: 26px;
}

.thumb:hover {
transform: translate(-50%, -50%) scale(1.1);
box-shadow: var(--shadow-glow-primary);
}

/* Disable the width transition while dragging */
.sliderFill.dragging {
transition: none;
}

/* Update your existing .thumb.dragging class */
.thumb.dragging {
transform: translate(-50%, -50%) scale(1.15);
box-shadow: var(--shadow-glow-primary);
/* Override 'transition: all' so 'left' updates instantly,
but keep the smooth scale and glow effect */
transition: transform 0.2s ease, box-shadow 0.2s ease;
}

.disabled .thumb {
cursor: not-allowed;
}

.disabled .thumb:hover {
transform: translate(-50%, -50%);
box-shadow: var(--shadow-md);
}

/* ===============================
Tooltip
=============================== */
.tooltip {
position: absolute;
bottom: calc(100% + 12px);
left: 50%;
transform: translateX(-50%);
padding: 0.375rem 0.75rem;
background: var(--surface-secondary);
border: 1px solid var(--border-strong);
border-radius: 8px;
color: var(--text-primary);
font-family: var(--font-ui);
font-size: 0.875rem;
font-weight: 600;
white-space: nowrap;
box-shadow: var(--shadow-lg);
pointer-events: none;
animation: tooltipFadeIn 0.2s ease-out;
z-index: 10;
}

.tooltip::after {
content: "";
position: absolute;
top: 100%;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 6px solid var(--surface-secondary);
}

@keyframes tooltipFadeIn {
from {
opacity: 0;
transform: translateX(-50%) translateY(-4px);
}
to {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
}
Comment on lines +192 to +201
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Rename tooltipFadeIn to tooltip-fade-in to satisfy the Stylelint keyframes-name-pattern rule.

The @keyframes name and its reference in .tooltip (line 175) must be updated together.

🐛 Proposed fix
-@keyframes tooltipFadeIn {
+@keyframes tooltip-fade-in {

And in .tooltip:

-  animation: tooltipFadeIn 0.2s ease-out;
+  animation: tooltip-fade-in 0.2s ease-out;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@keyframes tooltipFadeIn {
from {
opacity: 0;
transform: translateX(-50%) translateY(-4px);
}
to {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
}
`@keyframes` tooltip-fade-in {
from {
opacity: 0;
transform: translateX(-50%) translateY(-4px);
}
to {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
}
🧰 Tools
🪛 Stylelint (17.3.0)

[error] 192-192: Expected keyframe name "tooltipFadeIn" to be kebab-case (keyframes-name-pattern)

(keyframes-name-pattern)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/slider/Slider.module.css` around lines 192 - 201, Rename the
`@keyframes` identifier tooltipFadeIn to tooltip-fade-in and update the reference
inside the .tooltip rule so both match the new kebab-case name; locate the
`@keyframes` block named tooltipFadeIn and the .tooltip selector that uses
animation/animation-name and change its reference to tooltip-fade-in to satisfy
the Stylelint keyframes-name-pattern rule.


/* ===============================
Discrete Steps
=============================== */
.stepsContainer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
display: flex;
justify-content: center;
align-items: center;
}

.stepsSubContainer {
display: flex;
justify-content: space-between;
align-items: center;
width: 98%;
height: 100%;
}

.stepMarker {
width: 4px;
height: 4px;
background: var(--surface-hover);
border-radius: 50%;
transition: all 0.2s ease;
background: var(--primary-400);
}
Comment on lines +226 to +233
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove the dead first background declaration on .stepMarker.

Stylelint flags a duplicate background property (lines 229 and 232). The first value (var(--surface-hover)) is immediately overridden and never applied.

🐛 Proposed fix
 .stepMarker {
   width: 4px;
   height: 4px;
-  background: var(--surface-hover);
   border-radius: 50%;
   transition: all 0.2s ease;
   background: var(--primary-400);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
.stepMarker {
width: 4px;
height: 4px;
background: var(--surface-hover);
border-radius: 50%;
transition: all 0.2s ease;
background: var(--primary-400);
}
.stepMarker {
width: 4px;
height: 4px;
border-radius: 50%;
transition: all 0.2s ease;
background: var(--primary-400);
}
🧰 Tools
🪛 Stylelint (17.3.0)

[error] 229-229: Unexpected duplicate "background" (declaration-block-no-duplicate-properties)

(declaration-block-no-duplicate-properties)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/slider/Slider.module.css` around lines 226 - 233, The
.stepMarker CSS rule contains two background declarations; remove the dead first
background: delete the line setting background: var(--surface-hover) inside the
.stepMarker rule so only background: var(--primary-400) remains (locate the
.stepMarker selector in Slider.module.css).


.stepMarker.active {
background: var(--primary-100);
}

/* Hide step markers on small size for cleaner look */
.small .stepMarker {
width: 3px;
height: 3px;
}

/* ===============================
Responsive
=============================== */
@media (max-width: 640px) {
.sliderWrapper {
gap: 0.75rem;
}

.value {
font-size: 0.75rem;
min-width: 2rem;
}

.tooltip {
font-size: 0.75rem;
padding: 0.25rem 0.5rem;
}
}
Loading