Skip to content
Merged
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
1 change: 1 addition & 0 deletions percentage-tracker/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
CODE_LIBRARIES="true"
24 changes: 24 additions & 0 deletions percentage-tracker/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
19 changes: 19 additions & 0 deletions percentage-tracker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Percentage Tracker

This code component example displays an animated percentage tracker that highlights completion progress for any goal from 0–100.

## Features

- Animated progress bar that transitions from 0 to the provided value on load
- Props for customizing the displayed label, progress color, and animation delay within Webflow
- Styled with [TailwindCSS](https://tailwindcss.com/) and [DaisyUI](https://daisyui.com/)
- Vite project setup ready for local development and Webflow code component publishing

## Getting started

- Install dependencies: `npm i`
- Run the project locally: `npm run dev`
- Visit `http://localhost:5173/`
- Ensure that the component loads as expected
- Any local code changes saved should reflect accordingly
- Run `npx webflow library share` to create a code library for this example in your designated Webflow workspace
13 changes: 13 additions & 0 deletions percentage-tracker/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en" data-theme="light">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Percentage Tracker</title>
</head>
<body class="bg-base-200 min-h-screen">
<div id="app"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
29 changes: 29 additions & 0 deletions percentage-tracker/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "percentage-tracker",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"@types/react": "^19.1.12",
"@types/react-dom": "^19.1.9",
"@vitejs/plugin-react": "^4.3.3",
"@webflow/react": "^0.0.12",
"@webflow/webflow-cli": "^1.4.0",
"typescript": "^5.9.2",
"vite": "^7.1.2"
},
"dependencies": {
"@tailwindcss/postcss": "^4.1.13",
"@tailwindcss/vite": "^4.1.13",
"daisyui": "^5.1.8",
"postcss": "^8.5.6",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"tailwindcss": "^4.1.13"
}
}
6 changes: 6 additions & 0 deletions percentage-tracker/postcss.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};
export default config;
1 change: 1 addition & 0 deletions percentage-tracker/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 65 additions & 0 deletions percentage-tracker/src/PercentageTracker.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useEffect, useMemo, useState } from 'react'

type PercentageTrackerProps = {
value: number
label?: string
color?: string
delay?: number
}

const clampValue = (input: number) => {
if (Number.isNaN(input)) {
return 0
}

return Math.min(100, Math.max(0, Math.round(input)))
}

const PercentageTracker = ({ value, label, color = '#16a34a', delay = 0 }: PercentageTrackerProps) => {
const normalizedValue = useMemo(() => clampValue(value), [value])
const animationDelay = Math.max(0, delay)
const [displayValue, setDisplayValue] = useState(0)

useEffect(() => {
const timeout = window.setTimeout(() => {
setDisplayValue(normalizedValue)
}, animationDelay)

return () => {
window.clearTimeout(timeout)
}
}, [normalizedValue, animationDelay])

return (
<div className="w-full max-w-xl mx-auto p-8 bg-base-100 shadow-xl rounded-box">
<div className="flex items-end justify-between mb-6">
<div>
<h2 className="text-2xl font-semibold text-base-content">Progress</h2>
<p className="text-sm text-base-content/70">Tracking completion towards your goal</p>
</div>
<span className="text-4xl font-bold text-base-content">{displayValue}%</span>
</div>
<div
className="relative h-4 rounded-full bg-base-300 overflow-hidden"
role="progressbar"
aria-valuemin={0}
aria-valuemax={100}
aria-valuenow={displayValue}
>
<div
className="absolute left-0 top-0 h-full rounded-full transition-[width] duration-700 ease-out"
style={{ width: `${displayValue}%`, backgroundColor: color }}
/>
<div
className="absolute top-1/2 -translate-y-1/2 -translate-x-1/2 transition-[left] duration-700 ease-out"
style={{ left: `${displayValue}%` }}
>
<div className="w-6 h-6 rounded-full border-4 border-base-100" style={{ backgroundColor: color }} />
</div>
</div>
{label && <p className="mt-6 text-center text-base-content/80">{label}</p>}
</div>
)
}

export default PercentageTracker
30 changes: 30 additions & 0 deletions percentage-tracker/src/PercentageTracker.webflow.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { declareComponent } from '@webflow/react'
import { props } from '@webflow/data-types'
import PercentageTracker from './PercentageTracker'
import './style.css'

export default declareComponent(PercentageTracker, {
name: 'Percentage Tracker',
description: 'An animated progress tracker with customizable label, color, and delay.',
group: 'Feedback',
props: {
value: props.Number({
name: 'Value',
min: 0,
max: 100,
defaultValue: 50,
}),
label: props.Text({
name: 'Label',
}),
color: props.Text({
name: 'Color',
defaultValue: '#16a34a',
}),
delay: props.Number({
name: 'Delay (ms)',
min: 0,
defaultValue: 0,
}),
},
})
12 changes: 12 additions & 0 deletions percentage-tracker/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import PercentageTracker from './PercentageTracker'
import './style.css'

ReactDOM.createRoot(document.getElementById('app')!).render(
<React.StrictMode>
<div className="min-h-screen bg-base-200 flex items-center justify-center p-6">
<PercentageTracker value={72} label="Quarterly sales target" color="#16a34a" delay={300} />
</div>
</React.StrictMode>,
)
2 changes: 2 additions & 0 deletions percentage-tracker/src/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@import "tailwindcss";
@plugin "daisyui";
20 changes: 20 additions & 0 deletions percentage-tracker/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
}
17 changes: 17 additions & 0 deletions percentage-tracker/vite.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
plugins: [
react({
include: '**/*.{jsx,tsx}',
}),
tailwindcss(),
],
esbuild: {
loader: 'tsx',
include: /src\/.*\.[tj]sx?$/,
exclude: [],
},
})
16 changes: 16 additions & 0 deletions percentage-tracker/webflow.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"library": {
"name": "Webflow Code Import Examples - Percentage Tracker",
"components": [
"**/*.webflow.@(js|jsx|mjs|ts|tsx)"
],
"id": "webflow-code-import-examples---percentage-tracker"
},
"telemetry": {
"global": {
"allowTelemetry": true,
"lastPrompted": 1757368712207,
"version": "1.8.40"
}
}
}