diff --git a/js/react/lib/components/progress-bar/index.ts b/js/react/lib/components/progress-bar/index.ts
new file mode 100644
index 0000000..7a5a721
--- /dev/null
+++ b/js/react/lib/components/progress-bar/index.ts
@@ -0,0 +1 @@
+export * from "./progress-bar.component";
diff --git a/js/react/lib/components/progress-bar/progress-bar.component.tsx b/js/react/lib/components/progress-bar/progress-bar.component.tsx
new file mode 100644
index 0000000..c005d40
--- /dev/null
+++ b/js/react/lib/components/progress-bar/progress-bar.component.tsx
@@ -0,0 +1,41 @@
+import { Ferris } from "@/icons/ferris";
+import { cn } from "@/utils/tw-merge";
+
+type ProgressBarProps = {
+ percentage: number;
+};
+export const ProgressBar = (props: ProgressBarProps) => {
+ const percentage = Number(props.percentage ?? 0);
+ const isZeroProgress = percentage === 0;
+ const progressIsInLimit = isZeroProgress || percentage === 100;
+ const isInMinLimit = percentage < 25;
+
+ const position = {
+ right: isInMinLimit ? "auto" : `${100 - percentage}%`,
+ left: isInMinLimit ? `${percentage}%` : "auto",
+ };
+
+ return (
+
+
+
+ {percentage}%
+
+
+
+
+
+ );
+};
diff --git a/js/react/lib/icons/ferris.tsx b/js/react/lib/icons/ferris.tsx
new file mode 100644
index 0000000..f985efc
--- /dev/null
+++ b/js/react/lib/icons/ferris.tsx
@@ -0,0 +1,32 @@
+import { SVGProps } from "react";
+export const Ferris = (props: SVGProps) => (
+
+);
diff --git a/js/react/lib/index.ts b/js/react/lib/index.ts
index dfabc86..a63f98f 100644
--- a/js/react/lib/index.ts
+++ b/js/react/lib/index.ts
@@ -13,4 +13,5 @@ export * from "./components/dropdown";
export * from "./components/calendar";
export * from "./components/dropdown-tree";
export * from "./components/input-search";
+export * from "./components/progress-bar";
export * from "./icons";
diff --git a/js/react/showcase/App.tsx b/js/react/showcase/App.tsx
index b054de9..00be923 100644
--- a/js/react/showcase/App.tsx
+++ b/js/react/showcase/App.tsx
@@ -15,6 +15,7 @@ import {
Calendar,
CalendarRangeDate,
DropdownTree,
+ ProgressBar,
InputSearch,
} from "@rustlanges/react";
import { ShowComponent } from "./ShowComponent";
@@ -512,6 +513,17 @@ export function App() {
+
);
}
diff --git a/styles/components.css b/styles/components.css
index 814cb07..a7f7d88 100644
--- a/styles/components.css
+++ b/styles/components.css
@@ -15,3 +15,4 @@
@import "./components/dropdown-tree-subtopic.css";
@import "./components/dropdown-tree-end.css";
@import "./components/input-search.css";
+@import "./components/progress-bar.css";
diff --git a/styles/components/progress-bar.css b/styles/components/progress-bar.css
new file mode 100644
index 0000000..8a861e2
--- /dev/null
+++ b/styles/components/progress-bar.css
@@ -0,0 +1,35 @@
+@layer components {
+ .rustlanges-progress-bar__container {
+ @apply h-[33px] w-full;
+ }
+
+ .rustlanges-progress-bar {
+ @apply relative h-2.5 w-full rounded-xl border border-black;
+ @apply bg-neutral-100 dark:bg-neutral-900;
+ }
+ .rustlanges-progress-bar__fill {
+ @apply absolute left-0 h-full;
+ @apply border-r border-r-black;
+ @apply rounded-l-xl;
+ @apply transition-all duration-1000;
+ @apply bg-primary-500;
+ }
+ .rustlanges-progress-bar__percentage {
+ @apply absolute -top-6;
+ @apply flex items-center gap-1;
+ @apply h-fit w-fit;
+ @apply px-1 py-0.5;
+ @apply text-primary-500;
+ @apply border border-black;
+ @apply rounded-l-xs rounded-tr-xs;
+ @apply transition-all duration-1000;
+ @apply bg-white dark:bg-neutral-900;
+ }
+
+ .rustlanges-progress-bar__fill--limit {
+ @apply rounded-r-xl border-none;
+ }
+ .rustlanges-progress-bar__percentage--invert {
+ @apply rounded-r-xs rounded-bl-none;
+ }
+}
diff --git a/styles/theme.css b/styles/theme.css
index f594b00..69a7bb8 100644
--- a/styles/theme.css
+++ b/styles/theme.css
@@ -124,6 +124,8 @@
--font-monospace-body: monospace;
/* Border radiuses */
+
+ --radius-xs: 4px;
--radius-sm: 8px;
--radius-md: 16px;
--radius-DEFAULT: 16px;