change to netlify

This commit is contained in:
adeliptr 2025-06-10 20:50:41 +09:00
parent 456591043e
commit c91da2cf8e
10 changed files with 91 additions and 933 deletions

832
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@
},
"devDependencies": {
"@sveltejs/adapter-auto": "^6.0.0",
"@sveltejs/adapter-vercel": "^5.7.2",
"@sveltejs/adapter-netlify": "^5.0.2",
"@sveltejs/kit": "^2.16.0",
"@sveltejs/vite-plugin-svelte": "^5.0.0",
"@types/d3": "^7.4.3",

View File

@ -1,6 +1,7 @@
<script lang="ts">
export let showPopup = false;
export let destination = '';
export let mode = 'Trip to';
export let onConfirm: () => void;
export let onCancel: () => void;
export let darkMode = false;
@ -15,7 +16,7 @@
<div class="overlay" role="button" tabindex="0">
<div class="popup" class:dark-mode={darkMode} role="button" tabindex="0" onclick={handlePopupClick}>
<h2>Delete Trip</h2>
<p>Are you sure you want to delete Trip to {destination}?</p>
<p>Are you sure you want to delete {mode} {destination}?</p>
<div class="button-group">
<button class="cancel-btn" onclick={onCancel}>Cancel</button>
<button class="delete-btn" onclick={onConfirm}>Yes, delete</button>
@ -95,7 +96,7 @@
color: var(--white);
}
.popup.darkdark-mode h2 {
.popup.dark-mode h2 {
color: var(--memory-400);
}

View File

@ -1,79 +0,0 @@
<script lang="ts">
import { goto } from '$app/navigation';
export let destination = '';
export let startDate = '';
export let endDate = '';
export let image = '';
export let tid = '';
export let memoryId = '';
function handleClick() {
goto(`/viewimage/${tid}/${memoryId}`);
}
</script>
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
class="memory-card"
role="button"
tabindex="0"
onclick={handleClick}
>
<div class="image" style="background-image: url({image || ''})">
{#if !image}
<div class="placeholder">
<i class="fa-solid fa-image" style="color: var(--gray-400)"></i>
</div>
{/if}
</div>
<div class="info">
<h3>{destination}</h3>
<p class="date">{startDate} - {endDate}</p>
</div>
</div>
<style>
.memory-card {
background: var(--black);
border-radius: 12px;
overflow: hidden;
box-shadow: 0 2px 4px rgba(200, 200, 200, 0.2);
transition: transform 0.2s ease, box-shadow 0.2s ease;
cursor: pointer;
font-family: 'Inter', sans-serif;
position: relative;
}
.memory-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(200, 200, 200, 0.2);
}
.image {
height: 160px;
background-size: cover;
background-position: center;
background-color: var(--gray-100);
position: relative;
}
.placeholder {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 2rem;
}
.info {
padding: 1rem;
}
.info h3 {
margin: 0;
font-size: 1.2rem;
font-weight: 600;
color: var(--white);
}
.date {
margin: 0.25rem 0 0 0;
font-size: 0.8rem;
color: var(--gray-200);
}
</style>

View File

@ -80,7 +80,7 @@
destination={trip.destination.name}
startDate={new Date(trip.startDate).toLocaleDateString('en-GB', { day: '2-digit', month: '2-digit', year: 'numeric' })}
endDate={new Date(trip.endDate).toLocaleDateString('en-GB', { day: '2-digit', month: '2-digit', year: 'numeric' })}
image={trip.destination.photo}
image={trip._cardImage}
tid={trip.tid}
/>
{/each}

View File

@ -10,12 +10,18 @@
export let endDate = '';
export let image = '';
export let tid = '';
export let memoryId: string = '';
export let variant: 'trip' | 'memory' = 'trip';
let showDelete = false;
let showDeleteConfirmation = false;
function handleClick() {
goto(`/itinerary/${tid}`);
if (variant === 'memory') {
goto(`/viewimage/${tid}/${memoryId}`);
} else {
goto(`/itinerary/${tid}`);
}
}
function handleMouseEnter() {
@ -41,6 +47,16 @@
}
}
async function handleConfirmDeleteMemory() {
try {
const memoryRef = ref(db, `trips/${tid}/memories/${memoryId}`);
await remove(memoryRef);
showDeleteConfirmation = false;
} catch (error) {
console.error('Error deleting memory:', error);
}
}
function handleCancelDelete() {
showDeleteConfirmation = false;
}
@ -48,7 +64,8 @@
<!-- svelte-ignore a11y_click_events_have_key_events -->
<div
class="trip-card"
class:trip-card={variant === 'trip'}
class:memory-card={variant === 'memory'}
role="button"
tabindex="0"
onmouseenter={handleMouseEnter}
@ -74,17 +91,21 @@
{/if}
</div>
<div class="info">
<h3>{destination}</h3>
<p class="date">{startDate} - {endDate}</p>
<h3 class:dark={variant === 'memory'}>{destination}</h3>
<p class="date" class:dark={variant === 'memory'}>{startDate} - {endDate}</p>
</div>
</div>
<DeleteConfirmationPopup
showPopup={showDeleteConfirmation}
{destination}
onConfirm={handleConfirmDelete}
onCancel={handleCancelDelete}
/>
{#if showDeleteConfirmation}
<DeleteConfirmationPopup
showPopup={showDeleteConfirmation}
destination={variant === 'trip' ? destination : destination}
mode={variant === 'trip' ? 'Trip to' : 'Memory in'}
onConfirm={variant === 'trip' ? handleConfirmDelete : handleConfirmDeleteMemory}
onCancel={handleCancelDelete}
darkMode={variant === 'memory'}
/>
{/if}
<style>
.trip-card {
@ -97,12 +118,24 @@
font-family: 'Inter', sans-serif;
position: relative;
}
.trip-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.memory-card {
background: var(--black);
border-radius: 12px;
overflow: hidden;
box-shadow: 0 2px 4px rgba(200, 200, 200, 0.2);
transition: transform 0.2s ease, box-shadow 0.2s ease;
cursor: pointer;
font-family: 'Inter', sans-serif;
position: relative;
}
.memory-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(200, 200, 200, 0.2);
}
.image {
height: 160px;
background-size: cover;
@ -110,7 +143,6 @@
background-color: var(--gray-100);
position: relative;
}
.placeholder {
height: 100%;
display: flex;
@ -118,23 +150,26 @@
justify-content: center;
font-size: 2rem;
}
.info {
padding: 1rem;
}
.info h3 {
margin: 0;
font-size: 1.2rem;
font-weight: 600;
color: var(--gray-900);
}
.info h3.dark {
color: var(--white);
}
.date {
margin: 0.25rem 0 0 0;
font-size: 0.8rem;
color: var(--gray-400);
}
.date.dark {
color: var(--gray-200);
}
.delete-btn {
position: absolute;
top: 0.75rem;
@ -151,7 +186,6 @@
color: var(--gray-600);
transition: all 0.2s ease;
}
.delete-btn:hover {
background-color: var(--memory-50);
color: var(--memory-600);

View File

@ -74,10 +74,24 @@
// Filter past trips for this destination
pastTripsData = Object.entries(snapshot.val())
.map(([tripId, data]) => ({
tid: tripId,
...data as any
}))
.map(([tripId, data]: [string, any]) => {
// Find first memory image if exists
let cardImage = data.destination?.photo;
if (data.memories && typeof data.memories === 'object') {
const memoryIds = Object.keys(data.memories);
if (memoryIds.length > 0) {
const firstMemory = data.memories[memoryIds[0]];
if (firstMemory.images && firstMemory.images.length > 0) {
cardImage = firstMemory.images[0];
}
}
}
return {
tid: tripId,
...data,
_cardImage: cardImage
};
})
.filter(trip => {
const endDate = new Date(trip.endDate);
return trip.tid !== tid && // not current trip

View File

@ -1,6 +1,6 @@
<script lang="ts">
import '../../app.css';
import MemoryCard from '$lib/components/MemoryCard.svelte';
import TripCard from '$lib/components/TripCard.svelte';
import Button from '$lib/components/Button.svelte';
import NewMemoryPopup from '$lib/components/NewMemoryPopup.svelte';
import Nav from '$lib/components/Nav.svelte';
@ -76,7 +76,7 @@
{:else}
<div class="memories-grid">
{#each pastMemories as memory}
<MemoryCard {...memory} on:deleted={(e) => handleDeletedMemory(e.detail.memoryId)} />
<TripCard {...memory} variant="memory" memoryId={memory.memoryId} />
{/each}
</div>
{/if}

View File

@ -64,7 +64,6 @@ Example format:
}
`;
console.log(`prompt: ${prompt}`);
try {
const response = await openai.chat.completions.create({
model: 'gpt-4.1-mini',
@ -82,15 +81,11 @@ Example format:
response_format: { type: "json_object" }
});
console.log(response);
const content = response.choices[0]?.message?.content;
if (!content) {
throw new Error('No recommendations received');
}
console.log(`content: ${content}`);
const parsedContent = JSON.parse(content);
return parsedContent.recommendations || [];
} catch (error) {
@ -128,7 +123,6 @@ Please distribute these places into a daily itinerary following these rules:
- Each place should be assigned to exactly one day
The response should be ONLY the JSON object, nothing else.`;
console.log(`prompt: ${prompt}`);
try {
const response = await openai.chat.completions.create({

View File

@ -1,4 +1,4 @@
import adapter from '@sveltejs/adapter-vercel';
import adapter from '@sveltejs/adapter-netlify';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';