Skip to content
Closed
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
2 changes: 1 addition & 1 deletion docs/database-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ themselves are plain files on disk, not stored in the database. Sprites already
on disk are not downloaded again.

Locally they go to `backend/sprites/` (gitignored), and the Vite development
server serves that folder at `/project2/sprites/` (see `frontend/vite.config.ts`), so no
server serves that folder at `/sprites/` (see `frontend/vite.config.ts`), so no
extra web server is needed during development. On the VM, the project is served
by Apache under `/project2`, so set `SPRITES_DIR` in `backend/.env` to a folder
inside Apache's document root:
Expand Down
6 changes: 4 additions & 2 deletions frontend/.env.example
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# Optional: base URL for sprites. Defaults to sprites/ under Vite's base path.
# VITE_SPRITES_BASE_URL=/project2/sprites/
# Base URL used by Pokémon cards to load sprites.
# In development Vite serves backend/sprites/ at /sprites/ (see vite.config.ts).
# When building for the Apache deployment, set VITE_SPRITES_BASE_URL=/project2/sprites/
VITE_SPRITES_BASE_URL=/sprites/
10 changes: 4 additions & 6 deletions frontend/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,10 @@ The backend currently provides queries for retrieving a list of Pokémon and an

## Sprites

Pokémon cards load sprites from `sprites/` under the app's base path (Vite's
`base`), so the URL follows wherever the frontend is served, e.g.
`/project2/sprites/` on the VM. In development the Vite server serves
`backend/sprites/` at `/project2/sprites/`, so no extra configuration is needed after
running the backend import. Set `VITE_SPRITES_BASE_URL` only to load sprites
from somewhere else.
Pokémon cards load sprites from `VITE_SPRITES_BASE_URL` (default `/sprites/`).
In development the Vite server serves `backend/sprites/` at `/sprites/`, so no
extra configuration is needed after running the backend import. When building
for the Apache deployment, set `VITE_SPRITES_BASE_URL=/project2/sprites/`.

## Current Functionality

Expand Down
176 changes: 160 additions & 16 deletions frontend/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
max-width: 1024px;
}

/* Header */

.top-bar {
display: grid;
grid-template-columns: 1fr auto 1fr;
Expand Down Expand Up @@ -51,7 +53,13 @@
gap: 0.75rem;
}

/* Search button */

.search-button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.45rem;
background-color: var(--accent);
color: aliceblue;
border: 0;
Expand All @@ -62,6 +70,12 @@
transition: filter 0.2s ease, transform 0.1s ease;
}

.search-button-icon {
display: none;
width: 1.15rem;
height: 1.15rem;
}

.search-button:hover {
filter: brightness(1.1);
}
Expand All @@ -70,6 +84,8 @@
transform: scale(0.98);
}

/* Account button */

.account-button {
display: inline-block;
padding: 0.6rem 1.2rem;
Expand All @@ -87,13 +103,22 @@
color: white;
}

/* Accessibility */

.account-button:focus-visible,
.search-button:focus-visible,
.hamburger:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
}

/* Navigation */

.sidebar-header,
.menu-backdrop {
display: none;
}

.nav-links {
list-style: none;
display: flex;
Expand Down Expand Up @@ -150,9 +175,12 @@

.main-content {
flex: 1;
min-width: 0;
background-color: var(--bg);
}

/* Format selector */

#formats {
background-color: var(--code-bg);
color: var(--text);
Expand All @@ -171,6 +199,8 @@
border-color: var(--accent);
}

/* Add Pokémon button */

.addPokemon {
background-color: var(--accent);
color: aliceblue;
Expand All @@ -191,17 +221,25 @@
transform: scale(0.98);
}

/* Mobile layout */

@media (max-width: 768px) {
.top-bar {
grid-template-columns: 1fr auto 1fr;
padding: 1rem;
gap: 0.5rem;
padding: 0.6rem 1rem;
gap: 0.6rem;
min-height: 3.75rem;
}

.top-bar h1 {
font-size: 1.25rem;
min-width: 0;
margin: 0;
font-size: 1rem;
letter-spacing: 0;
white-space: normal;
line-height: 1.2;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}

.user-profile {
Expand All @@ -219,7 +257,27 @@
}

.search-button {
padding: 0.5rem 0.9rem;
flex: 0 0 auto;
width: 2.75rem;
height: 2.75rem;
padding: 0;
border-radius: 50%;
}

.search-button-icon {
display: block;
}

.search-button-label {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0 0 0 0);
white-space: nowrap;
border: 0;
}

.header-actions {
Expand All @@ -231,6 +289,8 @@
font-size: 0.85rem;
}

/* Hamburger menu */

.hamburger {
display: flex;
flex-direction: column;
Expand All @@ -243,24 +303,108 @@
left: 0;
}

.hamburger .hamburger-line {
width: 22px;
height: 2px;
background-color: var(--text-h);
}

/* Menu backdrop */

.menu-backdrop {
display: block;
position: fixed;
inset: 0;
z-index: 150;
padding: 0;
border: 0;
background: rgb(0 0 0 / 40%);
opacity: 0;
pointer-events: none;
transition: opacity 0.2s ease;
}

.menu-backdrop.active {
opacity: 1;
pointer-events: auto;
}

/* Sliding sidebar */

.sidebar {
display: none;
position: absolute;
display: block;
position: fixed;
top: 0;
left: 0;
width: 100vw;
background-color: var(--code-bg);
border-right: none;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
z-index: 100;
padding: 1rem 0;
bottom: 0;
z-index: 200;
width: min(82vw, 20rem);
height: 100dvh;
padding: 1.1rem 1.25rem;
box-sizing: border-box;
overflow-y: auto;
background-color: var(--bg);
border-right: 1px solid var(--border);
box-shadow: 0 10px 30px rgb(0 0 0 / 25%);
transform: translateX(-105%);
visibility: hidden;
transition: transform 0.2s ease, visibility 0.2s ease;
}

.sidebar.active {
display: block;
transform: translateX(0);
visibility: visible;
}

.nav-links.active {
.sidebar-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 0.75rem;
margin-bottom: 1.25rem;
padding-bottom: 0.75rem;
border-bottom: 1px solid var(--border);
}

.sidebar-title {
color: var(--text-h);
font-size: 0.95rem;
font-weight: 600;
text-align: left;
}
}

.sidebar-close {
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
width: 2.5rem;
height: 2.5rem;
padding: 0;
border: 0;
border-radius: 50%;
background: var(--code-bg);
color: var(--text-h);
cursor: pointer;
}

.sidebar-close-icon {
width: 1.1rem;
height: 1.1rem;
}

.sidebar .nav-links {
gap: 0;
}

.sidebar .nav-links li {
border-bottom: 1px solid var(--border);
}

.sidebar .nav-links a {
display: block;
padding: 0.9rem 0.25rem;
font-size: 1.05rem;
text-align: left;
}
}
Loading