Task 10: Build Footer component with ECG decoration

- Created Footer.tsx with decorative ECG waveform SVG
- Footer uses Framer Motion for scroll-triggered entrance animation
- Centered layout with border-top, muted attribution text
- Integrated Footer into App.tsx content phase
- Three-phase orchestration (boot → ecg → content) already working
This commit is contained in:
2026-02-10 17:03:11 +00:00
parent 75c6cf11dc
commit 1a2c43323b
3 changed files with 39 additions and 1 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"active": true, "active": true,
"iteration": 8, "iteration": 9,
"minIterations": 1, "minIterations": 1,
"maxIterations": 0, "maxIterations": 0,
"completionPromise": "COMPLETE", "completionPromise": "COMPLETE",
+2
View File
@@ -9,6 +9,7 @@ import { Experience } from './components/Experience'
import { Education } from './components/Education' import { Education } from './components/Education'
import { Projects } from './components/Projects' import { Projects } from './components/Projects'
import { Contact } from './components/Contact' import { Contact } from './components/Contact'
import { Footer } from './components/Footer'
function App() { function App() {
const [phase, setPhase] = useState<Phase>('boot') const [phase, setPhase] = useState<Phase>('boot')
@@ -39,6 +40,7 @@ function App() {
<Contact /> <Contact />
</main> </main>
<Footer />
</> </>
)} )}
</div> </div>
+36
View File
@@ -0,0 +1,36 @@
import { motion } from 'framer-motion'
const Footer: React.FC = () => {
return (
<motion.footer
initial={{ opacity: 0, y: 16 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: '-50px' }}
transition={{ duration: 0.5, ease: 'easeOut' }}
className="text-center pt-12 pb-8 border-t border-slate-200"
>
<svg
className="block mx-auto mb-3"
width="120"
height="20"
viewBox="0 0 120 20"
fill="none"
>
<path
d="M 0 10 L 35 10 L 40 10 C 42 10 43 7 45 7 C 47 7 48 10 50 10 L 54 10 L 56 13 L 60 2 L 64 15 L 66 10 L 70 10 C 72 10 73 7 75 7 C 77 7 78 10 80 10 L 120 10"
stroke="#00897B"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
opacity="0.3"
fill="none"
/>
</svg>
<p className="font-secondary text-xs text-muted">
Andy Charlwood &mdash; MPharm, GPhC Registered Pharmacist
</p>
</motion.footer>
)
}
export { Footer }