- Extract content to src/config/profile.js (single-file customization) - Add Apache-2.0 LICENSE, CONTRIBUTING.md, robots.txt - Add GitHub Pages auto-deploy workflow - Update package.json: private=false, license, homepage - Add SEO/Open Graph meta tags to index.html - Rewrite README.md with Quick Start guide - Update .gitignore: AI tooling, caches, deployment state
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
name: Deploy to GitHub Pages
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
- run: npm ci
|
||||
- run: npm run build
|
||||
- uses: actions/configure-pages@v4
|
||||
- uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: dist
|
||||
- id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
+13
@@ -54,3 +54,16 @@ package-backup.json
|
||||
package-modern.json
|
||||
package-updated-conservative.json
|
||||
package-vue2-working.json
|
||||
|
||||
# Tooling (Hermes / OpenCode)
|
||||
.hermes/
|
||||
NUL
|
||||
|
||||
# Generic caches
|
||||
.cache/
|
||||
.temp/
|
||||
.tmp/
|
||||
|
||||
# Deployment platform state (uncomment if used)
|
||||
# .netlify/
|
||||
# .vercel/
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
# Contributing
|
||||
|
||||
1. Fork the repository.
|
||||
2. Customize `src/config/profile.js` with your profile details.
|
||||
3. Push your branch and open a pull request.
|
||||
|
||||
Keep each pull request focused on one feature or fix. Use GitHub Issues to report bugs or propose features.
|
||||
|
||||
For other questions, contact [[email protected]](mailto:[email protected]).
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2024 Hoelee (https://hoelee.com)
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,117 +1,83 @@
|
||||
# Mr. Hoelee Resume - Animated Resume
|
||||
# Animated Profile
|
||||
|
||||
This project is inspired by: [Animating Resume](https://github.com/jirengu-inc/animating-resume)
|
||||
Deep respect to the original author.
|
||||
> Type your way to a stunning developer showcase.
|
||||
|
||||
An interactive animated resume built with Vue 3 and Vite that showcases your professional profile in a unique and engaging way. Features responsive design with separate mobile and desktop experiences.
|
||||
[](https://me.hoelee.com)
|
||||
[](LICENSE)
|
||||
|
||||
## Prerequisites
|
||||
An interactive animated resume template built with Vue 3 and Vite. It is inspired by and credits [jirengu-inc/animating-resume](https://github.com/jirengu-inc/animating-resume).
|
||||
|
||||
- **Node.js**: >= 18.0.0 ([Download](https://nodejs.org/))
|
||||
- **npm**: >= 9.0.0
|
||||
- **Git**: [Download](https://git-scm.com/)
|
||||
## Quick Start
|
||||
|
||||
## Usage
|
||||
1. Click **Use this template** on GitHub, or clone the repository:
|
||||
|
||||
1. Clone this repository:
|
||||
```bash
|
||||
git clone https://github.com/hoelee/hoelee-profile.git
|
||||
cd hoelee-profile
|
||||
```
|
||||
|
||||
```bash
|
||||
git clone <your-repository-url>
|
||||
cd hoelee-profile2
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
2. Install dependencies:
|
||||
|
||||
2. The development server will automatically open in your browser at `http://localhost:8080`
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
## Build and Deployment
|
||||
3. Edit `src/config/profile.js` and fill in your name, bio, skills, and contact information.
|
||||
|
||||
### Building for Production
|
||||
4. Start a local preview at <http://localhost:8080>:
|
||||
|
||||
1. Build the project:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
5. Create a production build in `dist/`:
|
||||
|
||||
2. The built files will be generated in the `dist/` directory
|
||||
```bash
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Deployment Options
|
||||
6. Deploy `dist/` to Netlify, Vercel, GitHub Pages, or any static host.
|
||||
|
||||
#### Option 1: Static Web Server
|
||||
## Typing Speed
|
||||
|
||||
Upload the contents of the `dist/` directory to any static web server (Netlify, Vercel, GitHub Pages, etc.)
|
||||
|
||||
#### Option 2: Preview Locally
|
||||
|
||||
Test the production build locally:
|
||||
|
||||
```bash
|
||||
npm run preview
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
- `npm run dev` - Start development server with hot reload (opens at <http://localhost:8080>)
|
||||
- `npm run build` - Build for production (outputs to `dist/` directory)
|
||||
- `npm run preview` - Preview production build locally
|
||||
Set `typingSpeed` in `src/config/profile.js` to control the milliseconds per character. `1` is fastest; `20` creates a slow, dramatic effect.
|
||||
|
||||
## Project Structure
|
||||
|
||||
```text
|
||||
src/
|
||||
├── App.vue # Desktop version of the resume
|
||||
├── Mobile.vue # Mobile-optimized version
|
||||
├── main.js # Entry point with responsive logic
|
||||
├── assets/ # Stylesheets and static assets
|
||||
│ └── reset.css # CSS reset styles
|
||||
└── components/ # Resume components
|
||||
├── ResumeEditor.vue # Resume content editor
|
||||
├── StyleEditor.vue # Style/CSS editor
|
||||
└── ThankEditor.vue # Thank you section
|
||||
```
|
||||
| Path | Purpose |
|
||||
| --- | --- |
|
||||
| `src/App.vue` | Desktop animated profile |
|
||||
| `src/Mobile.vue` | Mobile animated profile |
|
||||
| `src/config/profile.js` | Personal details, Markdown, animation speed, and typed CSS |
|
||||
| `src/main.js` | Responsive application entry point |
|
||||
| `src/components/` | Resume, style, and thank-you editors |
|
||||
| `src/assets/` | Reset stylesheet and static assets |
|
||||
| `public/robots.txt` | SEO crawler directives |
|
||||
|
||||
## Features
|
||||
## Deployment
|
||||
|
||||
- **Responsive Design**: Automatically switches between desktop and mobile versions based on screen width (500px breakpoint)
|
||||
- **Interactive Animation**: Type-writer effect for resume content
|
||||
- **Live Preview**: Real-time preview of resume as it's being "typed"
|
||||
- **Modern Stack**: Built with Vue 3 composition API and Vite for fast development
|
||||
- **Syntax Highlighting**: Integrated Prism.js for code highlighting
|
||||
- **Markdown Support**: Uses marked.js for markdown parsing
|
||||
| Platform | Approach |
|
||||
| --- | --- |
|
||||
| GitHub Pages | The included GitHub Actions workflow deploys every push to `main`. |
|
||||
| Netlify | Build with `npm run build` and publish `dist/`. |
|
||||
| Vercel | Import the repository; Vite settings are detected automatically. |
|
||||
| Static server | Upload the contents of `dist/` to any static web server. |
|
||||
|
||||
## Customization
|
||||
`public/robots.txt` is pre-included for SEO and is copied into the production build.
|
||||
|
||||
### Personalizing Your Resume
|
||||
## Tech Stack
|
||||
|
||||
1. **Content**: Edit the resume content in `src/components/ResumeEditor.vue`
|
||||
2. **Styling**: Modify CSS styles in `src/components/StyleEditor.vue`
|
||||
3. **Layout**: Adjust the main layout in `src/App.vue` (desktop) or `src/Mobile.vue` (mobile)
|
||||
4. **Title**: Update the page title in `index.html`
|
||||
|
||||
### Configuration
|
||||
|
||||
- **Port**: Development server port is set to 8080 in `vite.config.js`
|
||||
- **Build Output**: Configured to output to `dist/` directory with organized asset structure
|
||||
- **Aliases**: Path aliases are set up for easy imports (`@`, `src`, `assets`, `components`)
|
||||
|
||||
## Technologies Used
|
||||
|
||||
- **Vue 3** - Progressive JavaScript framework with Composition API
|
||||
- **Vite** - Next-generation frontend build tool
|
||||
- **Prism.js** - Syntax highlighting library
|
||||
- **Marked** - Markdown parser and compiler
|
||||
- **CSS3 Animations** - Smooth typing animations and transitions
|
||||
- **PostCSS & Autoprefixer** - CSS processing and vendor prefixing
|
||||
|
||||
## Browser Support
|
||||
|
||||
This project uses modern JavaScript features and is compatible with:
|
||||
|
||||
- Chrome/Edge 88+
|
||||
- Firefox 85+
|
||||
- Safari 14+
|
||||
| Technology | Role |
|
||||
| --- | --- |
|
||||
| Vue 3 | UI framework |
|
||||
| Vite | Development server and build tool |
|
||||
| Prism.js | Syntax highlighting |
|
||||
| marked.js | Markdown rendering |
|
||||
|
||||
## License
|
||||
|
||||
This project is for personal/educational use. Please respect the original author's work.
|
||||
Licensed under [Apache-2.0](LICENSE).
|
||||
|
||||
## Credits
|
||||
|
||||
Inspired by the original [animating-resume](https://github.com/jirengu-inc/animating-resume) project by jirengu-inc.
|
||||
|
||||
Vendored
+20
-15
@@ -1,15 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<title>Mr Hoelee Resume</title>
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.ico">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="./favicon.ico">
|
||||
<script type="module" crossorigin src="/static/js/index-BF7mfwu9.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/static/css/index-D2xCV1gI.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<meta name="description" content="Animated developer profile — customize and showcase your own resume with typewriter effects.">
|
||||
<meta property="og:title" content="Animated Profile | me.hoelee.com">
|
||||
<meta property="og:description" content="An interactive animated resume with typewriter effects. Built with Vue 3 + Vite.">
|
||||
<meta property="og:url" content="https://me.hoelee.com">
|
||||
<meta property="og:type" content="website">
|
||||
<title>Animated Profile | me.hoelee.com</title>
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.ico">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="./favicon.ico">
|
||||
<script type="module" crossorigin src="/static/js/index-M1D7qx2s.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/static/css/index-DXZ8y7TX.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>␍
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+7
-2
@@ -1,9 +1,14 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
|
||||
<title>Mr Hoelee Resume</title>
|
||||
<meta name="description" content="Animated developer profile — customize and showcase your own resume with typewriter effects.">
|
||||
<meta property="og:title" content="Animated Profile | me.hoelee.com">
|
||||
<meta property="og:description" content="An interactive animated resume with typewriter effects. Built with Vue 3 + Vite.">
|
||||
<meta property="og:url" content="https://me.hoelee.com">
|
||||
<meta property="og:type" content="website">
|
||||
<title>Animated Profile | me.hoelee.com</title>
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.ico">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="./favicon.ico">
|
||||
</head>
|
||||
|
||||
+6
-3
@@ -2,8 +2,11 @@
|
||||
"name": "hoelee-profile",
|
||||
"version": "2.0.0",
|
||||
"description": "Hoelee's animated resume - modernized",
|
||||
"author": "Hoelee <>",
|
||||
"private": true,
|
||||
"author": "Hoelee <[email protected]>",
|
||||
"private": false,
|
||||
"license": "Apache-2.0",
|
||||
"homepage": "https://me.hoelee.com",
|
||||
"repository": "https://github.com/hoelee/hoelee-profile",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
@@ -24,4 +27,4 @@
|
||||
"node": ">= 18.0.0",
|
||||
"npm": ">= 9.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
Sitemap: https://me.hoelee.com/sitemap.xml
|
||||
+35
-287
@@ -11,6 +11,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import profile from './config/profile.js'
|
||||
import StyleEditor from './components/StyleEditor.vue'
|
||||
import ResumeEditor from './components/ResumeEditor.vue'
|
||||
import ThankEditor from './components/ThankEditor.vue'
|
||||
@@ -18,319 +19,68 @@
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
StyleEditor,
|
||||
ResumeEditor,
|
||||
ThankEditor
|
||||
},
|
||||
components: { StyleEditor, ResumeEditor, ThankEditor },
|
||||
data() {
|
||||
return {
|
||||
interval: 1,
|
||||
interval: profile.typingSpeed,
|
||||
fullStyle: profile.desktopStyles,
|
||||
fullMarkdown: profile.resumeMarkdown,
|
||||
thanksMarkdown: profile.thanksMarkdown,
|
||||
currentStyle: '',
|
||||
enableHtml: false,
|
||||
fullStyle: [
|
||||
`/*
|
||||
* GitHub: https://github.com/hoelee/
|
||||
* Hi, I'm Mr. Hoelee — Web3 Developer & Full Stack Engineer
|
||||
* Let me create an animated resume!
|
||||
*/
|
||||
|
||||
/* Add transition effects to all elements */
|
||||
* {
|
||||
transition: all .1s;
|
||||
}
|
||||
/* Set background color */
|
||||
html {
|
||||
color: rgb(222,222,222); background: rgb(0,64,64);
|
||||
}
|
||||
#content{
|
||||
height:70vh;
|
||||
margin:0;
|
||||
}
|
||||
#foot{
|
||||
height:29vh;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
/* Set border */
|
||||
.styleEditor {
|
||||
padding: .5em;
|
||||
border: 1px solid;
|
||||
margin: .5em;
|
||||
overflow: auto;
|
||||
width: 50vw; height: 70vh;
|
||||
background: rgb(20,20,20);
|
||||
}
|
||||
/* Code highlighting */
|
||||
.token.selector{ color: rgb(130,150,0); }
|
||||
.token.property{ color: rgb(190,140,0); }
|
||||
.token.punctuation{ color: yellow; }
|
||||
.token.function{ color: rgb(40,160,150); }
|
||||
|
||||
/* Add 3D effect */
|
||||
html{
|
||||
perspective: 1000px;
|
||||
}
|
||||
.styleEditor {
|
||||
position: fixed; left: 0; top: 0;
|
||||
-webkit-transition: none;
|
||||
transition: none;
|
||||
-webkit-transform: rotateY(10deg) translateZ(-100px);
|
||||
transform: rotateY(10deg) translateZ(-100px);
|
||||
}
|
||||
|
||||
/* Prepare an editor */
|
||||
.resumeEditor{
|
||||
position: fixed; right: 0; top: 0;
|
||||
padding: .5em; margin: .5em;
|
||||
width: 50vw; height: 70vh;
|
||||
border: 1px solid;
|
||||
background: rgb(200,200,200); color: #222;
|
||||
overflow: auto;
|
||||
-webkit-transition: none;
|
||||
transition: none;
|
||||
-webkit-transform: rotateY(-10deg) translateZ(-100px);
|
||||
transform: rotateY(-10deg) translateZ(-100px);
|
||||
}
|
||||
/* Start writing resume */
|
||||
`, `
|
||||
/* Convert Markdown to HTML
|
||||
* then add some styles to HTML
|
||||
*/
|
||||
.resumeEditor{
|
||||
padding: 0.5em;
|
||||
}
|
||||
.resumeEditor h1{
|
||||
font-size: 1.3em;
|
||||
}
|
||||
.resumeEditor h2{
|
||||
font-size: 1.2em;
|
||||
display: inline-block;
|
||||
border-bottom: 1px solid;
|
||||
margin: 1em 0 .5em;
|
||||
}
|
||||
.resumeEditor ul,.resumeEditor ol{
|
||||
list-style: none;
|
||||
}
|
||||
.resumeEditor ul> li::before{
|
||||
content: '•';
|
||||
margin-right: .5em;
|
||||
}
|
||||
.resumeEditor ol {
|
||||
counter-reset: section;
|
||||
}
|
||||
.resumeEditor ol li::before {
|
||||
counter-increment: section;
|
||||
content: counters(section, ".") " ";
|
||||
margin-right: .5em;
|
||||
}
|
||||
.resumeEditor blockquote {
|
||||
margin: 1em;
|
||||
padding: .5em;
|
||||
background: #ddd;
|
||||
}
|
||||
`, `/* Write a thank you note.
|
||||
* Thanks for everyone's attention.
|
||||
*/
|
||||
.styleEditor{
|
||||
width:49vw;
|
||||
height:70vh;
|
||||
margin-left:1.2vw;
|
||||
}
|
||||
.resumeEditor{
|
||||
width:49vw;
|
||||
height:70vh;
|
||||
margin-right:1.2em;
|
||||
}
|
||||
|
||||
.thankEditor{
|
||||
position: relative; left: 0; top: 0;
|
||||
background: #E9D9BB;
|
||||
color: #001C42;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.thankEditor {
|
||||
width: 99vw; height: 45vh;
|
||||
border: 1px solid #ccc;
|
||||
font-size: .9em;
|
||||
}
|
||||
`,`
|
||||
.thankEditor{
|
||||
padding: .5em; margin: .5em; margin-top:1em;
|
||||
}
|
||||
|
||||
.thankEditor ul,.thankEditor ol{
|
||||
list-style: none;
|
||||
}
|
||||
.thankEditor ul> li::before{
|
||||
content: '☞'; color: red;
|
||||
margin-right: .5em;
|
||||
}
|
||||
.thankEditor ol {
|
||||
counter-reset: section;
|
||||
}
|
||||
.thankEditor ol li::before {
|
||||
counter-increment: section;
|
||||
content: counters(section, "☞") " ";
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
.thankEditor{
|
||||
width: 95vw;
|
||||
height: 45vh;
|
||||
margin: 0 auto;
|
||||
-webkit-transition: none;
|
||||
transition: none;
|
||||
-webkit-transform: rotateX(-10deg) translateZ(-200px);
|
||||
transform: rotateX(-10deg) translateZ(-200px);
|
||||
}
|
||||
|
||||
`],
|
||||
currentMarkdown: '',
|
||||
currentThankMarkdown: '',
|
||||
fullMarkdown: `Mr. Hoelee
|
||||
====
|
||||
Hi, I'm Mr. Hoelee — a Web3 Developer & Experience Full Stack Engineer.
|
||||
I design and build bridges between Web2 and Web3 — crafting scalable backend systems, gas-optimized smart contracts, and immersive decentralized frontends.
|
||||
My passion lies at the intersection of blockchain innovation, AI automation, and full-stack engineering — shaping how the next internet will work.
|
||||
|
||||
About Me
|
||||
----
|
||||
I'm a passionate Web3 developer with hands-on experience creating secure, upgradeable, and gas-efficient ERC-20 / ERC-721 smart contracts using Solidity, Hardhat, and Foundry.
|
||||
Beyond the blockchain, I bring an enterprise-level backend mindset — leveraging Java Spring Boot, CodeIgniter, and Dockerized infrastructure to scale decentralized apps with the reliability of traditional systems.
|
||||
When I'm not building, I explore the evolving Web3 landscape — from Layer 2 protocols and DAO governance to DeFi innovation and on-chain analytics.
|
||||
My mission: to merge creativity, code, and cryptography into meaningful digital experiences.
|
||||
|
||||
Web3 & Blockchain
|
||||
----
|
||||
- Solidity smart contracts (ERC-20 / ERC-721 / upgradeable patterns)
|
||||
- Hardhat, Foundry testing, OpenZeppelin & Chainlink Oracles
|
||||
- Alchemy SDK, Polygon, IPFS integration
|
||||
|
||||
Frontend Development
|
||||
----
|
||||
- Web3.js / Ethers.js integration
|
||||
- JavaScript, jQuery, HTML5, CSS3
|
||||
- UI/UX prototyping with Photoshop, Illustrator, Canva
|
||||
|
||||
Backend & DevOps
|
||||
----
|
||||
- PHP CodeIgniter (Web2↔Web3 bridge)
|
||||
- Java Spring Boot + Hibernate for scalable data layers
|
||||
- Databases: MySQL, MongoDB, Memcached, Elasticsearch
|
||||
- Docker, Nginx, IIS, OpenLiteSpeed, Apache Tomcat, WordPress
|
||||
- Server management (Windows, Ubuntu, unRaid, DSM)
|
||||
|
||||
Work Ethic
|
||||
----
|
||||
- Effective Communicator: Strong written & verbal clarity in remote teams
|
||||
- Problem-Solver: Adaptive mindset for complex, high-speed development
|
||||
- Continuous Learner: Always exploring blockchain advancements
|
||||
- AI-Driven: Using AI to accelerate workflows and creative tasks
|
||||
- Client-Focused: Prioritizing real solutions and transparent delivery
|
||||
|
||||
Education - Bachelor of Information System (Hons)
|
||||
----
|
||||
- Universiti Tunku Abdul Rahman (UTAR), Kampar, Malaysia
|
||||
- March 2016 | CGPA: 3.06 / 4.00 - Degree In Merit
|
||||
- Download Certificate → [hoelee.com/cert](https://hoelee.com/cert)
|
||||
|
||||
Languages
|
||||
----
|
||||
English | Malay | Mandarin | Cantonese | Hokkien
|
||||
|
||||
Interests
|
||||
----
|
||||
- DeFi Innovation
|
||||
- DAO Governance
|
||||
- AI-assisted Development
|
||||
- Cryptography
|
||||
- On-Chain Analytics
|
||||
|
||||
|
||||
`, thanksMarkdown: `
|
||||
Thank you for reading!
|
||||
----
|
||||
|
||||
I'm open to remote collaborations and Web3-driven projects.
|
||||
|
||||
Let's build something that connects the decentralized future with real-world impact.
|
||||
|
||||
* WhatsApp Mr Hoelee Now → [+6012-7972969](https://wa.me/60127972969)
|
||||
* Email Mr Hoelee Now → [[email protected]](mailto:[email protected])
|
||||
* Passionate about bridging the gap between traditional systems and decentralized technologies
|
||||
* Ready to contribute to innovative Web3 projects that solve real-world problems
|
||||
* Available for remote collaboration with forward-thinking teams and startups
|
||||
* Let's discuss how we can leverage blockchain technology to create meaningful digital experiences
|
||||
|
||||
Get in touch to explore opportunities in:
|
||||
* DeFi protocol development
|
||||
* Smart contract architecture and optimization
|
||||
* Web3 frontend integration
|
||||
* Scalable backend systems for dApps
|
||||
* Cross-chain solutions and Layer 2 implementations
|
||||
|
||||
`
|
||||
enableHtml: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.makeResume()
|
||||
},
|
||||
|
||||
methods: {
|
||||
makeResume: async function () {
|
||||
await this.progressivelyShowStyle(0);
|
||||
await this.progressivelyShowResume();
|
||||
await this.progressivelyShowStyle(1);
|
||||
await this.showHtml();
|
||||
await this.progressivelyShowStyle(1);
|
||||
await this.progressivelyShowThanks();
|
||||
await this.progressivelyShowStyle(0)
|
||||
await this.progressivelyShowResume()
|
||||
await this.progressivelyShowStyle(1)
|
||||
await this.showHtml()
|
||||
await this.progressivelyShowStyle(1)
|
||||
await this.progressivelyShowThanks()
|
||||
await this.progressivelyShowStyle(1)
|
||||
},
|
||||
showHtml() {
|
||||
return new Promise((resolve, reject) => {
|
||||
return new Promise((resolve) => {
|
||||
this.enableHtml = true
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
progressivelyShowStyle(n) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let interval = this.interval
|
||||
let showStyle = (async function () {
|
||||
let style = this.fullStyle[n]
|
||||
if (!style) {
|
||||
return
|
||||
}
|
||||
// Calculate total character count of first n styles
|
||||
let length = this.fullStyle.filter((_, index) => index <= n).map((item) => item.length).reduce((p, c) => p + c, 0)
|
||||
let prefixLength = length - style.length
|
||||
return new Promise((resolve) => {
|
||||
const interval = this.interval
|
||||
const showStyle = (() => {
|
||||
const style = this.fullStyle[n]
|
||||
if (!style) return
|
||||
const length = this.fullStyle.filter((_, index) => index <= n).map((item) => item.length).reduce((p, c) => p + c, 0)
|
||||
const prefixLength = length - style.length
|
||||
if (this.currentStyle.length < length) {
|
||||
let l = this.currentStyle.length - prefixLength
|
||||
let char = style.substring(l, l + 1) || ' '
|
||||
this.currentStyle += char
|
||||
const l = this.currentStyle.length - prefixLength
|
||||
this.currentStyle += style.substring(l, l + 1) || ' '
|
||||
if (style.substring(l - 1, l) === '\n' && this.$refs.styleEditor) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.styleEditor.goBottom()
|
||||
})
|
||||
this.$nextTick(() => this.$refs.styleEditor.goBottom())
|
||||
}
|
||||
setTimeout(showStyle, interval)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
}).bind(this)
|
||||
})
|
||||
showStyle()
|
||||
})
|
||||
},
|
||||
progressivelyShowResume() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let length = this.fullMarkdown.length
|
||||
let interval = this.interval
|
||||
let showResume = () => {
|
||||
return new Promise((resolve) => {
|
||||
const length = this.fullMarkdown.length
|
||||
const interval = this.interval
|
||||
const showResume = () => {
|
||||
if (this.currentMarkdown.length < length) {
|
||||
this.currentMarkdown = this.fullMarkdown.substring(0, this.currentMarkdown.length + 1)
|
||||
let lastChar = this.currentMarkdown[this.currentMarkdown.length - 1]
|
||||
let prevChar = this.currentMarkdown[this.currentMarkdown.length - 2]
|
||||
const prevChar = this.currentMarkdown[this.currentMarkdown.length - 2]
|
||||
if (prevChar === '\n' && this.$refs.resumeEditor) {
|
||||
this.$nextTick(() => this.$refs.resumeEditor.goBottom())
|
||||
}
|
||||
@@ -343,14 +93,13 @@ Get in touch to explore opportunities in:
|
||||
})
|
||||
},
|
||||
progressivelyShowThanks() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let length = this.thanksMarkdown.length
|
||||
let interval = this.interval
|
||||
let showThanks = () => {
|
||||
return new Promise((resolve) => {
|
||||
const length = this.thanksMarkdown.length
|
||||
const interval = this.interval
|
||||
const showThanks = () => {
|
||||
if (this.currentThankMarkdown.length < length) {
|
||||
this.currentThankMarkdown = this.thanksMarkdown.substring(0, this.currentThankMarkdown.length + 1)
|
||||
let lastChar = this.currentThankMarkdown[this.currentThankMarkdown.length - 1]
|
||||
let prevChar = this.currentThankMarkdown[this.currentThankMarkdown.length - 2]
|
||||
const prevChar = this.currentThankMarkdown[this.currentThankMarkdown.length - 2]
|
||||
if (prevChar === '\n' && this.$refs.thankEditor) {
|
||||
this.$nextTick(() => this.$refs.thankEditor.goBottom())
|
||||
}
|
||||
@@ -364,7 +113,6 @@ Get in touch to explore opportunities in:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
+25
-239
@@ -6,232 +6,27 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import profile from './config/profile.js'
|
||||
import StyleEditor from './components/StyleEditor.vue'
|
||||
import ResumeEditor from './components/ResumeEditor.vue'
|
||||
import './assets/reset.css'
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
components: {
|
||||
StyleEditor,
|
||||
ResumeEditor
|
||||
},
|
||||
components: { StyleEditor, ResumeEditor },
|
||||
data() {
|
||||
return {
|
||||
interval: 1,
|
||||
interval: profile.typingSpeed,
|
||||
fullStyle: profile.mobileStyles,
|
||||
fullMarkdown: profile.resumeMarkdown,
|
||||
currentStyle: '',
|
||||
enableHtml: false,
|
||||
fullStyle: [
|
||||
`/*
|
||||
* GitHub: https://github.com/hoelee/
|
||||
* Hi, I'm Mr. HoeleeWeb3 Developer & Full Stack Engineer
|
||||
* Let me create an animated resume!
|
||||
*/
|
||||
|
||||
/* Add transition effects to all elements */
|
||||
* {
|
||||
transition: all .2s;
|
||||
}
|
||||
/* Set background color */
|
||||
html {
|
||||
color: rgb(222,222,222);
|
||||
background: rgb(0,43,54);
|
||||
}
|
||||
/* Set border */
|
||||
.styleEditor {
|
||||
padding: .5em;
|
||||
border: 1px solid;
|
||||
overflow: auto;
|
||||
width: 96vw;
|
||||
margin: 2.3vh 2vw;
|
||||
height: 90vh;
|
||||
}
|
||||
/* Too short */
|
||||
.styleEditor {
|
||||
height: 47vh;
|
||||
}
|
||||
/* Code highlighting */
|
||||
.token.selector{
|
||||
color: rgb(133,153,0);
|
||||
}
|
||||
.token.property{
|
||||
color: rgb(187,137,0);
|
||||
}
|
||||
.token.punctuation{
|
||||
color: yellow;
|
||||
}
|
||||
.token.function{
|
||||
color: rgb(42,161,152);
|
||||
}
|
||||
|
||||
/* Add 3D effect */
|
||||
html{
|
||||
perspective: 1000px;
|
||||
}
|
||||
.styleEditor {
|
||||
position: fixed; left: 0; top: 0;
|
||||
transform: rotateX(-10deg) translateZ(-50px) ;
|
||||
}
|
||||
|
||||
/* Prepare an editor */
|
||||
.resumeEditor{
|
||||
position: fixed;
|
||||
top: 48%; left: 0;
|
||||
padding: .5em; margin: 1.5vh;
|
||||
width: 94vw; height: 48.5vh;
|
||||
border: 1px solid;
|
||||
background: white; color: #222;
|
||||
overflow: auto;
|
||||
}
|
||||
/* Start writing resume */
|
||||
|
||||
|
||||
`,
|
||||
`
|
||||
/* Convert Markdown to HTML
|
||||
* then add some styles to HTML
|
||||
*/
|
||||
.resumeEditor{
|
||||
padding: 1em;
|
||||
}
|
||||
.resumeEditor h1{
|
||||
font-size: 1.3em;
|
||||
}
|
||||
.resumeEditor h2{
|
||||
font-size: 1.2em;
|
||||
display: inline-block;
|
||||
border-bottom: 1px solid;
|
||||
margin: 1em 0 .5em;
|
||||
}
|
||||
.resumeEditor ul,.resumeEditor ol{
|
||||
list-style: none;
|
||||
}
|
||||
.resumeEditor ul> li::before{
|
||||
content: '•';
|
||||
margin-right: .5em;
|
||||
}
|
||||
.resumeEditor ol {
|
||||
counter-reset: section;
|
||||
}
|
||||
.resumeEditor ol li::before {
|
||||
counter-increment: section;
|
||||
content: counters(section, ".") " ";
|
||||
margin-right: .5em;
|
||||
}
|
||||
.resumeEditor blockquote {
|
||||
margin: 1em;
|
||||
padding: .5em;
|
||||
background: #ddd;
|
||||
}
|
||||
`, `
|
||||
/* Add mobile-optimized styles */
|
||||
.resumeEditor {
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.resumeEditor h1 {
|
||||
color: #0066cc;
|
||||
text-align: center;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
.resumeEditor a {
|
||||
color: #0066cc;
|
||||
text-decoration: none;
|
||||
}
|
||||
.resumeEditor a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
`],
|
||||
currentMarkdown: '',
|
||||
fullMarkdown: `Mr. Hoelee
|
||||
====
|
||||
Hi, I'm Mr. Hoelee — a Web3 Developer & Experience Full Stack Engineer.
|
||||
|
||||
I design and build bridges between Web2 and Web3 — crafting scalable backend systems, gas-optimized smart contracts, and immersive decentralized frontends.
|
||||
|
||||
My passion lies at the intersection of blockchain innovation, AI automation, and full-stack engineering — shaping how the next internet will work.
|
||||
|
||||
About Me
|
||||
----
|
||||
I'm a passionate Web3 developer with hands-on experience creating secure, upgradeable, and gas-efficient ERC-20 / ERC-721 smart contracts using Solidity, Hardhat, and Foundry.
|
||||
|
||||
Beyond the blockchain, I bring an enterprise-level backend mindset — leveraging Java Spring Boot, CodeIgniter, and Dockerized infrastructure to scale decentralized apps with the reliability of traditional systems.
|
||||
|
||||
When I'm not building, I explore the evolving Web3 landscape — from Layer 2 protocols and DAO governance to DeFi innovation and on-chain analytics.
|
||||
|
||||
My mission: to merge creativity, code, and cryptography into meaningful digital experiences.
|
||||
|
||||
Web3 & Blockchain
|
||||
----
|
||||
- Solidity smart contracts (ERC-20 / ERC-721 / upgradeable patterns)
|
||||
- Hardhat, Foundry testing, OpenZeppelin & Chainlink Oracles
|
||||
- Alchemy SDK, Polygon, IPFS integration
|
||||
|
||||
Frontend Development
|
||||
----
|
||||
- Web3.js / Ethers.js integration
|
||||
- JavaScript, jQuery, HTML5, CSS3
|
||||
- UI/UX prototyping with Photoshop, Illustrator, Canva
|
||||
|
||||
Backend & DevOps
|
||||
----
|
||||
- PHP CodeIgniter (Web2↔Web3 bridge)
|
||||
- Java Spring Boot + Hibernate for scalable data layers
|
||||
- Databases: MySQL, MongoDB, Memcached, Elasticsearch
|
||||
- Docker, Nginx, IIS, OpenLiteSpeed, Apache Tomcat, WordPress
|
||||
- Server management (Windows, Ubuntu, unRaid, DSM)
|
||||
|
||||
Work Ethic
|
||||
----
|
||||
- Effective Communicator: Strong written & verbal clarity in remote teams
|
||||
- Problem-Solver: Adaptive mindset for complex, high-speed development
|
||||
- Continuous Learner: Always exploring blockchain advancements
|
||||
- AI-Driven: Using AI to accelerate workflows and creative tasks
|
||||
- Client-Focused: Prioritizing real solutions and transparent delivery
|
||||
|
||||
Education - Bachelor of Information System (Hons)
|
||||
----
|
||||
- Universiti Tunku Abdul Rahman (UTAR), Kampar, Malaysia
|
||||
- March 2016 | CGPA: 3.06 / 4.00 - Degree In Merit
|
||||
- Download Certificate → [hoelee.com/cert](https://hoelee.com/cert)
|
||||
|
||||
Languages
|
||||
----
|
||||
English | Malay | Mandarin | Cantonese | Hokkien
|
||||
|
||||
Interests
|
||||
----
|
||||
- DeFi Innovation
|
||||
- DAO Governance
|
||||
- AI-assisted Development
|
||||
- Cryptography
|
||||
- On-Chain Analytics
|
||||
|
||||
Contact Me
|
||||
----
|
||||
I'm open to remote collaborations and Web3-driven projects.
|
||||
|
||||
Let's build something that connects the decentralized future with real-world impact.
|
||||
|
||||
* WhatsApp Mr Hoelee Now → [+6012-7972969](https://wa.me/60127972969)
|
||||
* Email Mr Hoelee Now → [[email protected]](mailto:[email protected])
|
||||
* Ready to contribute to innovative Web3 projects that solve real-world problems
|
||||
* Available for remote collaboration with forward-thinking teams and startups
|
||||
|
||||
Get in touch to explore opportunities in:
|
||||
* DeFi protocol development
|
||||
* Smart contract architecture and optimization
|
||||
* Web3 frontend integration
|
||||
* Scalable backend systems for dApps
|
||||
* Cross-chain solutions and Layer 2 implementations
|
||||
|
||||
`
|
||||
enableHtml: false
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.makeResume()
|
||||
},
|
||||
|
||||
methods: {
|
||||
makeResume: async function () {
|
||||
await this.progressivelyShowStyle(0)
|
||||
@@ -240,50 +35,43 @@ Get in touch to explore opportunities in:
|
||||
await this.showHtml()
|
||||
await this.progressivelyShowStyle(1)
|
||||
},
|
||||
showHtml: function () {
|
||||
return new Promise((resolve, reject) => {
|
||||
showHtml() {
|
||||
return new Promise((resolve) => {
|
||||
this.enableHtml = true
|
||||
this.$nextTick(() => {
|
||||
this.$refs.resumeEditor.goTop()
|
||||
})
|
||||
this.$nextTick(() => this.$refs.resumeEditor.goTop())
|
||||
resolve()
|
||||
})
|
||||
},
|
||||
progressivelyShowStyle(n) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let interval = this.interval
|
||||
let showStyle = (async function () {
|
||||
let style = this.fullStyle[n]
|
||||
if (!style) { return }
|
||||
// Calculate total character count of first n styles
|
||||
let length = this.fullStyle.filter((_, index) => index <= n).map((item) => item.length).reduce((p, c) => p + c, 0)
|
||||
let prefixLength = length - style.length
|
||||
return new Promise((resolve) => {
|
||||
const interval = this.interval
|
||||
const showStyle = (() => {
|
||||
const style = this.fullStyle[n]
|
||||
if (!style) return
|
||||
const length = this.fullStyle.filter((_, index) => index <= n).map((item) => item.length).reduce((p, c) => p + c, 0)
|
||||
const prefixLength = length - style.length
|
||||
if (this.currentStyle.length < length) {
|
||||
let l = this.currentStyle.length - prefixLength
|
||||
let char = style.substring(l, l + 1) || ' '
|
||||
this.currentStyle += char
|
||||
const l = this.currentStyle.length - prefixLength
|
||||
this.currentStyle += style.substring(l, l + 1) || ' '
|
||||
if (style.substring(l - 1, l) === '\n' && this.$refs.styleEditor) {
|
||||
this.$nextTick(() => {
|
||||
this.$refs.styleEditor.goBottom()
|
||||
})
|
||||
this.$nextTick(() => this.$refs.styleEditor.goBottom())
|
||||
}
|
||||
setTimeout(showStyle, interval)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
}).bind(this)
|
||||
})
|
||||
showStyle()
|
||||
})
|
||||
},
|
||||
progressivelyShowResume() {
|
||||
return new Promise((resolve, reject) => {
|
||||
let length = this.fullMarkdown.length
|
||||
let interval = this.interval
|
||||
let showResume = () => {
|
||||
return new Promise((resolve) => {
|
||||
const length = this.fullMarkdown.length
|
||||
const interval = this.interval
|
||||
const showResume = () => {
|
||||
if (this.currentMarkdown.length < length) {
|
||||
this.currentMarkdown = this.fullMarkdown.substring(0, this.currentMarkdown.length + 1)
|
||||
let lastChar = this.currentMarkdown[this.currentMarkdown.length - 1]
|
||||
let prevChar = this.currentMarkdown[this.currentMarkdown.length - 2]
|
||||
const prevChar = this.currentMarkdown[this.currentMarkdown.length - 2]
|
||||
if (prevChar === '\n' && this.$refs.resumeEditor) {
|
||||
this.$nextTick(() => this.$refs.resumeEditor.goBottom())
|
||||
}
|
||||
@@ -297,7 +85,6 @@ Get in touch to explore opportunities in:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@@ -314,5 +101,4 @@ Get in touch to explore opportunities in:
|
||||
*{
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,381 @@
|
||||
export default {
|
||||
// Personal info
|
||||
name: 'Mr. Hoelee',
|
||||
title: 'Web3 Developer & Full Stack Engineer',
|
||||
githubUrl: 'https://github.com/hoelee/',
|
||||
|
||||
// Animation speed (ms per character typed)
|
||||
// Lower = faster. Recommended range: 1 (instant) to 20 (dramatic slow)
|
||||
typingSpeed: 1,
|
||||
|
||||
// Resume content in Markdown
|
||||
resumeMarkdown: `Mr. Hoelee
|
||||
====
|
||||
Hi, I'm Mr. Hoelee — a Web3 Developer & Experience Full Stack Engineer.
|
||||
I design and build bridges between Web2 and Web3 — crafting scalable backend systems, gas-optimized smart contracts, and immersive decentralized frontends.
|
||||
My passion lies at the intersection of blockchain innovation, AI automation, and full-stack engineering — shaping how the next internet will work.
|
||||
|
||||
About Me
|
||||
----
|
||||
I'm a passionate Web3 developer with hands-on experience creating secure, upgradeable, and gas-efficient ERC-20 / ERC-721 smart contracts using Solidity, Hardhat, and Foundry.
|
||||
Beyond the blockchain, I bring an enterprise-level backend mindset — leveraging Java Spring Boot, CodeIgniter, and Dockerized infrastructure to scale decentralized apps with the reliability of traditional systems.
|
||||
When I'm not building, I explore the evolving Web3 landscape — from Layer 2 protocols and DAO governance to DeFi innovation and on-chain analytics.
|
||||
My mission: to merge creativity, code, and cryptography into meaningful digital experiences.
|
||||
|
||||
Web3 & Blockchain
|
||||
----
|
||||
- Solidity smart contracts (ERC-20 / ERC-721 / upgradeable patterns)
|
||||
- Hardhat, Foundry testing, OpenZeppelin & Chainlink Oracles
|
||||
- Alchemy SDK, Polygon, IPFS integration
|
||||
|
||||
Frontend Development
|
||||
----
|
||||
- Web3.js / Ethers.js integration
|
||||
- JavaScript, jQuery, HTML5, CSS3
|
||||
- UI/UX prototyping with Photoshop, Illustrator, Canva
|
||||
|
||||
Backend & DevOps
|
||||
----
|
||||
- PHP CodeIgniter (Web2↔Web3 bridge)
|
||||
- Java Spring Boot + Hibernate for scalable data layers
|
||||
- Databases: MySQL, MongoDB, Memcached, Elasticsearch
|
||||
- Docker, Nginx, IIS, OpenLiteSpeed, Apache Tomcat, WordPress
|
||||
- Server management (Windows, Ubuntu, unRaid, DSM)
|
||||
|
||||
Work Ethic
|
||||
----
|
||||
- Effective Communicator: Strong written & verbal clarity in remote teams
|
||||
- Problem-Solver: Adaptive mindset for complex, high-speed development
|
||||
- Continuous Learner: Always exploring blockchain advancements
|
||||
- AI-Driven: Using AI to accelerate workflows and creative tasks
|
||||
- Client-Focused: Prioritizing real solutions and transparent delivery
|
||||
|
||||
Education - Bachelor of Information System (Hons)
|
||||
----
|
||||
- Universiti Tunku Abdul Rahman (UTAR), Kampar, Malaysia
|
||||
- March 2016 | CGPA: 3.06 / 4.00 - Degree In Merit
|
||||
- Download Certificate → [hoelee.com/cert](https://hoelee.com/cert)
|
||||
|
||||
Languages
|
||||
----
|
||||
English | Malay | Mandarin | Cantonese | Hokkien
|
||||
|
||||
Interests
|
||||
----
|
||||
- DeFi Innovation
|
||||
- DAO Governance
|
||||
- AI-assisted Development
|
||||
- Cryptography
|
||||
- On-Chain Analytics
|
||||
|
||||
|
||||
`,
|
||||
|
||||
// Thank you section markdown
|
||||
thanksMarkdown: `
|
||||
Thank you for reading!
|
||||
----
|
||||
|
||||
I'm open to remote collaborations and Web3-driven projects.
|
||||
|
||||
Let's build something that connects the decentralized future with real-world impact.
|
||||
|
||||
* WhatsApp Mr Hoelee Now → [+6012-7972969](https://wa.me/60127972969)
|
||||
* Email Mr Hoelee Now → [[email protected]](mailto:[email protected])
|
||||
* Passionate about bridging the gap between traditional systems and decentralized technologies
|
||||
* Ready to contribute to innovative Web3 projects that solve real-world problems
|
||||
* Available for remote collaboration with forward-thinking teams and startups
|
||||
* Let's discuss how we can leverage blockchain technology to create meaningful digital experiences
|
||||
|
||||
Get in touch to explore opportunities in:
|
||||
* DeFi protocol development
|
||||
* Smart contract architecture and optimization
|
||||
* Web3 frontend integration
|
||||
* Scalable backend systems for dApps
|
||||
* Cross-chain solutions and Layer 2 implementations
|
||||
|
||||
`,
|
||||
|
||||
// CSS animation stages — array of CSS strings typed in sequence
|
||||
desktopStyles: [
|
||||
`/*
|
||||
* GitHub: https://github.com/hoelee/
|
||||
* Hi, I'm Mr. Hoelee — Web3 Developer & Full Stack Engineer
|
||||
* Let me create an animated resume!
|
||||
*/
|
||||
|
||||
/* Add transition effects to all elements */
|
||||
* {
|
||||
transition: all .1s;
|
||||
}
|
||||
/* Set background color */
|
||||
html {
|
||||
color: rgb(222,222,222); background: rgb(0,64,64);
|
||||
}
|
||||
#content{
|
||||
height:70vh;
|
||||
margin:0;
|
||||
}
|
||||
#foot{
|
||||
height:29vh;
|
||||
margin:0;
|
||||
}
|
||||
|
||||
/* Set border */
|
||||
.styleEditor {
|
||||
padding: .5em;
|
||||
border: 1px solid;
|
||||
margin: .5em;
|
||||
overflow: auto;
|
||||
width: 50vw; height: 70vh;
|
||||
background: rgb(20,20,20);
|
||||
}
|
||||
/* Code highlighting */
|
||||
.token.selector{ color: rgb(130,150,0); }
|
||||
.token.property{ color: rgb(190,140,0); }
|
||||
.token.punctuation{ color: yellow; }
|
||||
.token.function{ color: rgb(40,160,150); }
|
||||
|
||||
/* Add 3D effect */
|
||||
html{
|
||||
perspective: 1000px;
|
||||
}
|
||||
.styleEditor {
|
||||
position: fixed; left: 0; top: 0;
|
||||
-webkit-transition: none;
|
||||
transition: none;
|
||||
-webkit-transform: rotateY(10deg) translateZ(-100px);
|
||||
transform: rotateY(10deg) translateZ(-100px);
|
||||
}
|
||||
|
||||
/* Prepare an editor */
|
||||
.resumeEditor{
|
||||
position: fixed; right: 0; top: 0;
|
||||
padding: .5em; margin: .5em;
|
||||
width: 50vw; height: 70vh;
|
||||
border: 1px solid;
|
||||
background: rgb(200,200,200); color: #222;
|
||||
overflow: auto;
|
||||
-webkit-transition: none;
|
||||
transition: none;
|
||||
-webkit-transform: rotateY(-10deg) translateZ(-100px);
|
||||
transform: rotateY(-10deg) translateZ(-100px);
|
||||
}
|
||||
/* Start writing resume */
|
||||
`, `
|
||||
/* Convert Markdown to HTML
|
||||
* then add some styles to HTML
|
||||
*/
|
||||
.resumeEditor{
|
||||
padding: 0.5em;
|
||||
}
|
||||
.resumeEditor h1{
|
||||
font-size: 1.3em;
|
||||
}
|
||||
.resumeEditor h2{
|
||||
font-size: 1.2em;
|
||||
display: inline-block;
|
||||
border-bottom: 1px solid;
|
||||
margin: 1em 0 .5em;
|
||||
}
|
||||
.resumeEditor ul,.resumeEditor ol{
|
||||
list-style: none;
|
||||
}
|
||||
.resumeEditor ul> li::before{
|
||||
content: '•';
|
||||
margin-right: .5em;
|
||||
}
|
||||
.resumeEditor ol {
|
||||
counter-reset: section;
|
||||
}
|
||||
.resumeEditor ol li::before {
|
||||
counter-increment: section;
|
||||
content: counters(section, ".") " ";
|
||||
margin-right: .5em;
|
||||
}
|
||||
.resumeEditor blockquote {
|
||||
margin: 1em;
|
||||
padding: .5em;
|
||||
background: #ddd;
|
||||
}
|
||||
`, `/* Write a thank you note.
|
||||
* Thanks for everyone's attention.
|
||||
*/
|
||||
.styleEditor{
|
||||
width:49vw;
|
||||
height:70vh;
|
||||
margin-left:1.2vw;
|
||||
}
|
||||
.resumeEditor{
|
||||
width:49vw;
|
||||
height:70vh;
|
||||
margin-right:1.2em;
|
||||
}
|
||||
|
||||
.thankEditor{
|
||||
position: relative; left: 0; top: 0;
|
||||
background: #E9D9BB;
|
||||
color: #001C42;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.thankEditor {
|
||||
width: 99vw; height: 45vh;
|
||||
border: 1px solid #ccc;
|
||||
font-size: .9em;
|
||||
}
|
||||
`,`
|
||||
.thankEditor{
|
||||
padding: .5em; margin: .5em; margin-top:1em;
|
||||
}
|
||||
|
||||
.thankEditor ul,.thankEditor ol{
|
||||
list-style: none;
|
||||
}
|
||||
.thankEditor ul> li::before{
|
||||
content: '☞'; color: red;
|
||||
margin-right: .5em;
|
||||
}
|
||||
.thankEditor ol {
|
||||
counter-reset: section;
|
||||
}
|
||||
.thankEditor ol li::before {
|
||||
counter-increment: section;
|
||||
content: counters(section, "☞") " ";
|
||||
margin-right: .5em;
|
||||
}
|
||||
|
||||
.thankEditor{
|
||||
width: 95vw;
|
||||
height: 45vh;
|
||||
margin: 0 auto;
|
||||
-webkit-transition: none;
|
||||
transition: none;
|
||||
-webkit-transform: rotateX(-10deg) translateZ(-200px);
|
||||
transform: rotateX(-10deg) translateZ(-200px);
|
||||
}
|
||||
|
||||
`],
|
||||
|
||||
mobileStyles: [
|
||||
`/*
|
||||
* GitHub: https://github.com/hoelee/
|
||||
* Hi, I'm Mr. HoeleeWeb3 Developer & Full Stack Engineer
|
||||
* Let me create an animated resume!
|
||||
*/
|
||||
|
||||
/* Add transition effects to all elements */
|
||||
* {
|
||||
transition: all .2s;
|
||||
}
|
||||
/* Set background color */
|
||||
html {
|
||||
color: rgb(222,222,222);
|
||||
background: rgb(0,43,54);
|
||||
}
|
||||
/* Set border */
|
||||
.styleEditor {
|
||||
padding: .5em;
|
||||
border: 1px solid;
|
||||
overflow: auto;
|
||||
width: 96vw;
|
||||
margin: 2.3vh 2vw;
|
||||
height: 90vh;
|
||||
}
|
||||
/* Too short */
|
||||
.styleEditor {
|
||||
height: 47vh;
|
||||
}
|
||||
/* Code highlighting */
|
||||
.token.selector{
|
||||
color: rgb(133,153,0);
|
||||
}
|
||||
.token.property{
|
||||
color: rgb(187,137,0);
|
||||
}
|
||||
.token.punctuation{
|
||||
color: yellow;
|
||||
}
|
||||
.token.function{
|
||||
color: rgb(42,161,152);
|
||||
}
|
||||
|
||||
/* Add 3D effect */
|
||||
html{
|
||||
perspective: 1000px;
|
||||
}
|
||||
.styleEditor {
|
||||
position: fixed; left: 0; top: 0;
|
||||
transform: rotateX(-10deg) translateZ(-50px) ;
|
||||
}
|
||||
|
||||
/* Prepare an editor */
|
||||
.resumeEditor{
|
||||
position: fixed;
|
||||
top: 48%; left: 0;
|
||||
padding: .5em; margin: 1.5vh;
|
||||
width: 94vw; height: 48.5vh;
|
||||
border: 1px solid;
|
||||
background: white; color: #222;
|
||||
overflow: auto;
|
||||
}
|
||||
/* Start writing resume */
|
||||
|
||||
|
||||
`,
|
||||
`
|
||||
/* Convert Markdown to HTML
|
||||
* then add some styles to HTML
|
||||
*/
|
||||
.resumeEditor{
|
||||
padding: 1em;
|
||||
}
|
||||
.resumeEditor h1{
|
||||
font-size: 1.3em;
|
||||
}
|
||||
.resumeEditor h2{
|
||||
font-size: 1.2em;
|
||||
display: inline-block;
|
||||
border-bottom: 1px solid;
|
||||
margin: 1em 0 .5em;
|
||||
}
|
||||
.resumeEditor ul,.resumeEditor ol{
|
||||
list-style: none;
|
||||
}
|
||||
.resumeEditor ul> li::before{
|
||||
content: '•';
|
||||
margin-right: .5em;
|
||||
}
|
||||
.resumeEditor ol {
|
||||
counter-reset: section;
|
||||
}
|
||||
.resumeEditor ol li::before {
|
||||
counter-increment: section;
|
||||
content: counters(section, ".") " ";
|
||||
margin-right: .5em;
|
||||
}
|
||||
.resumeEditor blockquote {
|
||||
margin: 1em;
|
||||
padding: .5em;
|
||||
background: #ddd;
|
||||
}
|
||||
`, `
|
||||
/* Add mobile-optimized styles */
|
||||
.resumeEditor {
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.resumeEditor h1 {
|
||||
color: #0066cc;
|
||||
text-align: center;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
.resumeEditor a {
|
||||
color: #0066cc;
|
||||
text-decoration: none;
|
||||
}
|
||||
.resumeEditor a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
`]
|
||||
}
|
||||
Reference in New Issue
Block a user