astro-component-kit 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +218 -119
- package/package.json +25 -52
- package/src/components/index.ts +207 -0
- package/src/components/lib/AnimatedGalaxy.astro +185 -0
- package/src/components/lib/Galaxy3D.astro +308 -0
- package/src/components/lib/GlassNavbar.astro +13 -11
- package/src/components/lib/LogoWithGalaxy.astro +63 -0
- package/src/components/lib/buttons/3dPushButton.astro +9 -0
- package/src/components/lib/buttons/AnimatedIconButton.astro +10 -0
- package/src/components/lib/buttons/BorderDrawButton.astro +9 -0
- package/src/components/lib/buttons/CyberpunkButton.astro +10 -0
- package/src/components/lib/buttons/DoubleBorderButton.astro +9 -0
- package/src/components/lib/buttons/GhostOutlineButton.astro +10 -0
- package/src/components/lib/buttons/GlassButton.astro +13 -32
- package/src/components/lib/buttons/GlowButton.astro +9 -0
- package/src/components/lib/buttons/LiquidButton.astro +9 -0
- package/src/components/lib/buttons/LoadingButton.astro +10 -0
- package/src/components/lib/buttons/MagneticButton.astro +10 -0
- package/src/components/lib/buttons/MinimalPillButton.astro +9 -0
- package/src/components/lib/buttons/NeumorphicButton.astro +10 -0
- package/src/components/lib/buttons/PulseButton.astro +10 -0
- package/src/components/lib/buttons/RetroArcadeButton.astro +9 -0
- package/src/components/lib/buttons/RetroShadowButton.astro +9 -0
- package/src/components/lib/buttons/ShimmerButton.astro +9 -0
- package/src/components/lib/buttons/ShinyButton.astro +9 -0
- package/src/components/lib/buttons/TiltGlowButton.astro +10 -0
- package/src/components/lib/cards/BlogHorizontalCard.astro +46 -13
- package/src/components/lib/cards/CyberFeatureCard.astro +50 -6
- package/src/components/lib/cards/EcommerceProductCard.astro +69 -16
- package/src/components/lib/cards/GlassCard.astro +8 -0
- package/src/components/lib/cards/GlassEventCard.astro +53 -12
- package/src/components/lib/cards/GlowPortfolioCard.astro +46 -9
- package/src/components/lib/cards/InteractiveTiltCard.astro +47 -7
- package/src/components/lib/cards/KanbanItemCard.astro +40 -9
- package/src/components/lib/cards/MinimalLinkCard.astro +37 -7
- package/src/components/lib/cards/MusicPlayerMini.astro +54 -14
- package/src/components/lib/cards/NeumorphicCard.astro +32 -2
- package/src/components/lib/cards/NotificationCard.astro +44 -9
- package/src/components/lib/cards/PricingCard.astro +47 -9
- package/src/components/lib/cards/ProfileCard.astro +50 -11
- package/src/components/lib/cards/RetroGameCard.astro +37 -9
- package/src/components/lib/cards/StatCard.astro +43 -8
- package/src/components/lib/cards/TaskKanbanCard.astro +50 -11
- package/src/components/lib/cards/TestimonialCardClean.astro +43 -12
- package/src/components/lib/cards/WeatherWidgetCard.astro +36 -10
- package/src/components/lib/feedback/AnimatedCheckmark.astro +58 -9
- package/src/components/lib/feedback/Badge.astro +47 -12
- package/src/components/lib/feedback/CircleProgress.astro +56 -13
- package/src/components/lib/feedback/ConfettiFeedback.astro +74 -11
- package/src/components/lib/feedback/CyberGlitchAlert.astro +69 -6
- package/src/components/lib/feedback/EmptyStateCard.astro +55 -7
- package/src/components/lib/feedback/GlassAlert.astro +59 -13
- package/src/components/lib/feedback/GlassModal.astro +99 -14
- package/src/components/lib/feedback/GlassProgress.astro +39 -5
- package/src/components/lib/feedback/IndicatorBadgeMinimal.astro +56 -3
- package/src/components/lib/feedback/NeonSpinner.astro +40 -3
- package/src/components/lib/feedback/PulseDot.astro +51 -7
- package/src/components/lib/feedback/RatingPill.astro +38 -8
- package/src/components/lib/feedback/ShakeErrorGroup.astro +44 -3
- package/src/components/lib/feedback/SimpleTooltip.astro +53 -4
- package/src/components/lib/feedback/SkeletonList.astro +59 -13
- package/src/components/lib/feedback/Spotlight.astro +49 -4
- package/src/components/lib/feedback/StepProgress.astro +96 -9
- package/src/components/lib/feedback/ToastNotif.astro +60 -6
- package/src/components/lib/feedback/TypingIndicator.astro +52 -7
- package/src/components/lib/forms/AnimatedInput.astro +47 -5
- package/src/components/lib/forms/ChipInput.astro +116 -8
- package/src/components/lib/forms/ColorPickerInput.astro +53 -6
- package/src/components/lib/forms/CurrencyInput.astro +59 -6
- package/src/components/lib/forms/CustomRadioGroup.astro +61 -9
- package/src/components/lib/forms/CyberpunkCheckbox.astro +64 -8
- package/src/components/lib/forms/DragDropUpload.astro +87 -7
- package/src/components/lib/forms/ErrorInput.astro +31 -4
- package/src/components/lib/forms/FloatingPassword.astro +48 -10
- package/src/components/lib/forms/FormGroupVertical.astro +63 -9
- package/src/components/lib/forms/GlassSlider.astro +84 -3
- package/src/components/lib/forms/GlassTextarea.astro +39 -6
- package/src/components/lib/forms/ModernSelect.astro +66 -10
- package/src/components/lib/forms/NeumorphicSwitch.astro +54 -26
- package/src/components/lib/forms/OTPInput.astro +84 -12
- package/src/components/lib/forms/RatingStars.astro +66 -10
- package/src/components/lib/forms/SearchReveal.astro +44 -6
- package/src/components/lib/forms/SegmentedControl.astro +61 -7
- package/src/components/lib/forms/SimpleFileInput.astro +57 -6
- package/src/components/lib/forms/StepperInput.astro +101 -9
- package/src/components/lib/layout/FeatureHero.astro +70 -6
- package/src/components/lib/layout/FooterCenteredMinimal.astro +5 -2
- package/src/components/lib/navigation/GlassNavbar.astro +10 -5
- package/src/components/lib/navigation/MinimalSidebar.astro +6 -3
- package/src/components/lib/navigation/SimpleFooterGlass.astro +6 -2
- package/src/components/lib/overlays/SplashIntroOverlay.astro +6 -3
- package/src/components/lib/sections/ButtonsShowcase.astro +182 -0
- package/src/components/lib/sections/CardsShowcase.astro +376 -0
- package/src/components/lib/sections/DataShowcase.astro +329 -0
- package/src/components/lib/sections/FeedbackShowcase.astro +320 -0
- package/src/components/lib/sections/FormsShowcase.astro +347 -0
- package/src/components/lib/sections/HeroGlass.astro +202 -0
- package/src/components/lib/sections/HeroGradient.astro +143 -0
- package/src/components/lib/sections/HeroSplit.astro +210 -0
- package/src/components/lib/sections/LayoutShowcase.astro +317 -0
- package/src/components/lib/sections/NavigationShowcase.astro +285 -0
- package/src/components/lib/sections/OverlaysShowcase.astro +373 -0
- package/src/components/lib/sections/TypographyShowcase.astro +239 -0
- package/src/components/lib/sections/index.ts +9 -0
- package/src/components/types.d.ts +6 -0
- package/{dist → src}/styles/global.css +5 -5
- package/dist/AnimatedInput.astro +0 -82
- package/dist/Badge.astro +0 -52
- package/dist/GlassButton.astro +0 -87
- package/dist/GlassCard.astro +0 -72
- package/dist/GlassNavbar.astro +0 -65
- package/dist/GlowButton.astro +0 -60
- package/dist/buttons/3dPushButton.astro +0 -136
- package/dist/buttons/AnimatedIconButton.astro +0 -146
- package/dist/buttons/BorderDrawButton.astro +0 -112
- package/dist/buttons/CyberpunkButton.astro +0 -148
- package/dist/buttons/DoubleBorderButton.astro +0 -131
- package/dist/buttons/GhostOutlineButton.astro +0 -109
- package/dist/buttons/GlassButton.astro +0 -165
- package/dist/buttons/GlowButton.astro +0 -119
- package/dist/buttons/LiquidButton.astro +0 -167
- package/dist/buttons/LoadingButton.astro +0 -148
- package/dist/buttons/MagneticButton.astro +0 -134
- package/dist/buttons/MinimalPillButton.astro +0 -102
- package/dist/buttons/NeumorphicButton.astro +0 -158
- package/dist/buttons/PulseButton.astro +0 -111
- package/dist/buttons/RetroArcadeButton.astro +0 -105
- package/dist/buttons/RetroShadowButton.astro +0 -82
- package/dist/buttons/ShimmerButton.astro +0 -113
- package/dist/buttons/ShinyButton.astro +0 -121
- package/dist/buttons/TiltGlowButton.astro +0 -145
- package/dist/buttons/index.mjs +0 -19
- package/dist/buttons/index.ts +0 -19
- package/dist/cards/BlogHorizontalCard.astro +0 -18
- package/dist/cards/CyberFeatureCard.astro +0 -12
- package/dist/cards/EcommerceProductCard.astro +0 -24
- package/dist/cards/GlassCard.astro +0 -17
- package/dist/cards/GlassEventCard.astro +0 -19
- package/dist/cards/GlowPortfolioCard.astro +0 -16
- package/dist/cards/InteractiveTiltCard.astro +0 -25
- package/dist/cards/KanbanItemCard.astro +0 -15
- package/dist/cards/MinimalLinkCard.astro +0 -12
- package/dist/cards/MusicPlayerMini.astro +0 -21
- package/dist/cards/NeumorphicCard.astro +0 -6
- package/dist/cards/NotificationCard.astro +0 -15
- package/dist/cards/PricingCard.astro +0 -17
- package/dist/cards/ProfileCard.astro +0 -17
- package/dist/cards/RetroGameCard.astro +0 -15
- package/dist/cards/StatCard.astro +0 -15
- package/dist/cards/TaskKanbanCard.astro +0 -18
- package/dist/cards/TestimonialCardClean.astro +0 -20
- package/dist/cards/WeatherWidgetCard.astro +0 -17
- package/dist/cards/index.mjs +0 -19
- package/dist/cards/index.ts +0 -19
- package/dist/data/AccordionGroupGlass.astro +0 -21
- package/dist/data/AvatarGroupStack.astro +0 -15
- package/dist/data/CalendarGridView.astro +0 -18
- package/dist/data/DataChipsGroup.astro +0 -16
- package/dist/data/DescriptionListHoriz.astro +0 -14
- package/dist/data/FileTreeView.astro +0 -22
- package/dist/data/GanttChartMinimal.astro +0 -12
- package/dist/data/GlassTable.astro +0 -23
- package/dist/data/KeyValuePillGroup.astro +0 -12
- package/dist/data/PriceCompareTable.astro +0 -22
- package/dist/data/ProgressListSmall.astro +0 -17
- package/dist/data/RatingBreakdownBar.astro +0 -13
- package/dist/data/SparklineStatCard.astro +0 -16
- package/dist/data/StatsGridDashboard.astro +0 -16
- package/dist/data/StepperDataVertical.astro +0 -15
- package/dist/data/TagCloudData.astro +0 -14
- package/dist/data/TimelineHorizSteps.astro +0 -18
- package/dist/data/TreeItemInteractive.astro +0 -18
- package/dist/data/UserDirectoryItem.astro +0 -15
- package/dist/data/VerticalTimeline.astro +0 -21
- package/dist/data/index.mjs +0 -20
- package/dist/data/index.ts +0 -20
- package/dist/feedback/AnimatedCheckmark.astro +0 -13
- package/dist/feedback/Badge.astro +0 -19
- package/dist/feedback/CircleProgress.astro +0 -22
- package/dist/feedback/ConfettiFeedback.astro +0 -18
- package/dist/feedback/CyberGlitchAlert.astro +0 -11
- package/dist/feedback/EmptyStateCard.astro +0 -13
- package/dist/feedback/GlassAlert.astro +0 -20
- package/dist/feedback/GlassModal.astro +0 -19
- package/dist/feedback/GlassProgress.astro +0 -10
- package/dist/feedback/IndicatorBadgeMinimal.astro +0 -10
- package/dist/feedback/NeonSpinner.astro +0 -7
- package/dist/feedback/PulseDot.astro +0 -12
- package/dist/feedback/RatingPill.astro +0 -13
- package/dist/feedback/ShakeErrorGroup.astro +0 -7
- package/dist/feedback/SimpleTooltip.astro +0 -10
- package/dist/feedback/SkeletonList.astro +0 -20
- package/dist/feedback/Spotlight.astro +0 -9
- package/dist/feedback/StepProgress.astro +0 -14
- package/dist/feedback/ToastNotif.astro +0 -11
- package/dist/feedback/TypingIndicator.astro +0 -12
- package/dist/feedback/index.mjs +0 -20
- package/dist/feedback/index.ts +0 -20
- package/dist/forms/AnimatedInput.astro +0 -16
- package/dist/forms/ChipInput.astro +0 -13
- package/dist/forms/ColorPickerInput.astro +0 -13
- package/dist/forms/CurrencyInput.astro +0 -11
- package/dist/forms/CustomRadioGroup.astro +0 -13
- package/dist/forms/CyberpunkCheckbox.astro +0 -15
- package/dist/forms/DragDropUpload.astro +0 -12
- package/dist/forms/ErrorInput.astro +0 -11
- package/dist/forms/FloatingPassword.astro +0 -20
- package/dist/forms/FormGroupVertical.astro +0 -14
- package/dist/forms/GlassSlider.astro +0 -7
- package/dist/forms/GlassTextarea.astro +0 -14
- package/dist/forms/ModernSelect.astro +0 -16
- package/dist/forms/NeumorphicSwitch.astro +0 -55
- package/dist/forms/OTPInput.astro +0 -22
- package/dist/forms/RatingStars.astro +0 -15
- package/dist/forms/SearchReveal.astro +0 -13
- package/dist/forms/SegmentedControl.astro +0 -13
- package/dist/forms/SimpleFileInput.astro +0 -11
- package/dist/forms/StepperInput.astro +0 -14
- package/dist/forms/index.mjs +0 -20
- package/dist/forms/index.ts +0 -20
- package/dist/index.js +0 -1
- package/dist/index.mjs +0 -1
- package/dist/layout/BentoGrid3.astro +0 -14
- package/dist/layout/CenterFixedBox.astro +0 -6
- package/dist/layout/CenteredContainer.astro +0 -8
- package/dist/layout/ClusterHorizontal.astro +0 -6
- package/dist/layout/FeatureHero.astro +0 -17
- package/dist/layout/FooterCenteredMinimal.astro +0 -11
- package/dist/layout/FullBleedSection.astro +0 -6
- package/dist/layout/GalleryGrid4.astro +0 -7
- package/dist/layout/GlassCardGrid.astro +0 -6
- package/dist/layout/GlassSectionHeader.astro +0 -15
- package/dist/layout/LandingSectionSplit.astro +0 -13
- package/dist/layout/MasonryGrid.astro +0 -7
- package/dist/layout/MinimalFooterGrid.astro +0 -20
- package/dist/layout/ScrollSnapSection.astro +0 -7
- package/dist/layout/SectionDividerText.astro +0 -7
- package/dist/layout/SidebarLayoutWrapper.astro +0 -11
- package/dist/layout/SplitScreenLayout.astro +0 -11
- package/dist/layout/StepLayoutVertical.astro +0 -21
- package/dist/layout/StickySidebarWrapper.astro +0 -10
- package/dist/layout/VerticalStack.astro +0 -8
- package/dist/layout/index.mjs +0 -20
- package/dist/layout/index.ts +0 -20
- package/dist/navigation/AnchorSideNav.astro +0 -13
- package/dist/navigation/BottomNavMobile.astro +0 -13
- package/dist/navigation/BreadcrumbsMinimal.astro +0 -16
- package/dist/navigation/BurgerMorphIcon.astro +0 -12
- package/dist/navigation/CommandPaletteUI.astro +0 -17
- package/dist/navigation/DotNavigationSlider.astro +0 -13
- package/dist/navigation/FloatingTabBar.astro +0 -12
- package/dist/navigation/GlassNavbar.astro +0 -19
- package/dist/navigation/LangSwitcherPill.astro +0 -17
- package/dist/navigation/MegaMenuGlass.astro +0 -25
- package/dist/navigation/MinimalSidebar.astro +0 -18
- package/dist/navigation/PaginationGlass.astro +0 -20
- package/dist/navigation/PaginationInfiniteUI.astro +0 -11
- package/dist/navigation/RadialIconMenu.astro +0 -15
- package/dist/navigation/RetroArcadeMenu.astro +0 -12
- package/dist/navigation/ScrollProgressTop.astro +0 -15
- package/dist/navigation/SimpleFooterGlass.astro +0 -21
- package/dist/navigation/TabUnderline.astro +0 -14
- package/dist/navigation/UserProfileNav.astro +0 -21
- package/dist/navigation/VerticalTabs.astro +0 -14
- package/dist/navigation/index.mjs +0 -20
- package/dist/navigation/index.ts +0 -20
- package/dist/overlays/AgeVerificationOverlay.astro +0 -20
- package/dist/overlays/BackdropBlurMask.astro +0 -6
- package/dist/overlays/BottomSheetMobile.astro +0 -16
- package/dist/overlays/CommandDialog.astro +0 -19
- package/dist/overlays/ContextMenuOverlay.astro +0 -17
- package/dist/overlays/CookieBannerGlass.astro +0 -14
- package/dist/overlays/ExitIntentOverlay.astro +0 -19
- package/dist/overlays/FloatingTrayActions.astro +0 -13
- package/dist/overlays/HelpBubbleOverlay.astro +0 -11
- package/dist/overlays/LightboxOverlay.astro +0 -13
- package/dist/overlays/LoadingOverlayFull.astro +0 -10
- package/dist/overlays/MobileNavOverlay.astro +0 -18
- package/dist/overlays/OverlayModal.astro +0 -24
- package/dist/overlays/PopoverMenuGlass.astro +0 -17
- package/dist/overlays/SearchOverlayFullscreen.astro +0 -15
- package/dist/overlays/SideDrawerRight.astro +0 -16
- package/dist/overlays/SplashIntroOverlay.astro +0 -11
- package/dist/overlays/SpotlightIndicator.astro +0 -6
- package/dist/overlays/ToastStackOverlay.astro +0 -12
- package/dist/overlays/TooltipActionTray.astro +0 -14
- package/dist/overlays/index.mjs +0 -20
- package/dist/overlays/index.ts +0 -20
- package/dist/typography/AnimatedUnderlineLink.astro +0 -10
- package/dist/typography/BackgroundClipMask.astro +0 -7
- package/dist/typography/CodeInlineGlass.astro +0 -6
- package/dist/typography/CyberpunkGlitchText.astro +0 -20
- package/dist/typography/DropCapParagraph.astro +0 -7
- package/dist/typography/FadedVerticalText.astro +0 -6
- package/dist/typography/FloatingTextLabel.astro +0 -10
- package/dist/typography/GlassBlockQuote.astro +0 -13
- package/dist/typography/GlassTextReveal.astro +0 -7
- package/dist/typography/GradientHeading.astro +0 -9
- package/dist/typography/GradientUnderlineLink.astro +0 -7
- package/dist/typography/KbdIndicator.astro +0 -6
- package/dist/typography/LetterSpacingWide.astro +0 -6
- package/dist/typography/MinimalListMarkers.astro +0 -10
- package/dist/typography/MonospaceStatLine.astro +0 -6
- package/dist/typography/NeonTextHighlight.astro +0 -6
- package/dist/typography/ShadowRevealText.astro +0 -7
- package/dist/typography/StrokeHeadingOutline.astro +0 -8
- package/dist/typography/Text3DLayer.astro +0 -7
- package/dist/typography/TypewriterText.astro +0 -15
- package/dist/typography/index.mjs +0 -20
- package/dist/typography/index.ts +0 -20
- package/dist/utilities/AspectRatioBox.astro +0 -11
- package/dist/utilities/BackgroundDotPattern.astro +0 -6
- package/dist/utilities/CircularMask.astro +0 -7
- package/dist/utilities/ClickRippleWrapper.astro +0 -7
- package/dist/utilities/FadeInWrapper.astro +0 -11
- package/dist/utilities/FixedRatioImage.astro +0 -7
- package/dist/utilities/GlassBlurLayer.astro +0 -6
- package/dist/utilities/GradientBorderMask.astro +0 -7
- package/dist/utilities/HoverLift.astro +0 -7
- package/dist/utilities/ResponsiveSpacer.astro +0 -15
- package/dist/utilities/ResponsiveVisToggle.astro +0 -11
- package/dist/utilities/ScrollLockParent.astro +0 -11
- package/dist/utilities/ScrollMarginTarget.astro +0 -10
- package/dist/utilities/SlideUpReveal.astro +0 -7
- package/dist/utilities/SmoothAnchorLink.astro +0 -22
- package/dist/utilities/StackLayering.astro +0 -12
- package/dist/utilities/StickyObserver.astro +0 -8
- package/dist/utilities/TextTruncate.astro +0 -10
- package/dist/utilities/TruncateSingleLine.astro +0 -6
- package/dist/utilities/VisuallyHidden.astro +0 -6
- package/dist/utilities/index.mjs +0 -20
- package/dist/utilities/index.ts +0 -20
- package/src/components/lib/utilities/AspectRatioBox.astro +0 -11
- package/src/components/lib/utilities/BackgroundDotPattern.astro +0 -6
- package/src/components/lib/utilities/CircularMask.astro +0 -7
- package/src/components/lib/utilities/ClickRippleWrapper.astro +0 -7
- package/src/components/lib/utilities/FadeInWrapper.astro +0 -11
- package/src/components/lib/utilities/FixedRatioImage.astro +0 -7
- package/src/components/lib/utilities/GlassBlurLayer.astro +0 -6
- package/src/components/lib/utilities/GradientBorderMask.astro +0 -7
- package/src/components/lib/utilities/HoverLift.astro +0 -7
- package/src/components/lib/utilities/ResponsiveSpacer.astro +0 -15
- package/src/components/lib/utilities/ResponsiveVisToggle.astro +0 -11
- package/src/components/lib/utilities/ScrollLockParent.astro +0 -11
- package/src/components/lib/utilities/ScrollMarginTarget.astro +0 -10
- package/src/components/lib/utilities/SlideUpReveal.astro +0 -7
- package/src/components/lib/utilities/SmoothAnchorLink.astro +0 -22
- package/src/components/lib/utilities/StackLayering.astro +0 -12
- package/src/components/lib/utilities/StickyObserver.astro +0 -8
- package/src/components/lib/utilities/TextTruncate.astro +0 -10
- package/src/components/lib/utilities/TruncateSingleLine.astro +0 -6
- package/src/components/lib/utilities/VisuallyHidden.astro +0 -6
- package/src/components/lib/utilities/index.ts +0 -20
|
@@ -1,55 +1,83 @@
|
|
|
1
1
|
---
|
|
2
|
+
/**
|
|
3
|
+
* NeumorphicSwitch — A soft-UI checkbox toggle with realistic inset and outset shadow states.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} label - Optional descriptive text suffix.
|
|
6
|
+
* @param {string} id - HTML ID for input linkage.
|
|
7
|
+
* @param {string} name - HTML name binding.
|
|
8
|
+
* @param {boolean} checked - Initial toggle state. Default is false.
|
|
9
|
+
*/
|
|
10
|
+
interface Props {
|
|
11
|
+
label?: string;
|
|
12
|
+
id: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
checked?: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const { label, id, name, checked = false } = Astro.props;
|
|
2
18
|
---
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<
|
|
6
|
-
|
|
19
|
+
|
|
20
|
+
<div class="neu-switch-wrapper">
|
|
21
|
+
<label class="neu-switch">
|
|
22
|
+
<input type="checkbox" {id} {name} {checked} />
|
|
23
|
+
<span class="slider"></span>
|
|
24
|
+
</label>
|
|
25
|
+
{label && <label for={id} class="neu-label">{label}</label>}
|
|
26
|
+
</div>
|
|
27
|
+
|
|
7
28
|
<style>
|
|
29
|
+
.neu-switch-wrapper { display: flex; align-items: center; gap: var(--sp-3, 0.75rem); }
|
|
30
|
+
|
|
8
31
|
.neu-switch {
|
|
9
32
|
position: relative;
|
|
10
33
|
display: inline-block;
|
|
11
|
-
width:
|
|
12
|
-
height:
|
|
34
|
+
width: 60px;
|
|
35
|
+
height: 32px;
|
|
36
|
+
flex-shrink: 0;
|
|
13
37
|
}
|
|
38
|
+
|
|
39
|
+
.neu-label { font-size: 0.9rem; color: var(--c-text-2, #94a3b8); cursor: pointer; }
|
|
40
|
+
|
|
14
41
|
.neu-switch input {
|
|
15
42
|
opacity: 0;
|
|
16
43
|
width: 0;
|
|
17
44
|
height: 0;
|
|
18
45
|
}
|
|
46
|
+
|
|
19
47
|
.slider {
|
|
20
48
|
position: absolute;
|
|
21
49
|
cursor: pointer;
|
|
22
50
|
inset: 0;
|
|
23
|
-
background: #1a1f2e;
|
|
24
|
-
transition: 0.4s;
|
|
51
|
+
background: var(--c-bg, #1a1f2e);
|
|
52
|
+
transition: 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
|
25
53
|
border-radius: 34px;
|
|
26
|
-
border: 1px solid rgba(255, 255, 255, 0.05);
|
|
54
|
+
border: 1px solid var(--c-border, rgba(255, 255, 255, 0.05));
|
|
27
55
|
box-shadow:
|
|
28
|
-
inset 2px 2px
|
|
29
|
-
inset -2px -2px
|
|
56
|
+
inset 2px 2px 5px rgba(0, 0, 0, 0.5),
|
|
57
|
+
inset -2px -2px 5px rgba(255, 255, 255, 0.04);
|
|
30
58
|
}
|
|
59
|
+
|
|
31
60
|
.slider:before {
|
|
32
61
|
position: absolute;
|
|
33
62
|
content: "";
|
|
34
|
-
height:
|
|
35
|
-
width:
|
|
36
|
-
left:
|
|
37
|
-
|
|
38
|
-
background: #
|
|
39
|
-
transition: 0.4s;
|
|
63
|
+
height: 24px;
|
|
64
|
+
width: 24px;
|
|
65
|
+
left: 4px;
|
|
66
|
+
bottom: 3px;
|
|
67
|
+
background: #374151;
|
|
68
|
+
transition: 0.4s cubic-bezier(0.18, 0.89, 0.32, 1.28);
|
|
40
69
|
border-radius: 50%;
|
|
41
|
-
box-shadow: 0
|
|
70
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.4);
|
|
42
71
|
}
|
|
72
|
+
|
|
43
73
|
input:checked + .slider {
|
|
44
|
-
background:
|
|
45
|
-
|
|
46
|
-
inset 2px 2px 4px rgba(0, 0, 0, 0.5),
|
|
47
|
-
inset -2px -2px 4px rgba(255, 255, 255, 0.02);
|
|
74
|
+
background: rgba(99, 102, 241, 0.1);
|
|
75
|
+
border-color: rgba(99, 102, 241, 0.2);
|
|
48
76
|
}
|
|
77
|
+
|
|
49
78
|
input:checked + .slider:before {
|
|
50
|
-
transform: translateX(
|
|
51
|
-
background: #818cf8;
|
|
52
|
-
box-shadow: 0 0
|
|
79
|
+
transform: translateX(28px);
|
|
80
|
+
background: var(--c-primary, #818cf8);
|
|
81
|
+
box-shadow: 0 0 15px rgba(129, 140, 248, 0.5);
|
|
53
82
|
}
|
|
54
83
|
</style>
|
|
55
|
-
|
|
@@ -1,22 +1,94 @@
|
|
|
1
1
|
---
|
|
2
|
+
/**
|
|
3
|
+
* OTPInput — A specialized input group for One-Time Password verification codes.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} label - Optional grouping label title.
|
|
6
|
+
* @param {string} id - Base HTML ID for the inputs.
|
|
7
|
+
* @param {number} length - Number of OTP digits. Default is 4.
|
|
8
|
+
* @param {string} name - Base name for form submission (will be indexed).
|
|
9
|
+
*/
|
|
10
|
+
interface Props {
|
|
11
|
+
label?: string;
|
|
12
|
+
id: string;
|
|
13
|
+
length?: number;
|
|
14
|
+
name?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const { label, id, length = 4, name = "otp" } = Astro.props;
|
|
2
18
|
---
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<
|
|
6
|
-
<
|
|
7
|
-
|
|
19
|
+
|
|
20
|
+
<div class="otp-container">
|
|
21
|
+
{label && <label class="otp-label">{label}</label>}
|
|
22
|
+
<div class="otp-wrap" data-otp-group>
|
|
23
|
+
{Array.from({ length }).map((_, i) => (
|
|
24
|
+
<input
|
|
25
|
+
type="text"
|
|
26
|
+
inputmode="numeric"
|
|
27
|
+
maxlength="1"
|
|
28
|
+
pattern="[0-9]*"
|
|
29
|
+
autocomplete="one-time-code"
|
|
30
|
+
id={`${id}-${i}`}
|
|
31
|
+
name={`${name}[]`}
|
|
32
|
+
class="otp-field"
|
|
33
|
+
data-otp-index={i}
|
|
34
|
+
/>
|
|
35
|
+
))}
|
|
36
|
+
</div>
|
|
8
37
|
</div>
|
|
38
|
+
|
|
9
39
|
<style>
|
|
40
|
+
.otp-container { display: flex; flex-direction: column; align-items: center; gap: var(--sp-4, 1rem); }
|
|
41
|
+
.otp-label { font-size: 0.9rem; font-weight: 600; color: var(--c-text-2, #94a3b8); }
|
|
42
|
+
|
|
10
43
|
.otp-wrap { display: flex; gap: 0.75rem; justify-content: center; }
|
|
11
|
-
|
|
12
|
-
.otp-
|
|
44
|
+
|
|
45
|
+
.otp-field {
|
|
46
|
+
width: 50px; height: 60px;
|
|
47
|
+
background: var(--c-bg-elev, rgba(255,255,255,0.05));
|
|
48
|
+
border: 1px solid var(--c-border, rgba(255,255,255,0.1));
|
|
49
|
+
border-radius: var(--r-md, 12px);
|
|
50
|
+
text-align: center; color: var(--c-text-1, #fff);
|
|
51
|
+
font-size: 1.75rem; font-weight: 800;
|
|
52
|
+
outline: none; transition: 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.otp-field:focus {
|
|
56
|
+
border-color: var(--c-primary, #6366f1);
|
|
57
|
+
background: rgba(99, 102, 241, 0.1);
|
|
58
|
+
box-shadow: 0 0 15px rgba(99, 102, 241, 0.3), 0 0 0 3px rgba(99, 102, 241, 0.15);
|
|
59
|
+
transform: translateY(-2px);
|
|
60
|
+
}
|
|
13
61
|
</style>
|
|
62
|
+
|
|
14
63
|
<script>
|
|
15
|
-
document.querySelectorAll('
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
64
|
+
document.querySelectorAll('[data-otp-group]').forEach(group => {
|
|
65
|
+
const inputs = group.querySelectorAll('input') as NodeListOf<HTMLInputElement>;
|
|
66
|
+
|
|
67
|
+
inputs.forEach((input, idx) => {
|
|
68
|
+
// Auto-advance
|
|
69
|
+
input.addEventListener('input', (e) => {
|
|
70
|
+
const val = (e.target as HTMLInputElement).value;
|
|
71
|
+
if (val && idx < inputs.length - 1) {
|
|
72
|
+
inputs[idx + 1].focus();
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Backspace logic
|
|
77
|
+
input.addEventListener('keydown', (e) => {
|
|
78
|
+
if (e.key === 'Backspace' && !input.value && idx > 0) {
|
|
79
|
+
inputs[idx - 1].focus();
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Paste logic
|
|
84
|
+
input.addEventListener('paste', (e) => {
|
|
85
|
+
e.preventDefault();
|
|
86
|
+
const data = e.clipboardData?.getData('text').slice(0, inputs.length).split('') || [];
|
|
87
|
+
data.forEach((val, i) => {
|
|
88
|
+
if (inputs[i]) inputs[i].value = val;
|
|
89
|
+
});
|
|
90
|
+
if (inputs[data.length - 1]) inputs[data.length - 1].focus();
|
|
91
|
+
});
|
|
20
92
|
});
|
|
21
93
|
});
|
|
22
94
|
</script>
|
|
@@ -1,15 +1,71 @@
|
|
|
1
1
|
---
|
|
2
|
+
/**
|
|
3
|
+
* RatingStars — A classic star-rating input for user reviews and feedback.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} name - HTML name for form submission. Default is "rating".
|
|
6
|
+
* @param {number} maxRating - Maximum number of stars. Default is 5.
|
|
7
|
+
* @param {string} idPrefix - Prefix used to generate unique IDs for radio buttons.
|
|
8
|
+
* @param {number} initialValue - Currently selected rating.
|
|
9
|
+
*/
|
|
10
|
+
interface Props {
|
|
11
|
+
name?: string;
|
|
12
|
+
maxRating?: number;
|
|
13
|
+
idPrefix?: string;
|
|
14
|
+
initialValue?: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const { name = "rating", maxRating = 5, idPrefix = "star", initialValue = 0 } = Astro.props;
|
|
2
18
|
---
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
19
|
+
|
|
20
|
+
<div class="rating-stars" data-rating-group>
|
|
21
|
+
{Array.from({ length: maxRating }).map((_, i) => {
|
|
22
|
+
const val = maxRating - i;
|
|
23
|
+
return (
|
|
24
|
+
<>
|
|
25
|
+
<input
|
|
26
|
+
type="radio"
|
|
27
|
+
name={name}
|
|
28
|
+
id={`${idPrefix}-${val}`}
|
|
29
|
+
value={val}
|
|
30
|
+
checked={initialValue === val}
|
|
31
|
+
class="rating-stars__input"
|
|
32
|
+
/>
|
|
33
|
+
<label for={`${idPrefix}-${val}`} class="rating-stars__star" aria-label={`${val} stars`}>
|
|
34
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
35
|
+
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"></polygon>
|
|
36
|
+
</svg>
|
|
37
|
+
</label>
|
|
38
|
+
</>
|
|
39
|
+
);
|
|
40
|
+
})}
|
|
9
41
|
</div>
|
|
42
|
+
|
|
10
43
|
<style>
|
|
11
|
-
.rating { display: flex; flex-direction: row-reverse; gap:
|
|
12
|
-
|
|
13
|
-
.rating
|
|
14
|
-
|
|
44
|
+
.rating-stars { display: flex; flex-direction: row-reverse; gap: 4px; width: fit-content; }
|
|
45
|
+
|
|
46
|
+
.rating-stars__input { display: none; }
|
|
47
|
+
|
|
48
|
+
.rating-stars__star {
|
|
49
|
+
width: 32px; height: 32px;
|
|
50
|
+
cursor: pointer; transition: all 0.2s ease;
|
|
51
|
+
color: var(--c-border, #334155);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.rating-stars__star svg { width: 100%; height: 100%; fill: transparent; transition: all 0.2s; }
|
|
55
|
+
|
|
56
|
+
/* Hover and check logic using sibling selectors (requires row-reverse) */
|
|
57
|
+
.rating-stars__star:hover,
|
|
58
|
+
.rating-stars__star:hover ~ .rating-stars__star,
|
|
59
|
+
.rating-stars__input:checked ~ .rating-stars__star {
|
|
60
|
+
color: #fbbf24;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.rating-stars__star:hover svg,
|
|
64
|
+
.rating-stars__star:hover ~ .rating-stars__star svg,
|
|
65
|
+
.rating-stars__input:checked ~ .rating-stars__star svg {
|
|
66
|
+
fill: #fbbf24;
|
|
67
|
+
filter: drop-shadow(0 0 5px rgba(251, 191, 36, 0.4));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.rating-stars__star:active { transform: scale(0.9); }
|
|
15
71
|
</style>
|
|
@@ -1,13 +1,51 @@
|
|
|
1
1
|
---
|
|
2
|
+
/**
|
|
3
|
+
* SearchReveal — A dynamic minimal search pod that expands smoothly into a full input field on hover or focus.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} id - Standard HTML ID property.
|
|
6
|
+
* @param {string} placeholder - Default placeholder ("Search...").
|
|
7
|
+
* @param {string} name - Standard HTML name grouping.
|
|
8
|
+
*/
|
|
9
|
+
interface Props {
|
|
10
|
+
id: string;
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
name?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { id, placeholder = "Search...", name } = Astro.props;
|
|
2
16
|
---
|
|
17
|
+
|
|
3
18
|
<div class="search-box">
|
|
4
|
-
<input type="
|
|
5
|
-
<button
|
|
19
|
+
<input type="search" {id} {name} {placeholder} class="search-input" aria-label="Search content" />
|
|
20
|
+
<button type="button" aria-label="Submit search" class="search-btn">
|
|
21
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
22
|
+
<circle cx="11" cy="11" r="8"></circle>
|
|
23
|
+
<line x1="21" y1="21" x2="16.65" y2="16.65"></line>
|
|
24
|
+
</svg>
|
|
25
|
+
</button>
|
|
6
26
|
</div>
|
|
27
|
+
|
|
7
28
|
<style>
|
|
8
|
-
.search-box { position: relative; width:
|
|
29
|
+
.search-box { position: relative; width: 44px; height: 44px; transition: 0.4s cubic-bezier(0.4, 0, 0.2, 1); }
|
|
9
30
|
.search-box:hover, .search-box:focus-within { width: 250px; }
|
|
10
|
-
.search-
|
|
11
|
-
|
|
12
|
-
|
|
31
|
+
.search-input {
|
|
32
|
+
width: 100%; height: 100%; box-sizing: border-box;
|
|
33
|
+
background: var(--c-bg-elev, #1e293b);
|
|
34
|
+
border: 1px solid var(--c-border, rgba(255,255,255,0.1));
|
|
35
|
+
border-radius: var(--r-full, 100px);
|
|
36
|
+
padding: 0 45px 0 20px;
|
|
37
|
+
color: var(--c-text-1, #fff); outline: none; opacity: 0; transition: 0.3s;
|
|
38
|
+
}
|
|
39
|
+
.search-box:hover .search-input, .search-box:focus-within .search-input { opacity: 1; }
|
|
40
|
+
.search-input::placeholder { color: var(--c-text-muted, #64748b); }
|
|
41
|
+
|
|
42
|
+
.search-btn {
|
|
43
|
+
position: absolute; right: 0; top: 0;
|
|
44
|
+
width: 44px; height: 44px;
|
|
45
|
+
background: var(--c-primary, #6366f1); border: none;
|
|
46
|
+
border-radius: 50%; color: #fff; cursor: pointer;
|
|
47
|
+
display: flex; align-items: center; justify-content: center;
|
|
48
|
+
transition: background 0.2s;
|
|
49
|
+
}
|
|
50
|
+
.search-btn:hover { background: var(--c-primary-light, #818cf8); }
|
|
13
51
|
</style>
|
|
@@ -1,13 +1,67 @@
|
|
|
1
1
|
---
|
|
2
|
+
/**
|
|
3
|
+
* SegmentedControl — A horizontal group of button-like radio choices for switching views or modes.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} name - Shared HTML name for the internal radio inputs.
|
|
6
|
+
* @param {Array<{label: string, value: string, checked?: boolean}>} options - Selectable segments.
|
|
7
|
+
* @param {string} idPrefix - Prefix for auto-generating input IDs.
|
|
8
|
+
*/
|
|
9
|
+
interface Props {
|
|
10
|
+
name: string;
|
|
11
|
+
options: Array<{ label: string; value: string; checked?: boolean }>;
|
|
12
|
+
idPrefix?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const { name, options = [], idPrefix = "seg" } = Astro.props;
|
|
2
16
|
---
|
|
17
|
+
|
|
3
18
|
<div class="segmented">
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
19
|
+
{options.map((opt, i) => (
|
|
20
|
+
<div class="segmented-item">
|
|
21
|
+
<input
|
|
22
|
+
type="radio"
|
|
23
|
+
name={name}
|
|
24
|
+
id={`${idPrefix}-${i}`}
|
|
25
|
+
value={opt.value}
|
|
26
|
+
checked={opt.checked}
|
|
27
|
+
class="segmented-input"
|
|
28
|
+
/>
|
|
29
|
+
<label for={`${idPrefix}-${i}`} class="segmented-label">{opt.label}</label>
|
|
30
|
+
</div>
|
|
31
|
+
))}
|
|
7
32
|
</div>
|
|
33
|
+
|
|
8
34
|
<style>
|
|
9
|
-
.segmented {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
35
|
+
.segmented {
|
|
36
|
+
display: flex; position: relative;
|
|
37
|
+
background: var(--c-bg-elev, rgba(255,255,255,0.05));
|
|
38
|
+
padding: 4px; border-radius: var(--r-md, 12px);
|
|
39
|
+
width: fit-content; border: 1px solid var(--c-border, rgba(255,255,255,0.05));
|
|
40
|
+
box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.segmented-item { display: flex; }
|
|
44
|
+
|
|
45
|
+
.segmented-label {
|
|
46
|
+
padding: 0.5rem 1.4rem; cursor: pointer; z-index: 1;
|
|
47
|
+
font-size: 0.85rem; transition: all 0.25s ease;
|
|
48
|
+
color: var(--c-text-2, #94a3b8);
|
|
49
|
+
border-radius: var(--r-sm, 8px);
|
|
50
|
+
font-weight: 500;
|
|
51
|
+
user-select: none;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.segmented-input { display: none; }
|
|
55
|
+
|
|
56
|
+
.segmented-input:checked + .segmented-label {
|
|
57
|
+
color: var(--c-text-1, #fff);
|
|
58
|
+
font-weight: 700;
|
|
59
|
+
background: var(--c-primary, #6366f1);
|
|
60
|
+
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.segmented-label:hover:not(.segmented-input:checked + .segmented-label) {
|
|
64
|
+
color: var(--c-text-1);
|
|
65
|
+
background: rgba(255,255,255,0.03);
|
|
66
|
+
}
|
|
13
67
|
</style>
|
|
@@ -1,11 +1,62 @@
|
|
|
1
1
|
---
|
|
2
|
+
/**
|
|
3
|
+
* SimpleFileInput — A minimalist file upload button that masks the native browser input.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} label - The text displayed on the button. Default is "Choose File".
|
|
6
|
+
* @param {string} id - HTML ID for the file input.
|
|
7
|
+
* @param {string} name - HTML name binding.
|
|
8
|
+
* @param {string} accept - Allowed file formats.
|
|
9
|
+
*/
|
|
10
|
+
interface Props {
|
|
11
|
+
label?: string;
|
|
12
|
+
id: string;
|
|
13
|
+
name?: string;
|
|
14
|
+
accept?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const { label = "Choose File", id, name, accept } = Astro.props;
|
|
2
18
|
---
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<
|
|
19
|
+
|
|
20
|
+
<label class="file-btn" for={id}>
|
|
21
|
+
<input type="file" {id} {name} {accept} class="file-btn__input" />
|
|
22
|
+
<span class="file-btn__label">{label}</span>
|
|
6
23
|
</label>
|
|
24
|
+
|
|
7
25
|
<style>
|
|
8
|
-
.file-btn {
|
|
9
|
-
|
|
10
|
-
|
|
26
|
+
.file-btn {
|
|
27
|
+
position: relative;
|
|
28
|
+
overflow: hidden;
|
|
29
|
+
display: inline-block;
|
|
30
|
+
cursor: pointer;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.file-btn__input {
|
|
34
|
+
position: absolute;
|
|
35
|
+
left: 0; top: 0;
|
|
36
|
+
width: 100%; height: 100%;
|
|
37
|
+
opacity: 0; cursor: pointer;
|
|
38
|
+
font-size: 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.file-btn__label {
|
|
42
|
+
background: var(--c-primary, #6366f1);
|
|
43
|
+
color: #fff;
|
|
44
|
+
padding: 0.8rem 1.6rem;
|
|
45
|
+
border-radius: var(--r-md, 10px);
|
|
46
|
+
font-weight: 700;
|
|
47
|
+
display: inline-block;
|
|
48
|
+
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
|
|
49
|
+
box-shadow: 0 4px 15px rgba(99, 102, 241, 0.2);
|
|
50
|
+
font-size: 0.95rem;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.file-btn:hover .file-btn__label {
|
|
54
|
+
filter: brightness(1.1);
|
|
55
|
+
transform: translateY(-2px);
|
|
56
|
+
box-shadow: 0 6px 20px rgba(99, 102, 241, 0.3);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.file-btn:active .file-btn__label {
|
|
60
|
+
transform: translateY(0);
|
|
61
|
+
}
|
|
11
62
|
</style>
|
|
@@ -1,14 +1,106 @@
|
|
|
1
1
|
---
|
|
2
|
+
/**
|
|
3
|
+
* StepperInput — A numeric input with increment and decrement buttons for precise control.
|
|
4
|
+
*
|
|
5
|
+
* @param {string} label - Optional input label.
|
|
6
|
+
* @param {string} id - HTML ID for the number input.
|
|
7
|
+
* @param {string} name - HTML name binding.
|
|
8
|
+
* @param {number} value - Initial default value. Default is 1.
|
|
9
|
+
* @param {number} min - Minimum allowed value.
|
|
10
|
+
* @param {number} max - Maximum allowed value.
|
|
11
|
+
* @param {number} step - Numeric increment step. Default is 1.
|
|
12
|
+
*/
|
|
13
|
+
interface Props {
|
|
14
|
+
label?: string;
|
|
15
|
+
id: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
value?: number;
|
|
18
|
+
min?: number;
|
|
19
|
+
max?: number;
|
|
20
|
+
step?: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const { label, id, name, value = 1, min, max, step = 1 } = Astro.props;
|
|
2
24
|
---
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
<
|
|
6
|
-
<
|
|
25
|
+
|
|
26
|
+
<div class="stepper-container">
|
|
27
|
+
{label && <label class="stepper-label" for={id}>{label}</label>}
|
|
28
|
+
<div class="stepper" data-stepper>
|
|
29
|
+
<button type="button" class="stepper-btn stepper-btn--minus" data-step-minus aria-label="Decrease value">−</button>
|
|
30
|
+
<input
|
|
31
|
+
type="number"
|
|
32
|
+
{id}
|
|
33
|
+
{name}
|
|
34
|
+
{min}
|
|
35
|
+
{max}
|
|
36
|
+
{step}
|
|
37
|
+
value={value}
|
|
38
|
+
class="stepper-input"
|
|
39
|
+
data-step-input
|
|
40
|
+
/>
|
|
41
|
+
<button type="button" class="stepper-btn stepper-btn--plus" data-step-plus aria-label="Increase value">+</button>
|
|
42
|
+
</div>
|
|
7
43
|
</div>
|
|
44
|
+
|
|
8
45
|
<style>
|
|
9
|
-
.stepper { display: flex;
|
|
10
|
-
.stepper
|
|
11
|
-
|
|
12
|
-
.stepper
|
|
13
|
-
|
|
46
|
+
.stepper-container { display: flex; flex-direction: column; gap: var(--sp-2, 0.5rem); }
|
|
47
|
+
.stepper-label { font-size: 0.85rem; font-weight: 600; color: var(--c-text-2, #94a3b8); margin-left: 0.5rem; }
|
|
48
|
+
|
|
49
|
+
.stepper {
|
|
50
|
+
display: flex; align-items: center;
|
|
51
|
+
background: var(--c-bg-elev, rgba(255,255,255,0.05));
|
|
52
|
+
border-radius: var(--r-md, 12px);
|
|
53
|
+
border: 1px solid var(--c-border, rgba(255,255,255,0.1));
|
|
54
|
+
overflow: hidden;
|
|
55
|
+
width: fit-content;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.stepper-btn {
|
|
59
|
+
width: 40px; height: 40px;
|
|
60
|
+
background: var(--c-primary, #6366f1);
|
|
61
|
+
border: none; color: #fff;
|
|
62
|
+
font-size: 1.25rem; font-weight: 600;
|
|
63
|
+
cursor: pointer; transition: all 0.2s;
|
|
64
|
+
display: grid; place-items: center;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.stepper-btn:hover { background: var(--c-primary-light, #818cf8); }
|
|
68
|
+
.stepper-btn:active { transform: scale(0.95); }
|
|
69
|
+
|
|
70
|
+
.stepper-input {
|
|
71
|
+
width: 60px; height: 40px;
|
|
72
|
+
background: transparent;
|
|
73
|
+
border: none; text-align: center;
|
|
74
|
+
color: var(--c-text-1, #fff);
|
|
75
|
+
font-size: 1rem; font-weight: 700;
|
|
76
|
+
outline: none; -moz-appearance: textfield;
|
|
77
|
+
font-family: inherit;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.stepper-input::-webkit-inner-spin-button,
|
|
81
|
+
.stepper-input::-webkit-outer-spin-button { display: none; }
|
|
14
82
|
</style>
|
|
83
|
+
|
|
84
|
+
<script>
|
|
85
|
+
document.querySelectorAll('[data-stepper]').forEach(wrapper => {
|
|
86
|
+
const input = wrapper.querySelector('[data-step-input]') as HTMLInputElement;
|
|
87
|
+
const minus = wrapper.querySelector('[data-step-minus]');
|
|
88
|
+
const plus = wrapper.querySelector('[data-step-plus]');
|
|
89
|
+
|
|
90
|
+
if (!input || !minus || !plus) return;
|
|
91
|
+
|
|
92
|
+
const step = parseFloat(input.step) || 1;
|
|
93
|
+
const min = input.min !== "" ? parseFloat(input.min) : -Infinity;
|
|
94
|
+
const max = input.max !== "" ? parseFloat(input.max) : Infinity;
|
|
95
|
+
|
|
96
|
+
minus.addEventListener('click', () => {
|
|
97
|
+
const current = parseFloat(input.value) || 0;
|
|
98
|
+
if (current - step >= min) input.value = (current - step).toString();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
plus.addEventListener('click', () => {
|
|
102
|
+
const current = parseFloat(input.value) || 0;
|
|
103
|
+
if (current + step <= max) input.value = (current + step).toString();
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
</script>
|