NewMemoryPopup with problems

This commit is contained in:
Chaebean Yang 2025-06-06 18:58:10 +09:00
parent 7b0740fe0a
commit bd6b405478
4 changed files with 205 additions and 181 deletions

52
package-lock.json generated
View File

@ -10,7 +10,7 @@
"dependencies": { "dependencies": {
"@googlemaps/js-api-loader": "^1.16.8", "@googlemaps/js-api-loader": "^1.16.8",
"d3": "^7.9.0", "d3": "^7.9.0",
"firebase": "^11.8.1", "firebase": "^11.9.0",
"topojson-client": "^3.1.0", "topojson-client": "^3.1.0",
"topojson-server": "^3.0.1" "topojson-server": "^3.0.1"
}, },
@ -469,9 +469,9 @@
} }
}, },
"node_modules/@firebase/ai": { "node_modules/@firebase/ai": {
"version": "1.3.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/@firebase/ai/-/ai-1.3.0.tgz", "resolved": "https://registry.npmjs.org/@firebase/ai/-/ai-1.4.0.tgz",
"integrity": "sha512-qBxJTtl9hpgZr050kVFTRADX6I0Ss6mEQyp/JEkBgKwwxixKnaRNqEDGFba4OKNL7K8E4Y7LlA/ZW6L8aCKH4A==", "integrity": "sha512-wvF33gtU6TXb6Co8TEC1pcl4dnVstYmRE/vs9XjUGE7he7Sgf5TqSu+EoXk/fuzhw5tKr1LC5eG9KdYFM+eosw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@firebase/app-check-interop-types": "0.3.3", "@firebase/app-check-interop-types": "0.3.3",
@ -527,9 +527,9 @@
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/@firebase/app": { "node_modules/@firebase/app": {
"version": "0.13.0", "version": "0.13.1",
"resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.13.0.tgz", "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.13.1.tgz",
"integrity": "sha512-Vj3MST245nq+V5UmmfEkB3isIgPouyUr8yGJlFeL9Trg/umG5ogAvrjAYvQ8gV7daKDoQSRnJKWI2JFpQqRsuQ==", "integrity": "sha512-0O33PKrXLoIWkoOO5ByFaLjZehBctSYWnb+xJkIdx2SKP/K9l1UPFXPwASyrOIqyY3ws+7orF/1j7wI5EKzPYQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@firebase/component": "0.6.17", "@firebase/component": "0.6.17",
@ -593,12 +593,12 @@
"license": "Apache-2.0" "license": "Apache-2.0"
}, },
"node_modules/@firebase/app-compat": { "node_modules/@firebase/app-compat": {
"version": "0.4.0", "version": "0.4.1",
"resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.4.0.tgz", "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.4.1.tgz",
"integrity": "sha512-LjLUrzbUgTa/sCtPoLKT2C7KShvLVHS3crnU1Du02YxnGVLE0CUBGY/NxgfR/Zg84mEbj1q08/dgesojxjn0dA==", "integrity": "sha512-9VGjnY23Gc1XryoF/ABWtZVJYnaPOnjHM7dsqq9YALgKRtxI1FryvELUVkDaEIUf4In2bfkb9ZENF1S9M273Dw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@firebase/app": "0.13.0", "@firebase/app": "0.13.1",
"@firebase/component": "0.6.17", "@firebase/component": "0.6.17",
"@firebase/logger": "0.4.4", "@firebase/logger": "0.4.4",
"@firebase/util": "1.12.0", "@firebase/util": "1.12.0",
@ -748,9 +748,9 @@
} }
}, },
"node_modules/@firebase/firestore": { "node_modules/@firebase/firestore": {
"version": "4.7.16", "version": "4.7.17",
"resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.16.tgz", "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.17.tgz",
"integrity": "sha512-5OpvlwYVUTLEnqewOlXmtIpH8t2ISlZHDW0NDbKROM2D0ATMqFkMHdvl+/wz9zOAcb8GMQYlhCihOnVAliUbpQ==", "integrity": "sha512-YhXWA7HlSnekExhZ5u4i0e+kpPxsh/qMrzeNDgsAva71JXK8OOuOx+yLyYBFhmu3Hr5JJDO2fsZA/wrWoQYHDg==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@firebase/component": "0.6.17", "@firebase/component": "0.6.17",
@ -769,13 +769,13 @@
} }
}, },
"node_modules/@firebase/firestore-compat": { "node_modules/@firebase/firestore-compat": {
"version": "0.3.51", "version": "0.3.52",
"resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.51.tgz", "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.52.tgz",
"integrity": "sha512-E5iubPhS6aAM7oSsHMx/FGBwfA2nbEHaK/hCs+MD3l3N7rHKnq4SYCGmVu/AraSJaMndZR1I37N9A/BH7aCq5A==", "integrity": "sha512-nzt3Sag+EBdm1Jkw/FnnKBPk0LpUUxOlMHMADPBXYhhXrLszxn1+vb64nJsbgRIHfsCn+rg8gyGrb+8frzXrjg==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@firebase/component": "0.6.17", "@firebase/component": "0.6.17",
"@firebase/firestore": "4.7.16", "@firebase/firestore": "4.7.17",
"@firebase/firestore-types": "3.0.3", "@firebase/firestore-types": "3.0.3",
"@firebase/util": "1.12.0", "@firebase/util": "1.12.0",
"tslib": "^2.1.0" "tslib": "^2.1.0"
@ -2733,26 +2733,26 @@
} }
}, },
"node_modules/firebase": { "node_modules/firebase": {
"version": "11.8.1", "version": "11.9.0",
"resolved": "https://registry.npmjs.org/firebase/-/firebase-11.8.1.tgz", "resolved": "https://registry.npmjs.org/firebase/-/firebase-11.9.0.tgz",
"integrity": "sha512-oetXhPCvJZM4DVL/n/06442emMU+KzM0JLZjszpwlU6mqdFZqBwumBxn6hQkLukJyU5wsjihZHUY8HEAE2micg==", "integrity": "sha512-7uIGhxKtTNfDcoMKWn0G8G0Z1Zj5VeW8uzImAcUmI31PaYQdVWi2rVVig7thWB3vPianESPrLEKim2Fw7U8fiA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@firebase/ai": "1.3.0", "@firebase/ai": "1.4.0",
"@firebase/analytics": "0.10.16", "@firebase/analytics": "0.10.16",
"@firebase/analytics-compat": "0.2.22", "@firebase/analytics-compat": "0.2.22",
"@firebase/app": "0.13.0", "@firebase/app": "0.13.1",
"@firebase/app-check": "0.10.0", "@firebase/app-check": "0.10.0",
"@firebase/app-check-compat": "0.3.25", "@firebase/app-check-compat": "0.3.25",
"@firebase/app-compat": "0.4.0", "@firebase/app-compat": "0.4.1",
"@firebase/app-types": "0.9.3", "@firebase/app-types": "0.9.3",
"@firebase/auth": "1.10.6", "@firebase/auth": "1.10.6",
"@firebase/auth-compat": "0.5.26", "@firebase/auth-compat": "0.5.26",
"@firebase/data-connect": "0.3.9", "@firebase/data-connect": "0.3.9",
"@firebase/database": "1.0.19", "@firebase/database": "1.0.19",
"@firebase/database-compat": "2.0.10", "@firebase/database-compat": "2.0.10",
"@firebase/firestore": "4.7.16", "@firebase/firestore": "4.7.17",
"@firebase/firestore-compat": "0.3.51", "@firebase/firestore-compat": "0.3.52",
"@firebase/functions": "0.12.8", "@firebase/functions": "0.12.8",
"@firebase/functions-compat": "0.3.25", "@firebase/functions-compat": "0.3.25",
"@firebase/installations": "0.6.17", "@firebase/installations": "0.6.17",

View File

@ -28,7 +28,7 @@
"dependencies": { "dependencies": {
"@googlemaps/js-api-loader": "^1.16.8", "@googlemaps/js-api-loader": "^1.16.8",
"d3": "^7.9.0", "d3": "^7.9.0",
"firebase": "^11.8.1", "firebase": "^11.9.0",
"topojson-client": "^3.1.0", "topojson-client": "^3.1.0",
"topojson-server": "^3.0.1" "topojson-server": "^3.0.1"
} }

View File

@ -1,32 +1,24 @@
<script lang="ts"> <script lang="ts">
import '../../app.css'; import '../../app.css';
import Button from './Button.svelte'; import Button from '$lib/components/Button.svelte';
import { goto } from '$app/navigation';
import { onMount } from 'svelte'; import { onMount } from 'svelte';
import { Loader } from '@googlemaps/js-api-loader'; import { Loader } from '@googlemaps/js-api-loader';
import { goto } from '$app/navigation'; import { collection, addDoc, getFirestore, Timestamp } from 'firebase/firestore';
import { app } from '$lib/firebase';
export let showPopup = false; export let showPopup = false;
<<<<<<< HEAD
export let onAddMemory = () => {}; export let onAddMemory = () => {};
=======
export let locations: any[] = [];
export let onAddMemory = (p0?: { location: string; images: any[]; startDate: string; endDate: string; }) => {};
>>>>>>> 9def1973a7b39a01052b5d81f6a5327e2524e7e1
export let onCancel = () => {}; export let onCancel = () => {};
let startDate = ""; let startDate = '';
let endDate = ""; let endDate = '';
let isGoogleLoaded = false; let isGoogleLoaded = false;
let dragActive = false; let dragActive = false;
let selectedLocation = ''; let selectedLocation = '';
let customLocation = ''; let customLocation = '';
<<<<<<< HEAD
let customLocationInput: HTMLInputElement; let customLocationInput: HTMLInputElement;
let images = []; let images: File[] = [];
=======
let images: any[] = [];
let dragActive = false;
>>>>>>> 9def1973a7b39a01052b5d81f6a5327e2524e7e1
let showLocationError = false; let showLocationError = false;
let showImageError = false; let showImageError = false;
@ -34,20 +26,17 @@
const GOOGLE_PLACES_API_KEY = import.meta.env.VITE_GOOGLE_PLACES_API_KEY; const GOOGLE_PLACES_API_KEY = import.meta.env.VITE_GOOGLE_PLACES_API_KEY;
onMount(async () => { onMount(async () => {
if (!GOOGLE_PLACES_API_KEY) { if (!GOOGLE_PLACES_API_KEY) return;
console.error('Google Maps API key is missing');
return;
}
const loader = new Loader({ const loader = new Loader({
apiKey: GOOGLE_PLACES_API_KEY, apiKey: GOOGLE_PLACES_API_KEY,
version: "weekly", version: 'weekly',
libraries: ["places"], libraries: ['places'],
language: 'en' language: 'en'
}); });
try { try {
await loader.importLibrary("places"); await loader.importLibrary('places');
isGoogleLoaded = true; isGoogleLoaded = true;
} catch (error) { } catch (error) {
console.error('Error loading Places Autocomplete:', error); console.error('Error loading Places Autocomplete:', error);
@ -59,8 +48,7 @@
types: ['(regions)'] types: ['(regions)']
}); });
autocompleteCustom.setFields(['name', 'formatted_address']); autocompleteCustom.setFields(['name']);
autocompleteCustom.addListener('place_changed', () => { autocompleteCustom.addListener('place_changed', () => {
const place = autocompleteCustom.getPlace(); const place = autocompleteCustom.getPlace();
if (place.name) { if (place.name) {
@ -70,7 +58,7 @@
}); });
} }
function handleFiles(files: any) { function handleFiles(files: FileList) {
for (const file of files) { for (const file of files) {
if (file.type.startsWith('image/')) { if (file.type.startsWith('image/')) {
images = [...images, file]; images = [...images, file];
@ -78,31 +66,56 @@
} }
} }
function handleDrop(event: any) { function handleDrop(event: DragEvent) {
event.preventDefault(); event.preventDefault();
dragActive = false; dragActive = false;
handleFiles(event.dataTransfer.files); handleFiles(event.dataTransfer!.files);
} }
function handleDragOver(event: any) { function handleDragOver(event: DragEvent) {
event.preventDefault(); event.preventDefault();
dragActive = true; dragActive = true;
} }
function handleDragLeave(event: any) { function handleDragLeave(event: DragEvent) {
event.preventDefault(); event.preventDefault();
dragActive = false; dragActive = false;
} }
function handleInputChange(event: any) { function handleInputChange(event: Event) {
if (event.target.files) { const target = event.target as HTMLInputElement;
handleFiles(event.target.files); if (target.files) {
handleFiles(target.files);
} }
} }
function handleCancelClick() { function isCustomLocation() {
onCancel(); return selectedLocation === 'custom';
}
function removeImage(imageToRemove: File) {
images = images.filter(img => img !== imageToRemove);
}
async function handleAddMemory() {
showLocationError = selectedLocation === '' || (isCustomLocation() && customLocation.trim() === '');
showImageError = images.length === 0;
if (showLocationError || showImageError) return;
const finalLocation = isCustomLocation() ? customLocation : selectedLocation;
const db = getFirestore(app);
const docRef = await addDoc(collection(db, 'memories'), {
location: finalLocation,
startDate,
endDate,
images: images.map(file => URL.createObjectURL(file)), // 임시 처리. 실제 서비스에서는 Storage URL 써야 함
createdAt: Timestamp.now()
});
reset(); reset();
goto(`/viewimage?id=${docRef.id}`);
} }
function reset() { function reset() {
@ -116,44 +129,9 @@
showImageError = false; showImageError = false;
} }
function isCustomLocation() {
return selectedLocation === 'custom';
}
function removeImage(imageToRemove: File) {
images = images.filter(img => img !== imageToRemove);
}
function handleAddMemory() {
showLocationError = selectedLocation === '' || (selectedLocation === 'custom' && customLocation.trim() === '');
showImageError = images.length === 0;
if (showLocationError || showImageError) return;
const finalLocation = selectedLocation === 'custom' ? customLocation : selectedLocation;
const memory = {
location: finalLocation,
images,
startDate,
endDate
};
// link data later...
const params = new URLSearchParams({
location: finalLocation,
startDate,
endDate
});
goto(`/viewimage?${params.toString()}`);
reset();
}
// needs to link with plan data set
const locations = ['Paris', 'Tokyo', 'New York']; const locations = ['Paris', 'Tokyo', 'New York'];
</script> </script>
{#if showPopup} {#if showPopup}
<div class="overlay"> <div class="overlay">

View File

@ -1,43 +1,89 @@
<script> <script>
import { page } from '$app/stores'; import '../../app.css';
import { onMount } from 'svelte'; import Button from '$lib/components/Button.svelte';
import Nav from '$lib/components/Nav.svelte';
import { currentMemory } from '$lib/stores/memory';
import { get } from 'svelte/store';
let location = ''; let memory = get(currentMemory);
let startDate = '';
let endDate = '';
$: { // 메인 이미지
const q = $page.url.searchParams; let mainImageUrl = memory?.images?.[0]
location = q.get('location') ?? ''; ? typeof memory.images[0] === 'string'
startDate = q.get('startDate') ?? ''; ? memory.images[0]
endDate = q.get('endDate') ?? ''; : URL.createObjectURL(memory.images[0])
} : '';
// 컬럼별 대표 색 (예시용)
let gradientColors = ['#e74c3c', '#f1c40f', '#2ecc71', '#3498db', '#9b59b6']; let gradientColors = ['#e74c3c', '#f1c40f', '#2ecc71', '#3498db', '#9b59b6'];
$: gradientStyle = `conic-gradient(${[...gradientColors, gradientColors[0]].join(', ')})`; $: gradientStyle = `conic-gradient(${[...gradientColors, gradientColors[0]].join(', ')})`;
</script> </script>
<div class="memory-view"> <main>
<h2>{location}</h2> <Nav activeTab="Memory" />
<p>{startDate} - {endDate}</p>
<div class="gradient-wheel" style="background-image: {gradientStyle};"></div> <div class="content">
</div> <div class="header">
<h1>Memory View</h1>
</div>
{#if memory}
<div class="memory-container">
<h2>{memory.location}</h2>
<p>{memory.startDate} - {memory.endDate}</p>
<div class="visual-section">
<!-- 🎨 gradient wheel -->
<div
class="gradient-wheel"
style="background-image: {gradientStyle}; width: 300px; height: 300px"
></div>
<!-- 📸 main image -->
<img
class="main-image"
src={mainImageUrl}
alt="Main Memory Image"
/>
</div>
</div>
{:else}
<p>Memory not loaded.</p>
{/if}
</div>
</main>
<style> <style>
.memory-view { .content {
padding: 2rem; padding: 2rem;
font-family: sans-serif; }
.header {
margin-bottom: 2rem;
}
.memory-container {
text-align: center; text-align: center;
} }
.visual-section {
margin-top: 2rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 2rem;
}
.gradient-wheel { .gradient-wheel {
width: 300px;
height: 300px;
margin: 2rem auto;
border-radius: 50%; border-radius: 50%;
background: var(--gradient); box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
box-shadow: 0 0 20px rgba(0, 0, 0, 0.3); }
.main-image {
width: 300px;
height: auto;
border-radius: 12px;
object-fit: cover;
box-shadow: 0 0 12px rgba(0, 0, 0, 0.2);
} }
</style> </style>