Compare commits
8 Commits
99a3f58b0b
...
3c6654ba47
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c6654ba47 | ||
|
|
12f585642d | ||
|
|
05f6603fc4 | ||
|
|
098d0f5b41 | ||
|
|
5c4c2c3b24 | ||
|
|
658be88bcc | ||
|
|
e1b512d8cd | ||
|
|
1cdaaf5dff |
41
.gitea/workflows/pipeline.yml
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
name: Deploy on push
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "main" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: contains(gitea.event.head_commit.message, '[deploy]')
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install ssh + rsync
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y openssh-client rsync
|
||||||
|
|
||||||
|
- name: Setup SSH
|
||||||
|
env:
|
||||||
|
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
|
||||||
|
run: |
|
||||||
|
mkdir -p ~/.ssh
|
||||||
|
echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_ed25519
|
||||||
|
chmod 600 ~/.ssh/id_ed25519
|
||||||
|
ssh-keyscan -p 22 "rchou.org" >> ~/.ssh/known_hosts
|
||||||
|
chmod 644 ~/.ssh/known_hosts
|
||||||
|
|
||||||
|
- name: Rsync to server
|
||||||
|
env:
|
||||||
|
SSH_TARGET_DIR: /home/cab/docker/portfolio/src
|
||||||
|
RSYNC_SOURCE: .
|
||||||
|
run: |
|
||||||
|
rsync -rz --delete \
|
||||||
|
--no-times --no-perms --no-owner --no-group \
|
||||||
|
--omit-dir-times --mkpath \
|
||||||
|
-e "ssh -i ~/.ssh/id_ed25519 -p 22" \
|
||||||
|
"$RSYNC_SOURCE"/ "deploy@rchou.org:${SSH_TARGET_DIR}/"
|
||||||
|
|
||||||
BIN
favicon/.DS_Store
vendored
Normal file
6
favicon/about.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
This favicon was generated using the following font:
|
||||||
|
|
||||||
|
- Font Title: Fira Sans
|
||||||
|
- Font Author: undefined
|
||||||
|
- Font Source: https://fonts.gstatic.com/s/firasans/v17/va9B4kDNxMZdWfMOD5VnFK_uQR37fF3Wlg.ttf
|
||||||
|
- Font License: undefined)
|
||||||
BIN
favicon/android-chrome-192x192.png
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
BIN
favicon/android-chrome-512x512.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
favicon/apple-touch-icon.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
favicon/favicon-16x16.png
Normal file
|
After Width: | Height: | Size: 641 B |
BIN
favicon/favicon-32x32.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
favicon/favicon.ico
Normal file
|
After Width: | Height: | Size: 15 KiB |
1
favicon/site.webmanifest
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}
|
||||||
BIN
images/cabby.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
images/logo.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
images/tancha.jpg
Normal file
|
After Width: | Height: | Size: 1.5 MiB |
BIN
images/wip.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
images/work.jpg
Normal file
|
After Width: | Height: | Size: 1.2 MiB |
111
index.html
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<!-- Meta Info -->
|
||||||
|
<title>Ryan Chou's Portfolio</title>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="description" content="Ryan Chou's Portfolio">
|
||||||
|
<meta property="og:title" content="Ryan Chou's Portfolio">
|
||||||
|
<meta property="og:description" content="Ryan Chou's Portfolio">
|
||||||
|
<meta property="og:url" content="https://rchou.org">
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:image" content="https://rchou.org/images/cabby.jpg">
|
||||||
|
<!-- Favicon -->
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="./favicon/apple-touch-icon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="./favicon/favicon-32x32.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="./favicon/favicon-16x16.png">
|
||||||
|
<link rel="manifest" href="./favicon/site.webmanifest">
|
||||||
|
<!-- CSS -->
|
||||||
|
<link href="https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.css" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="style/style.css">
|
||||||
|
<link rel="stylesheet" href="style/intro.css">
|
||||||
|
<link rel="stylesheet" href="style/mapbox.css">
|
||||||
|
<link rel="stylesheet" href="style/projects.css">
|
||||||
|
<link rel="stylesheet" href="style/hobbies.css">
|
||||||
|
<!-- Font -->
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<!-- intro.css -->
|
||||||
|
<section id="intro" class="scroll-section">
|
||||||
|
<div id="intro" class="intro">
|
||||||
|
<h1><b>Hi,</b>
|
||||||
|
I'm Ryan Chou</h1>
|
||||||
|
<p>I'm a Computer Science Major at UCSC.
|
||||||
|
Keep scrolling to learn more about me!</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- mapbox.css -->
|
||||||
|
<section id="intro" class="scroll-section">
|
||||||
|
<h2>Experience</h2>
|
||||||
|
<div class="map-wrapper">
|
||||||
|
<div id="map" class="map"></div>
|
||||||
|
<!-- buttons -->
|
||||||
|
<nav class="company-list" id="company-list"></nav>
|
||||||
|
<div id="popup" class="popup"></div>
|
||||||
|
</div>
|
||||||
|
<!-- blurb -->
|
||||||
|
<div class="blurb" id="blurb">
|
||||||
|
<p>Select a company to learn more about what I did there.</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- projects.css -->
|
||||||
|
<section id="intro" class="scroll-section">
|
||||||
|
<div id="projects" class="projects">
|
||||||
|
<h2>Projects</h2>
|
||||||
|
<p>test</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- hobbies.css -->
|
||||||
|
<section id="hobbies" class="scroll-section">
|
||||||
|
<h2>Hobbies</h2>
|
||||||
|
<div class="horizontal-section">
|
||||||
|
<div class="horizontal-section__inner">
|
||||||
|
<!-- Card #1 -->
|
||||||
|
<div class="card">
|
||||||
|
<img src="images/wip.jpg" alt="Hobby 1">
|
||||||
|
<div class="caption">Caption for hobby 1</div>
|
||||||
|
</div>
|
||||||
|
<!-- Card #2 -->
|
||||||
|
<div class="card">
|
||||||
|
<img src="images/wip.jpg" alt="Hobby 2">
|
||||||
|
<div class="caption">Caption for hobby 2</div>
|
||||||
|
</div>
|
||||||
|
<!-- Card #2 -->
|
||||||
|
<div class="card">
|
||||||
|
<img src="images/wip.jpg" alt="Hobby 2">
|
||||||
|
<div class="caption">Caption for hobby 2</div>
|
||||||
|
</div>
|
||||||
|
<!-- Card #2 -->
|
||||||
|
<div class="card">
|
||||||
|
<img src="images/wip.jpg" alt="Hobby 2">
|
||||||
|
<div class="caption">Caption for hobby 2</div>
|
||||||
|
</div>
|
||||||
|
<!-- Card #2 -->
|
||||||
|
<div class="card">
|
||||||
|
<img src="images/wip.jpg" alt="Hobby 2">
|
||||||
|
<div class="caption">
|
||||||
|
<p> test <br> test <br> test <br> test <br> test <br> test <br> test </p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- …add as many cards as you like… -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<!-- thanks.css -->
|
||||||
|
<section id="intro" class="scroll-section">
|
||||||
|
<div id="thanks" class="thanks">
|
||||||
|
<h2>Thanks</h2>
|
||||||
|
<p>Thanks for stopping by. If you like what you saw, please leave a like and subscribe</p>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<!-- JS -->
|
||||||
|
<script src="https://api.mapbox.com/mapbox-gl-js/v2.15.0/mapbox-gl.js"></script>
|
||||||
|
<script src="script/mapbox.js"></script>
|
||||||
|
<script src="script/scroll.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
6
resume.html
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<iframe
|
||||||
|
src="https://mozilla.github.io/pdf.js/web/viewer.html?file=https://rchou.org/resume.pdf"
|
||||||
|
width="100%"
|
||||||
|
height="800px"
|
||||||
|
style="border: none;">
|
||||||
|
</iframe>
|
||||||
BIN
resume.pdf
Normal file
160
script/mapbox.js
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
// script.js
|
||||||
|
|
||||||
|
// 1️⃣ Your Mapbox access token
|
||||||
|
mapboxgl.accessToken = 'pk.eyJ1IjoiY2FiYmJ5eSIsImEiOiJjbWRpYzY1MGgwYzA5Mm1xM25udDUzbGtpIn0.RX6zv4VI6r2vpj7IWidz0w';
|
||||||
|
|
||||||
|
// 2️⃣ Initialize the map zoomed fully out (globe‑like)
|
||||||
|
const map = new mapboxgl.Map({
|
||||||
|
container: 'map',
|
||||||
|
style: 'mapbox://styles/mapbox/streets-v12',
|
||||||
|
center: [0, 0],
|
||||||
|
zoom: 1,
|
||||||
|
attributionControl: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// 3️⃣ Define your companies ([lat, lng], zoom, imageUrl, description)
|
||||||
|
const companies = [
|
||||||
|
{
|
||||||
|
id: 'overview',
|
||||||
|
name: 'Overview',
|
||||||
|
coords: [40.14010599415405, -107.69483342077913],
|
||||||
|
zoom: 3,
|
||||||
|
imageUrl: 'images/wip.jpg',
|
||||||
|
description: `
|
||||||
|
<h2>Overview</h2>
|
||||||
|
<p>Use the controls in the top left corner to jump to a spot!</p>
|
||||||
|
`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tancha',
|
||||||
|
name: 'Tan‑Cha',
|
||||||
|
coords: [37.325382569107695, -122.01149036275054],
|
||||||
|
zoom: 9,
|
||||||
|
imageUrl: 'images/tancha.jpg',
|
||||||
|
description: `
|
||||||
|
<h2>Tan‑Cha</h2>
|
||||||
|
<p>Wip.</p>
|
||||||
|
`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'pokehouse',
|
||||||
|
name: 'Poke House',
|
||||||
|
coords: [37.301113384436285, -121.9493462690826],
|
||||||
|
zoom: 9,
|
||||||
|
imageUrl: 'images/wip.jpg',
|
||||||
|
description: `
|
||||||
|
<h2>Poke House</h2>
|
||||||
|
<p>Wip.</p>
|
||||||
|
`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'nanobase',
|
||||||
|
name: 'NanoBase',
|
||||||
|
coords: [34.68104506798117, 135.49167196036512],
|
||||||
|
zoom: 9,
|
||||||
|
imageUrl: 'images/work.jpg',
|
||||||
|
description: `
|
||||||
|
<h2>NanoBase</h2>
|
||||||
|
<p>Developed automated payroll processing scripts in Python, reducing errors by 85%.</p>
|
||||||
|
<a href="https://www.nanobase.co.jp/blogs/30">NanoBase Blog</a>
|
||||||
|
`
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'lanner',
|
||||||
|
name: 'Lanner Electronics',
|
||||||
|
coords: [43.69824981965482, -79.62570806485385],
|
||||||
|
zoom: 9,
|
||||||
|
imageUrl: 'images/wip.jpg',
|
||||||
|
description: `
|
||||||
|
<h2>Lanner Electronics</h2>
|
||||||
|
<p>Wip.</p>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
// 4️⃣ Populate the company list
|
||||||
|
const listEl = document.getElementById('company-list');
|
||||||
|
companies.forEach((company, idx) => {
|
||||||
|
const btn = document.createElement('button');
|
||||||
|
btn.textContent = company.name;
|
||||||
|
btn.id = company.id;
|
||||||
|
btn.addEventListener('click', () => selectCompany(idx));
|
||||||
|
listEl.appendChild(btn);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Holder for mapboxgl.Marker instances
|
||||||
|
const markers = [];
|
||||||
|
|
||||||
|
// Reference to the .map-wrapper for our fixed popups
|
||||||
|
const mapWrapper = document.querySelector('.map-wrapper');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a fixed-position popup (does not move with the map)
|
||||||
|
*/
|
||||||
|
function showFixedPopup(company, [lng, lat]) {
|
||||||
|
// Remove any existing fixed popups
|
||||||
|
document.querySelectorAll('.fixed-popup').forEach(el => el.remove());
|
||||||
|
|
||||||
|
// Build the popup element
|
||||||
|
const popupEl = document.createElement('div');
|
||||||
|
popupEl.className = 'fixed-popup';
|
||||||
|
popupEl.innerHTML = `
|
||||||
|
<img
|
||||||
|
loading="lazy"
|
||||||
|
src="${company.imageUrl}"
|
||||||
|
alt="Me at ${company.name}" />
|
||||||
|
<strong>${company.name}</strong>
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Attach into the map wrapper (above the map canvas)
|
||||||
|
mapWrapper.appendChild(popupEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles company selection:
|
||||||
|
* - cleans up old markers/popups
|
||||||
|
* - flies the map
|
||||||
|
* - updates the blurb
|
||||||
|
* - adds marker + fixed popup (if not overview)
|
||||||
|
*/
|
||||||
|
function selectCompany(index) {
|
||||||
|
const { coords, zoom, description, id } = companies[index];
|
||||||
|
const [lat, lng] = coords;
|
||||||
|
|
||||||
|
// Remove existing markers
|
||||||
|
markers.forEach(m => m.remove());
|
||||||
|
markers.length = 0;
|
||||||
|
|
||||||
|
// Remove any existing popups
|
||||||
|
document.querySelectorAll('.mapboxgl-popup, .fixed-popup').forEach(el => el.remove());
|
||||||
|
|
||||||
|
// Fly to the new location
|
||||||
|
map.flyTo({
|
||||||
|
center: [lng, lat],
|
||||||
|
zoom,
|
||||||
|
speed: 1.5,
|
||||||
|
essential: true
|
||||||
|
});
|
||||||
|
|
||||||
|
// Update the description blurb
|
||||||
|
document.getElementById('blurb').innerHTML = description;
|
||||||
|
|
||||||
|
// Highlight the active button
|
||||||
|
document.querySelectorAll('.company-list button')
|
||||||
|
.forEach(b => b.classList.toggle('active', b.id === id));
|
||||||
|
|
||||||
|
// If it's the overview, skip marker + popup
|
||||||
|
if (index === 0) return;
|
||||||
|
|
||||||
|
// Add a marker
|
||||||
|
const marker = new mapboxgl.Marker()
|
||||||
|
.setLngLat([lng, lat])
|
||||||
|
.addTo(map);
|
||||||
|
markers.push(marker);
|
||||||
|
|
||||||
|
// Show our custom fixed popup
|
||||||
|
showFixedPopup(companies[index], [lng, lat]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize on load with the overview
|
||||||
|
selectCompany(0);
|
||||||
59
script/scroll.js
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// scroll.js
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// 1) Vertical “zoom‑in/out” on .scroll‑section using IntersectionObserver
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
const sections = document.querySelectorAll('.scroll-section');
|
||||||
|
const io = new IntersectionObserver((entries) => {
|
||||||
|
entries.forEach(entry => {
|
||||||
|
entry.target.classList.toggle('in-view', entry.isIntersecting);
|
||||||
|
});
|
||||||
|
}, { threshold: 0.15 });
|
||||||
|
sections.forEach(sec => io.observe(sec));
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
// 2) Horizontal‑scroll “pin & pan” for the Hobbies section
|
||||||
|
// ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
const wrapper = document.getElementById('hobbies');
|
||||||
|
if (!wrapper) return; // no Hobbies section → exit
|
||||||
|
|
||||||
|
// The element that will stay stuck in the viewport:
|
||||||
|
const stickySection = wrapper.querySelector('.horizontal-section');
|
||||||
|
// The inner flex row we translate left/right:
|
||||||
|
const inner = stickySection.querySelector('.horizontal-section__inner');
|
||||||
|
|
||||||
|
// A) Make the section itself “sticky” at the top of the viewport
|
||||||
|
stickySection.style.position = 'sticky';
|
||||||
|
stickySection.style.top = '3rem';
|
||||||
|
stickySection.style.height = '100vh';
|
||||||
|
stickySection.style.overflow = 'hidden';
|
||||||
|
|
||||||
|
// B) Compute how far we need to scroll to reveal all cards
|
||||||
|
let containerW = wrapper.clientWidth; // e.g. 70vw in px
|
||||||
|
let scrollableDist = inner.scrollWidth - containerW; // total horizontal span minus one screen
|
||||||
|
|
||||||
|
// C) Stretch the wrapper’s vertical height so that
|
||||||
|
// scrolling wrapperHeight(px) → moving inner by scrollableDist(px)
|
||||||
|
wrapper.style.height = `${window.innerHeight + scrollableDist}px`;
|
||||||
|
|
||||||
|
// D) On scroll, when within the wrapper’s “pin zone,”
|
||||||
|
// translate the inner row instead of moving vertically
|
||||||
|
window.addEventListener('scroll', () => {
|
||||||
|
const y = window.scrollY;
|
||||||
|
const top = wrapper.offsetTop;
|
||||||
|
const end = top + scrollableDist;
|
||||||
|
|
||||||
|
if (y >= top && y <= end) {
|
||||||
|
// map vertical scroll → horizontal translate
|
||||||
|
inner.style.transform = `translateX(-${y - top}px)`;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// E) Recompute on resize
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
containerW = wrapper.clientWidth;
|
||||||
|
scrollableDist = inner.scrollWidth - containerW;
|
||||||
|
wrapper.style.height = `${window.innerHeight + scrollableDist}px`;
|
||||||
|
});
|
||||||
|
});
|
||||||
48
style/hobbies.css
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
.hobbies {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh; /* adjust as you like */
|
||||||
|
border-radius: 10px !important; /* ← rounded corners */
|
||||||
|
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Horizontal‑scroll wrapper */
|
||||||
|
.horizontal-section {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Inner scroller — flex row, full viewport height */
|
||||||
|
.horizontal-section__inner {
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 0;
|
||||||
|
display: flex;
|
||||||
|
height: 100vh;
|
||||||
|
will-change: transform;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Each card: same width as the container (70vw), stacked vertically inside */
|
||||||
|
.card {
|
||||||
|
flex: none;
|
||||||
|
width: 100%; /* same as .container width (70vw) */
|
||||||
|
margin-right: 1rem; /* gap between cards */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Image on top */
|
||||||
|
.card img {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
border-radius: 10px;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caption below */
|
||||||
|
.card .caption {
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--fg-one);
|
||||||
|
font-size: 0.95rem;
|
||||||
|
}
|
||||||
22
style/intro.css
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
.intro {
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh; /* adjust as you like */
|
||||||
|
border-radius: 10px !important; /* ← rounded corners */
|
||||||
|
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro h1 {
|
||||||
|
font-size: 7rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro b {
|
||||||
|
font-size: 10rem;
|
||||||
|
font-weight: 800;
|
||||||
|
}
|
||||||
|
|
||||||
|
.intro p {
|
||||||
|
font-size: 3rem;
|
||||||
|
}
|
||||||
155
style/mapbox.css
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
/* map + overlay wrapper */
|
||||||
|
.map-wrapper {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map */
|
||||||
|
.map {
|
||||||
|
width: 100%;
|
||||||
|
height: 70vh; /* adjust as you like */
|
||||||
|
border-radius: 10px !important; /* ← rounded corners */
|
||||||
|
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* removing watermark */
|
||||||
|
.mapboxgl-ctrl-logo { display: none !important; }
|
||||||
|
|
||||||
|
/* Company list */
|
||||||
|
.company-list {
|
||||||
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
left: 1rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
max-height: 50vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
z-index: 1;
|
||||||
|
color: var(--fg-one);
|
||||||
|
|
||||||
|
background: rgba(0, 0, 0, 0.1) !important;
|
||||||
|
backdrop-filter: blur(4px);
|
||||||
|
border-radius: 10px !important; /* ← rounded corners */
|
||||||
|
filter: drop-shadow(0 0 1px gray) !important; /* <- gives a border */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* company list button*/
|
||||||
|
.company-list button {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.5rem;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
background: none;
|
||||||
|
border-radius: 10px; /* ← rounded corners */
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-list button:hover {
|
||||||
|
background: rgb(255, 255, 255, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.company-list button + button {
|
||||||
|
margin-top: 0.5rem; /* Only applies if there's a previous button */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pressed company list button */
|
||||||
|
|
||||||
|
.company-list button.active {
|
||||||
|
background: rgb(255, 255, 255, 0.2);
|
||||||
|
filter: drop-shadow(0 0 2px gray) !important; /* <- gives a border */
|
||||||
|
color: var(--fg-one);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* popup */
|
||||||
|
.mapboxgl-popup {
|
||||||
|
position: absolute !important;
|
||||||
|
transform: none !important; /* cancel out Mapbox’s translate() */
|
||||||
|
|
||||||
|
overflow-y: auto;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
top: 1rem !important;
|
||||||
|
left: auto !important;
|
||||||
|
right: 1rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* popup bg */
|
||||||
|
.mapboxgl-popup-content {
|
||||||
|
background: rgba(0, 0, 0, 0.1) !important;
|
||||||
|
-webkit-backdrop-filter: blur(4px) !important;
|
||||||
|
backdrop-filter: blur(4px) !important;
|
||||||
|
border-radius: 10px !important; /* ← rounded corners */
|
||||||
|
filter: drop-shadow(0 0 1px gray) !important; /* <- gives a border */
|
||||||
|
|
||||||
|
color: var(--bg-one);
|
||||||
|
padding-bottom: 5px; /* or else its too big */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* popup image */
|
||||||
|
.mapboxgl-popup-content img {
|
||||||
|
border-radius: 5px !important; /* ← rounded corners */
|
||||||
|
filter: drop-shadow(0 0 1px gray) !important; /* <- gives a border */
|
||||||
|
|
||||||
|
width: 100%; /* fill the popup’s width */
|
||||||
|
max-width: none; /* ignore any mapbox defaults */
|
||||||
|
height: auto; /* maintain aspect ratio */
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hide the popup tip/arrow */
|
||||||
|
.mapboxgl-popup-tip {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caption */
|
||||||
|
.blurb {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
|
||||||
|
background: var(--bg-two);
|
||||||
|
color: var(--fg-one);
|
||||||
|
|
||||||
|
border-radius: 10px;
|
||||||
|
min-height: 8rem; /* optional */
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||||
|
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* blurb title */
|
||||||
|
.blurb h2 {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fixed popup that won’t move with the map */
|
||||||
|
.fixed-popup {
|
||||||
|
position: absolute !important;
|
||||||
|
transform: none !important; /* cancel out Mapbox’s translate() */
|
||||||
|
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
top: 1rem !important;
|
||||||
|
right: -1rem !important;
|
||||||
|
|
||||||
|
background: rgba(0, 0, 0, 0.1) !important;
|
||||||
|
-webkit-backdrop-filter: blur(4px) !important;
|
||||||
|
backdrop-filter: blur(4px) !important;
|
||||||
|
border-radius: 10px !important; /* ← rounded corners */
|
||||||
|
filter: drop-shadow(0 0 1px gray) !important; /* <- gives a border */
|
||||||
|
|
||||||
|
color: var(--bg-one);
|
||||||
|
|
||||||
|
padding: 0.75rem;
|
||||||
|
border-radius: 6px;
|
||||||
|
max-width: 200px;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fixed-popup img {
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
8
style/projects.css
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.projects {
|
||||||
|
width: 100%;
|
||||||
|
height: 50vh; /* adjust as you like */
|
||||||
|
border-radius: 10px !important; /* ← rounded corners */
|
||||||
|
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
52
style/style.css
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/* styles.css
|
||||||
|
* Global Color Theme
|
||||||
|
* ex: ` color: var(--red);`
|
||||||
|
*/
|
||||||
|
:root {
|
||||||
|
--bg-one: #111111; /* black */
|
||||||
|
--bg-two: #303030; /* gray */
|
||||||
|
|
||||||
|
--fg-one: #ffffff; /* white */
|
||||||
|
--fg-two: #f3f3f3; /* light gray */
|
||||||
|
|
||||||
|
--blue: #1e90ff;
|
||||||
|
--red: #e63946;
|
||||||
|
--green: #2a9d8f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* General Site */
|
||||||
|
html, body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
background-color: var(--bg-one);
|
||||||
|
color: var(--fg-one);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* container centered at 85% width */
|
||||||
|
.container {
|
||||||
|
width: 70vw;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
font-size: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* scroll.js */
|
||||||
|
/* base state: slightly shrunken + faded out */
|
||||||
|
.scroll-section {
|
||||||
|
transform: scale(0.85);
|
||||||
|
opacity: 0.5;
|
||||||
|
transition:
|
||||||
|
transform 0.6s cubic-bezier(.22,.61,.36,1),
|
||||||
|
opacity 0.6s cubic-bezier(.22,.61,.36,1);
|
||||||
|
transform-origin: center center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* when in view: full size + fully opaque */
|
||||||
|
.scroll-section.in-view {
|
||||||
|
transform: scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
8
style/thanks.css
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.thanks {
|
||||||
|
width: 100%;
|
||||||
|
height: 50vh; /* adjust as you like */
|
||||||
|
border-radius: 10px !important; /* ← rounded corners */
|
||||||
|
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||