Personal Profile (2023-06-16)
Grayscale resume portfolio with fixed left tab bar, assembled from view/*.html by QuickUI 0.6.2 templates, with tabbed resume and pricing.
Overview
| Item | Value |
|---|---|
| Created | 2023-06-16 |
| Category | Personal Examples |
| HTML files | index.html, view/left-tab.html, view/home.html, view/features.html, view/portfolio.html, view/resume.html, view/pricing.html, view/contact.html |
| Source | target/20230616 |
Live Preview
Page Sections
| Section | Description |
|---|---|
| Left tab bar (view/left-tab.html) | Avatar, #body-tab with 6 items (HOME, FEATURES, PORTFOLIO, RESUMES, PRICING, CONTACTS) highlighted by [index], and FIND WITH ME social links. |
| Home (view/home.html) | Avatar, "Hi, I'm Pardn Chiu", role line, GITHUB and CONTACT ME buttons on an animated gradient. |
| Features (view/features.html) | What I Do: 3 cards for iOS, front-end, back-end. |
| Portfolio (view/portfolio.html) | ALL / WEB / iOS labels and 20 album cards rendered with :for from data.albums, lazy-loaded images with captions. |
| Resume (view/resume.html) | EXPERIENCE / SKILLS tabs: education and job timelines, or front-end and back-end skill bars sized by span[year]. |
| Pricing (view/pricing.html) | iOS APP / Front-end / Back-end tabs, each showing a plan card (120k / 30k / 30k) with a 10-item checklist. |
| Contact (view/contact.html) | Profile card with mail and LinkedIn links beside a 5-field form (name, phone, email, subject, message; no handler). |
| Footer | Copyright line inside #body. |
Interactions
- Inline script creates new QUI({id: "page", data: {albums}, when: {rendered}}); QuickUI loads each <temp :path> view and renders :for / {{ }} / :lazyload bindings.
- rendered hook: clicks on #body-resume and #body-pricing tab items set filter-index on the container; CSS shows the matching [filter-key] sections. The #body-portfolio tab loop is empty, so portfolio tabs do nothing.
- offsetY(i) sums #body children heights; #body-tab item click sets document.body.scrollTop, body scroll listener sets #body-tab[index] 0..6 (scroll-spy, vh/3 offset).
Dependencies
| Name | Version | Source |
|---|---|---|
| Font Awesome Free | 6.5.2 | https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.5.2/css/all.min.css |
| QuickUI (@pardnchiu/quickui) | 0.6.2 | https://cdn.jsdelivr.net/npm/@pardnchiu/quickui@0.6.2/dist/QuickUI.js |
| Google Analytics (gtag.js) | - | https://www.googletagmanager.com/gtag/js?id=G-L5VYEZPVXX |
Styling
| Item | Value |
|---|---|
| SCSS entry | sass/index.scss |
| Output CSS | css/index.css |
| Partials | _left-tab.scss, _home.scss, _features.scss, _portfolio.scss, _resume.scss, _pricing.scss, _contact.scss, animation/_bg-move.scss |
index.scss: reset, body scroll container, #body offset for the left bar at 480px/800px; one partial per view. _left-tab: fixed bar, @for [index] highlight; _portfolio/_resume/_pricing: @for 0..9 generating [filter-index]/[filter-key] tab rules; _resume: timeline and @for [year] skill bars with attr(year)"年"; _pricing/_contact: position: sticky at >=1024px; animation/_bg-move: gradient background-position keyframes. --gradient-col and grayscale vars are in an inline <style>.
cd target/20230616
npx sass sass/index.scss css/index.css --no-source-map || exit 1
Techniques
- QuickUI template syntax: <temp :path> includes, :for="item in albums", :filter-key / :href attribute binding, :lazyload, {{ item.name }} interpolation.
- Attribute-driven tab filtering with SCSS @for-generated [filter-index="n"] [filter-key="n"] selectors.
- Animated multi-stop gradient via shared bg-move keyframes; position: sticky side panels; content: attr(year).
- Semantic markup: article, time[datetime], figure/figcaption; breakpoints 480px, 640px, 800px, 1024px, 1280px.
External Assets
- https://fakeimg.pl/1024/282828/eae0d0/?text=sample (avatars, album and contact images)
- https://pardn.io/image/head.png (favicon)
- https://pardn.io/web-template/image/20230616.jpg (og/twitter image)