mirror of
https://github.com/seanmorley15/AdventureLog.git
synced 2025-08-05 13:15:18 +02:00
commit
6b97b3a7f3
29 changed files with 2480 additions and 56 deletions
|
@ -19,8 +19,13 @@ RUN npm run build
|
||||||
# Expose the port that the app is listening on
|
# Expose the port that the app is listening on
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
|
|
||||||
|
|
||||||
|
RUN chmod +x ./startup.sh
|
||||||
|
|
||||||
# The USER instruction sets the user name to use as the default user for the remainder of the current stage
|
# The USER instruction sets the user name to use as the default user for the remainder of the current stage
|
||||||
USER node:node
|
USER node:node
|
||||||
|
|
||||||
# This is the command that will be run inside the image when you tell Docker to start the container
|
# get permission to run startup script
|
||||||
CMD ["node", "build/index.js"]
|
|
||||||
|
# Run startup.sh instead of the default command
|
||||||
|
CMD ["./startup.sh"]
|
||||||
|
|
|
@ -3,9 +3,15 @@ services:
|
||||||
build: .
|
build: .
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
# depends_on:
|
environment:
|
||||||
# - db
|
- DATABASE_URL=postgres://adventurelog:PO24VjITwGgk@db:5432/adventurelog
|
||||||
# db:
|
depends_on:
|
||||||
# image: postgres
|
- db
|
||||||
# environment:
|
db:
|
||||||
# POSTGRES_PASSWORD: example
|
image: postgres
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: adventurelog
|
||||||
|
POSTGRES_PASSWORD: PO24VjITwGgk
|
||||||
|
POSTGRES_DB: adventurelog
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
15
drizzle.config.ts
Normal file
15
drizzle.config.ts
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import type { Config } from 'drizzle-kit';
|
||||||
|
import * as dotenv from 'dotenv';
|
||||||
|
dotenv.config();
|
||||||
|
const { DATABASE_URL } = process.env;
|
||||||
|
if (!DATABASE_URL) {
|
||||||
|
throw new Error('No url');
|
||||||
|
}
|
||||||
|
export default {
|
||||||
|
schema: './src/lib/db/schema.ts',
|
||||||
|
out: './migrations',
|
||||||
|
driver: 'pg',
|
||||||
|
dbCredentials: {
|
||||||
|
connectionString: DATABASE_URL
|
||||||
|
}
|
||||||
|
} satisfies Config;
|
5
migrations/0000_fancy_starjammers.sql
Normal file
5
migrations/0000_fancy_starjammers.sql
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS "featuredAdventures" (
|
||||||
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"location" text
|
||||||
|
);
|
6
migrations/0001_nostalgic_skreet.sql
Normal file
6
migrations/0001_nostalgic_skreet.sql
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS "sharedAdventures" (
|
||||||
|
"id" serial PRIMARY KEY NOT NULL,
|
||||||
|
"name" text NOT NULL,
|
||||||
|
"location" text,
|
||||||
|
"date" text
|
||||||
|
);
|
1
migrations/0002_dusty_captain_midlands.sql
Normal file
1
migrations/0002_dusty_captain_midlands.sql
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE "sharedAdventures" ALTER COLUMN "id" SET DATA TYPE text;
|
4
migrations/0003_clammy_goblin_queen.sql
Normal file
4
migrations/0003_clammy_goblin_queen.sql
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
ALTER TABLE "sharedAdventures" ADD COLUMN "data" json NOT NULL;--> statement-breakpoint
|
||||||
|
ALTER TABLE "sharedAdventures" DROP COLUMN IF EXISTS "name";--> statement-breakpoint
|
||||||
|
ALTER TABLE "sharedAdventures" DROP COLUMN IF EXISTS "location";--> statement-breakpoint
|
||||||
|
ALTER TABLE "sharedAdventures" DROP COLUMN IF EXISTS "date";
|
43
migrations/meta/0000_snapshot.json
Normal file
43
migrations/meta/0000_snapshot.json
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
{
|
||||||
|
"id": "1639b320-88dd-4af5-ae34-092ab26b4b85",
|
||||||
|
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "pg",
|
||||||
|
"tables": {
|
||||||
|
"featuredAdventures": {
|
||||||
|
"name": "featuredAdventures",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "serial",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"name": "location",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
77
migrations/meta/0001_snapshot.json
Normal file
77
migrations/meta/0001_snapshot.json
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
{
|
||||||
|
"id": "183ebfda-8d83-4256-8715-169d36867deb",
|
||||||
|
"prevId": "1639b320-88dd-4af5-ae34-092ab26b4b85",
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "pg",
|
||||||
|
"tables": {
|
||||||
|
"featuredAdventures": {
|
||||||
|
"name": "featuredAdventures",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "serial",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"name": "location",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"sharedAdventures": {
|
||||||
|
"name": "sharedAdventures",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "serial",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"name": "location",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"name": "date",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
77
migrations/meta/0002_snapshot.json
Normal file
77
migrations/meta/0002_snapshot.json
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
{
|
||||||
|
"id": "808d6d31-5ef6-4b22-97f0-cfc73193eb5e",
|
||||||
|
"prevId": "183ebfda-8d83-4256-8715-169d36867deb",
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "pg",
|
||||||
|
"tables": {
|
||||||
|
"featuredAdventures": {
|
||||||
|
"name": "featuredAdventures",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "serial",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"name": "location",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"sharedAdventures": {
|
||||||
|
"name": "sharedAdventures",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"name": "location",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
},
|
||||||
|
"date": {
|
||||||
|
"name": "date",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
65
migrations/meta/0003_snapshot.json
Normal file
65
migrations/meta/0003_snapshot.json
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
{
|
||||||
|
"id": "45d98527-f0a9-44fc-9658-d3c461afed95",
|
||||||
|
"prevId": "808d6d31-5ef6-4b22-97f0-cfc73193eb5e",
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "pg",
|
||||||
|
"tables": {
|
||||||
|
"featuredAdventures": {
|
||||||
|
"name": "featuredAdventures",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "serial",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"name": "location",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"sharedAdventures": {
|
||||||
|
"name": "sharedAdventures",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"name": "data",
|
||||||
|
"type": "json",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"indexes": {},
|
||||||
|
"foreignKeys": {},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enums": {},
|
||||||
|
"schemas": {},
|
||||||
|
"_meta": {
|
||||||
|
"columns": {},
|
||||||
|
"schemas": {},
|
||||||
|
"tables": {}
|
||||||
|
}
|
||||||
|
}
|
34
migrations/meta/_journal.json
Normal file
34
migrations/meta/_journal.json
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
{
|
||||||
|
"version": "5",
|
||||||
|
"dialect": "pg",
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"idx": 0,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1712061709595,
|
||||||
|
"tag": "0000_fancy_starjammers",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 1,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1712083579596,
|
||||||
|
"tag": "0001_nostalgic_skreet",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 2,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1712083756923,
|
||||||
|
"tag": "0002_dusty_captain_midlands",
|
||||||
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 3,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1712083977580,
|
||||||
|
"tag": "0003_clammy_goblin_queen",
|
||||||
|
"breakpoints": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
1845
package-lock.json
generated
1845
package-lock.json
generated
File diff suppressed because it is too large
Load diff
16
package.json
16
package.json
|
@ -1,32 +1,42 @@
|
||||||
{
|
{
|
||||||
"name": "adventurelog",
|
"name": "adventurelog",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
|
"description": "Embark, Explore, Remember. 🌍",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite dev",
|
"dev": "vite dev",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
|
||||||
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
|
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
|
||||||
|
"studio": "drizzle-kit studio --config drizzle.config.ts",
|
||||||
|
"generate": "drizzle-kit generate:pg --config drizzle.config.ts",
|
||||||
|
"migrate": "drizzle-kit push:pg --config drizzle.config.ts",
|
||||||
|
"seed": "node seed.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sveltejs/adapter-auto": "^3.0.0",
|
"@sveltejs/adapter-auto": "^3.0.0",
|
||||||
"@sveltejs/adapter-node": "^5.0.1",
|
"@sveltejs/adapter-node": "^5.0.1",
|
||||||
|
"@sveltejs/adapter-vercel": "^5.2.0",
|
||||||
"@sveltejs/kit": "^2.0.0",
|
"@sveltejs/kit": "^2.0.0",
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
"@sveltejs/vite-plugin-svelte": "^3.0.0",
|
||||||
"@tailwindcss/typography": "^0.5.12",
|
"@tailwindcss/typography": "^0.5.12",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"daisyui": "^4.9.0",
|
"daisyui": "^4.9.0",
|
||||||
|
"dotenv": "^16.4.5",
|
||||||
|
"drizzle-kit": "^0.20.14",
|
||||||
|
"pg": "^8.11.4",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
"svelte": "^4.2.7",
|
"svelte": "^4.2.7",
|
||||||
"svelte-check": "^3.6.0",
|
"svelte-check": "^3.6.0",
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.3",
|
||||||
"tslib": "^2.4.1",
|
"tslib": "^2.4.1",
|
||||||
"typescript": "^5.0.0",
|
"typescript": "^5.0.0",
|
||||||
"vite": "^5.0.3",
|
"vite": "^5.0.3"
|
||||||
"@sveltejs/adapter-vercel": "^5.2.0"
|
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"drizzle-orm": "^0.30.6",
|
||||||
|
"postgres": "^3.4.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
81
sampleData/parks.sql
Normal file
81
sampleData/parks.sql
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
INSERT INTO "featuredAdventures" (id, name, location) VALUES
|
||||||
|
(20, 'Yellowstone National Park', 'Wyoming, Montana, Idaho, USA'),
|
||||||
|
(21, 'Yosemite National Park', 'California, USA'),
|
||||||
|
(22, 'Banff National Park', 'Alberta, Canada'),
|
||||||
|
(23, 'Kruger National Park', 'Limpopo, South Africa'),
|
||||||
|
(24, 'Grand Canyon National Park', 'Arizona, USA'),
|
||||||
|
(25, 'Great Smoky Mountains National Park', 'North Carolina, Tennessee, USA'),
|
||||||
|
(26, 'Zion National Park', 'Utah, USA'),
|
||||||
|
(27, 'Glacier National Park', 'Montana, USA'),
|
||||||
|
(28, 'Rocky Mountain National Park', 'Colorado, USA'),
|
||||||
|
(29, 'Everglades National Park', 'Florida, USA'),
|
||||||
|
(30, 'Arches National Park', 'Utah, USA'),
|
||||||
|
(31, 'Acadia National Park', 'Maine, USA'),
|
||||||
|
(32, 'Sequoia National Park', 'California, USA'),
|
||||||
|
(33, 'Joshua Tree National Park', 'California, USA'),
|
||||||
|
(34, 'Yellowstone National Park', 'Wyoming, Montana, Idaho, USA'),
|
||||||
|
(35, 'Bryce Canyon National Park', 'Utah, USA'),
|
||||||
|
(36, 'Grand Teton National Park', 'Wyoming, USA'),
|
||||||
|
(37, 'Denali National Park', 'Alaska, USA'),
|
||||||
|
(38, 'Olympic National Park', 'Washington, USA'),
|
||||||
|
(39, 'Canyonlands National Park', 'Utah, USA'),
|
||||||
|
(40, 'Death Valley National Park', 'California, Nevada, USA'),
|
||||||
|
(41, 'Redwood National and State Parks', 'California, USA'),
|
||||||
|
(42, 'Waterton Lakes National Park', 'Alberta, Canada'),
|
||||||
|
(43, 'Mesa Verde National Park', 'Colorado, USA'),
|
||||||
|
(44, 'Petrified Forest National Park', 'Arizona, USA'),
|
||||||
|
(45, 'Capitol Reef National Park', 'Utah, USA'),
|
||||||
|
(46, 'Yellowstone National Park', 'Wyoming, Montana, Idaho, USA'),
|
||||||
|
(47, 'Yosemite National Park', 'California, USA'),
|
||||||
|
(48, 'Banff National Park', 'Alberta, Canada'),
|
||||||
|
(49, 'Kruger National Park', 'Limpopo, South Africa'),
|
||||||
|
(50, 'Grand Canyon National Park', 'Arizona, USA'),
|
||||||
|
(51, 'Great Smoky Mountains National Park', 'North Carolina, Tennessee, USA'),
|
||||||
|
(52, 'Zion National Park', 'Utah, USA'),
|
||||||
|
(53, 'Glacier National Park', 'Montana, USA'),
|
||||||
|
(54, 'Rocky Mountain National Park', 'Colorado, USA'),
|
||||||
|
(55, 'Everglades National Park', 'Florida, USA'),
|
||||||
|
(56, 'Arches National Park', 'Utah, USA'),
|
||||||
|
(57, 'Acadia National Park', 'Maine, USA'),
|
||||||
|
(58, 'Sequoia National Park', 'California, USA'),
|
||||||
|
(59, 'Joshua Tree National Park', 'California, USA'),
|
||||||
|
(60, 'Yellowstone National Park', 'Wyoming, Montana, Idaho, USA'),
|
||||||
|
(61, 'Bryce Canyon National Park', 'Utah, USA'),
|
||||||
|
(62, 'Grand Teton National Park', 'Wyoming, USA'),
|
||||||
|
(63, 'Denali National Park', 'Alaska, USA'),
|
||||||
|
(64, 'Olympic National Park', 'Washington, USA'),
|
||||||
|
(65, 'Canyonlands National Park', 'Utah, USA'),
|
||||||
|
(66, 'Yellowstone National Park', 'Wyoming, Montana, Idaho, USA'),
|
||||||
|
(67, 'Yosemite National Park', 'California, USA'),
|
||||||
|
(68, 'Banff National Park', 'Alberta, Canada'),
|
||||||
|
(69, 'Kruger National Park', 'Limpopo, South Africa'),
|
||||||
|
(70, 'Grand Canyon National Park', 'Arizona, USA'),
|
||||||
|
(71, 'Great Smoky Mountains National Park', 'North Carolina, Tennessee, USA'),
|
||||||
|
(72, 'Zion National Park', 'Utah, USA'),
|
||||||
|
(73, 'Glacier National Park', 'Montana, USA'),
|
||||||
|
(74, 'Rocky Mountain National Park', 'Colorado, USA'),
|
||||||
|
(75, 'Everglades National Park', 'Florida, USA'),
|
||||||
|
(76, 'Arches National Park', 'Utah, USA'),
|
||||||
|
(77, 'Acadia National Park', 'Maine, USA'),
|
||||||
|
(78, 'Sequoia National Park', 'California, USA'),
|
||||||
|
(79, 'Joshua Tree National Park', 'California, USA'),
|
||||||
|
(80, 'Yellowstone National Park', 'Wyoming, Montana, Idaho, USA'),
|
||||||
|
(81, 'Bryce Canyon National Park', 'Utah, USA'),
|
||||||
|
(82, 'Grand Teton National Park', 'Wyoming, USA'),
|
||||||
|
(83, 'Denali National Park', 'Alaska, USA'),
|
||||||
|
(84, 'Olympic National Park', 'Washington, USA'),
|
||||||
|
(85, 'Canyonlands National Park', 'Utah, USA'),
|
||||||
|
(86, 'Yellowstone National Park', 'Wyoming, Montana, Idaho, USA'),
|
||||||
|
(87, 'Yosemite National Park', 'California, USA'),
|
||||||
|
(88, 'Banff National Park', 'Alberta, Canada'),
|
||||||
|
(89, 'Kruger National Park', 'Limpopo, South Africa'),
|
||||||
|
(90, 'Grand Canyon National Park', 'Arizona, USA'),
|
||||||
|
(91, 'Great Smoky Mountains National Park', 'North Carolina, Tennessee, USA'),
|
||||||
|
(92, 'Zion National Park', 'Utah, USA'),
|
||||||
|
(93, 'Glacier National Park', 'Montana, USA'),
|
||||||
|
(94, 'Rocky Mountain National Park', 'Colorado, USA'),
|
||||||
|
(95, 'Everglades National Park', 'Florida, USA'),
|
||||||
|
(96, 'Arches National Park', 'Utah, USA'),
|
||||||
|
(97, 'Acadia National Park', 'Maine, USA'),
|
||||||
|
(98, 'Sequoia National Park', 'California, USA'),
|
||||||
|
(99, 'Joshua Tree National Park', 'California, USA');
|
24
src/lib/components/FeaturedAdventureCard.svelte
Normal file
24
src/lib/components/FeaturedAdventureCard.svelte
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher } from 'svelte';
|
||||||
|
import locationDot from "$lib/assets/locationDot.svg";
|
||||||
|
import calendar from "$lib/assets/calendar.svg";
|
||||||
|
const dispatch = createEventDispatcher();
|
||||||
|
|
||||||
|
export let name:String;
|
||||||
|
export let location:String;
|
||||||
|
|
||||||
|
function add() {
|
||||||
|
dispatch('add', {name, location});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="card min-w-max lg:w-96 md:w-80 sm:w-60 xs:w-40 bg-neutral shadow-xl overflow-hidden">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="card-title overflow-ellipsis">{name}</h2>
|
||||||
|
<p><img src={locationDot} class="inline-block -mt-1 mr-1" alt="Logo" />{location}</p>
|
||||||
|
<div class="card-actions justify-end">
|
||||||
|
<button class="btn btn-primary" on:click={add}>Add</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { getNumberOfAdventures } from "../../services/adventureService";
|
import { visitCount } from '$lib/utils/stores/visitCountStore';
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
|
||||||
async function goHome() {
|
async function goHome() {
|
||||||
|
@ -8,16 +8,37 @@
|
||||||
async function goToLog() {
|
async function goToLog() {
|
||||||
goto('/log');
|
goto('/log');
|
||||||
}
|
}
|
||||||
|
async function goToFeatured() {
|
||||||
|
goto('/featured');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
let count = 0;
|
||||||
|
visitCount.subscribe((value) => {
|
||||||
|
count = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Set the visit count to the number of adventures stored in local storage
|
||||||
|
const isBrowser = typeof window !== 'undefined';
|
||||||
|
if (isBrowser) {
|
||||||
|
const storedAdventures = localStorage.getItem('adventures');
|
||||||
|
if (storedAdventures) {
|
||||||
|
let parsed = JSON.parse(storedAdventures);
|
||||||
|
visitCount.set (parsed.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<div class="navbar bg-base-100 flex flex-col md:flex-row">
|
<div class="navbar bg-base-100 flex flex-col md:flex-row">
|
||||||
<div class="navbar-start flex justify-around md:justify-start">
|
<div class="navbar-start flex justify-around md:justify-start">
|
||||||
<button class="btn btn-primary my-2 md:my-0 md:mr-4 md:ml-2" on:click={goHome}>Home</button>
|
<button class="btn btn-primary my-2 md:my-0 md:mr-4 md:ml-2" on:click={goHome}>Home</button>
|
||||||
<button class="btn btn-primary my-2 md:my-0" on:click={goToLog}>My Log</button>
|
<button class="btn btn-primary my-2 md:my-0 md:mr-4 md:ml-2" on:click={goToLog}>My Log</button>
|
||||||
|
<button class="btn btn-primary my-2 md:my-0" on:click={goToFeatured}>Featured</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="navbar-center flex justify-center md:justify-center">
|
<div class="navbar-center flex justify-center md:justify-center">
|
||||||
<a class="btn btn-ghost text-xl" href="/">AdventureLog 🗺️</a>
|
<a class="btn btn-ghost text-xl" href="/">AdventureLog 🗺️</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="navbar-end flex justify-around md:justify-end">
|
<div class="navbar-end flex justify-around md:justify-end mr-4">
|
||||||
<p>Adventures: {getNumberOfAdventures()} </p>
|
<p>Adventures: {count} </p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
8
src/lib/db/db.server.ts
Normal file
8
src/lib/db/db.server.ts
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
import { drizzle } from 'drizzle-orm/postgres-js';
|
||||||
|
import postgres from 'postgres';
|
||||||
|
import dotenv from 'dotenv';
|
||||||
|
dotenv.config();
|
||||||
|
const { DATABASE_URL } = process.env;
|
||||||
|
|
||||||
|
const client = postgres(DATABASE_URL)
|
||||||
|
export const db = drizzle(client, {});
|
12
src/lib/db/schema.ts
Normal file
12
src/lib/db/schema.ts
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { pgTable,json,text,serial } from "drizzle-orm/pg-core";
|
||||||
|
|
||||||
|
export const featuredAdventures = pgTable("featuredAdventures",{
|
||||||
|
id:serial("id").primaryKey(),
|
||||||
|
name:text("name").notNull(),
|
||||||
|
location:text("location"),
|
||||||
|
})
|
||||||
|
|
||||||
|
export const sharedAdventures = pgTable("sharedAdventures",{
|
||||||
|
id:text("id").primaryKey(),
|
||||||
|
data:json("data").notNull(),
|
||||||
|
})
|
|
@ -1 +1,11 @@
|
||||||
// place files you want to import through the `$lib` alias in this folder.
|
// place files you want to import through the `$lib` alias in this folder.
|
||||||
|
export function generateRandomString() {
|
||||||
|
let randomString = '';
|
||||||
|
const digits = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||||
|
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
const randomIndex = Math.floor(Math.random() * digits.length);
|
||||||
|
randomString += digits[randomIndex];
|
||||||
|
}
|
||||||
|
return randomString;
|
||||||
|
}
|
4
src/lib/utils/stores/visitCountStore.ts
Normal file
4
src/lib/utils/stores/visitCountStore.ts
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import { writable } from "svelte/store";
|
||||||
|
|
||||||
|
export const visitCount = writable(0);
|
11
src/routes/api/share/+server.ts
Normal file
11
src/routes/api/share/+server.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { db } from "$lib/db/db.server";
|
||||||
|
import { sharedAdventures } from "$lib/db/schema";
|
||||||
|
import type { Adventure } from "$lib/utils/types";
|
||||||
|
|
||||||
|
export async function POST({ request }: { request: Request }) {
|
||||||
|
const { key , data } = await request.json();
|
||||||
|
let adventure = data as Adventure;
|
||||||
|
console.log(adventure);
|
||||||
|
await db.insert(sharedAdventures).values({ id:key,data:adventure }).execute();
|
||||||
|
return new Response(JSON.stringify({key:key}));
|
||||||
|
}
|
11
src/routes/featured/+page.server.ts
Normal file
11
src/routes/featured/+page.server.ts
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { db } from '$lib/db/db.server';
|
||||||
|
import { featuredAdventures } from '$lib/db/schema';
|
||||||
|
import type { Adventure } from '$lib/utils/types';
|
||||||
|
|
||||||
|
|
||||||
|
export const load = (async () => {
|
||||||
|
const result = await db.select().from(featuredAdventures).orderBy(featuredAdventures.id);
|
||||||
|
return {
|
||||||
|
result : result as Adventure[]
|
||||||
|
};
|
||||||
|
})
|
31
src/routes/featured/+page.svelte
Normal file
31
src/routes/featured/+page.svelte
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
<script lang="ts">
|
||||||
|
export let data
|
||||||
|
console.log(data.result);
|
||||||
|
import FeaturedAdventureCard from '$lib/components/FeaturedAdventureCard.svelte';
|
||||||
|
import type { Adventure } from '$lib/utils/types.js';
|
||||||
|
import { addAdventure, getNextId } from '../../services/adventureService.js';
|
||||||
|
|
||||||
|
function add(event: CustomEvent<{name: string, location: string}>) {
|
||||||
|
console.log(event.detail);
|
||||||
|
let newAdventure:Adventure = {
|
||||||
|
id: getNextId(),
|
||||||
|
name: event.detail.name,
|
||||||
|
location: event.detail.location,
|
||||||
|
created: ""
|
||||||
|
}
|
||||||
|
addAdventure(newAdventure);
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="flex justify-center items-center w-full mt-4 mb-4">
|
||||||
|
<article class="prose">
|
||||||
|
<h1 class="text-center">Featured Adventure Locations</h1>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid xl:grid-cols-3 lg:grid-cols-3 md:grid-cols-2 sm:grid-cols-1 gap-4 mt-4 content-center auto-cols-auto ml-6 mr-6">
|
||||||
|
{#each data.result as adventure (adventure.id)}
|
||||||
|
<FeaturedAdventureCard on:add={add} name={adventure.name} location={adventure.location} />
|
||||||
|
{/each}
|
||||||
|
</div>
|
|
@ -10,6 +10,7 @@
|
||||||
import SucessToast from "$lib/components/SucessToast.svelte";
|
import SucessToast from "$lib/components/SucessToast.svelte";
|
||||||
import mapDrawing from "$lib/assets/adventure_map.svg"
|
import mapDrawing from "$lib/assets/adventure_map.svg"
|
||||||
import EditModal from "$lib/components/EditModal.svelte";
|
import EditModal from "$lib/components/EditModal.svelte";
|
||||||
|
import { generateRandomString } from "$lib";
|
||||||
|
|
||||||
let newName = '';
|
let newName = '';
|
||||||
let newLocation = '';
|
let newLocation = '';
|
||||||
|
@ -79,6 +80,28 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function shareLink() {
|
||||||
|
let key = generateRandomString()
|
||||||
|
let data = JSON.stringify(adventures)
|
||||||
|
fetch('/api/share', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ key, data }),
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
console.log('Success:', data);
|
||||||
|
let url = window.location.origin + '/shared/' + key
|
||||||
|
navigator.clipboard.writeText(url)
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.error('Error:', error);
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function handleClose() {
|
function handleClose() {
|
||||||
editId = NaN;
|
editId = NaN;
|
||||||
editName = '';
|
editName = '';
|
||||||
|
@ -94,6 +117,12 @@
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<div class="flex justify-center items-center w-full mt-4 mb-4">
|
||||||
|
<article class="prose">
|
||||||
|
<h2 class="text-center">Add new Location</h2>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-row items-center justify-center gap-4">
|
<div class="flex flex-row items-center justify-center gap-4">
|
||||||
<form on:submit={createNewAdventure} class="flex gap-2">
|
<form on:submit={createNewAdventure} class="flex gap-2">
|
||||||
<input type="text" bind:value={newName} placeholder="Adventure Name" class="input input-bordered w-full max-w-xs" />
|
<input type="text" bind:value={newName} placeholder="Adventure Name" class="input input-bordered w-full max-w-xs" />
|
||||||
|
@ -101,6 +130,13 @@
|
||||||
<input class="btn btn-primary" type="submit" value="Add Adventure">
|
<input class="btn btn-primary" type="submit" value="Add Adventure">
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
{#if adventures.length != 0}
|
||||||
|
<div class="flex justify-center items-center w-full mt-4 mb-4">
|
||||||
|
<article class="prose">
|
||||||
|
<h1 class="text-center">My Visited Adventure Locations</h1>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
{#if isShowingToast}
|
{#if isShowingToast}
|
||||||
<SucessToast action={toastAction} />
|
<SucessToast action={toastAction} />
|
||||||
|
@ -124,12 +160,15 @@
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if adventures.length != 0}
|
{#if adventures.length != 0}
|
||||||
<div class="flex flex-row items-center justify-center mt-16 gap-4">
|
<div class="flex flex-row items-center justify-center mt-16 gap-4 mb-4">
|
||||||
<button class="btn btn-neutral" on:click={async () => { window.location.href = exportData(); }}>
|
<button class="btn btn-neutral" on:click={async () => { window.location.href = exportData(); }}>
|
||||||
<img src={exportFile} class="inline-block -mt-1" alt="Logo" /> Save as File
|
<img src={exportFile} class="inline-block -mt-1" alt="Logo" /> Save as File
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-neutral" on:click={deleteData}>
|
<button class="btn btn-neutral" on:click={deleteData}>
|
||||||
<img src={deleteIcon} class="inline-block -mt-1" alt="Logo" /> Delete Data
|
<img src={deleteIcon} class="inline-block -mt-1" alt="Logo" /> Delete Data
|
||||||
</button>
|
</button>
|
||||||
|
<button class="btn btn-neutral" on:click={shareLink}>
|
||||||
|
<img src={deleteIcon} class="inline-block -mt-1" alt="Logo" /> Share as Link
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
14
src/routes/shared/[key]/+page.server.ts
Normal file
14
src/routes/shared/[key]/+page.server.ts
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import { db } from "$lib/db/db.server";
|
||||||
|
import { sharedAdventures } from "$lib/db/schema";
|
||||||
|
import { eq } from "drizzle-orm";
|
||||||
|
import type { Adventure } from "$lib/utils/types";
|
||||||
|
|
||||||
|
export async function load({ params }) {
|
||||||
|
let key = params.key;
|
||||||
|
let result = await db.select().from(sharedAdventures).where(eq(sharedAdventures.id, key)).execute();
|
||||||
|
let adventure = result[0].data as Adventure;
|
||||||
|
console.log(adventure);
|
||||||
|
return {
|
||||||
|
result: adventure
|
||||||
|
};
|
||||||
|
};
|
8
src/routes/shared/[key]/+page.svelte
Normal file
8
src/routes/shared/[key]/+page.svelte
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import type { Adventure } from '$lib/utils/types'
|
||||||
|
export let data;
|
||||||
|
let result = data.result;
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<p>{result}</p>
|
|
@ -2,9 +2,12 @@ import type { Adventure } from '$lib/utils/types';
|
||||||
|
|
||||||
let adventures: Adventure[] = [];
|
let adventures: Adventure[] = [];
|
||||||
|
|
||||||
|
import { visitCount } from '$lib/utils/stores/visitCountStore';
|
||||||
|
|
||||||
// Check if localStorage is available (browser environment)
|
// Check if localStorage is available (browser environment)
|
||||||
const isBrowser = typeof window !== 'undefined';
|
const isBrowser = typeof window !== 'undefined';
|
||||||
|
|
||||||
|
|
||||||
// Load adventures from localStorage on startup (only in the browser)
|
// Load adventures from localStorage on startup (only in the browser)
|
||||||
if (isBrowser) {
|
if (isBrowser) {
|
||||||
const storedAdventures = localStorage.getItem('adventures');
|
const storedAdventures = localStorage.getItem('adventures');
|
||||||
|
@ -26,8 +29,10 @@ export function addAdventure(adventure: Adventure) {
|
||||||
adventures = [...adventures, adventure];
|
adventures = [...adventures, adventure];
|
||||||
if (isBrowser) {
|
if (isBrowser) {
|
||||||
localStorage.setItem('adventures', JSON.stringify(adventures));
|
localStorage.setItem('adventures', JSON.stringify(adventures));
|
||||||
|
visitCount.update((n) => n + 1);
|
||||||
}
|
}
|
||||||
console.log(adventures);
|
console.log(adventures);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAdventures(): Adventure[] {
|
export function getAdventures(): Adventure[] {
|
||||||
|
@ -38,7 +43,9 @@ export function removeAdventure(event: { detail: number; }) {
|
||||||
adventures = adventures.filter(adventure => adventure.id !== event.detail);
|
adventures = adventures.filter(adventure => adventure.id !== event.detail);
|
||||||
if (isBrowser) {
|
if (isBrowser) {
|
||||||
localStorage.setItem('adventures', JSON.stringify(adventures));
|
localStorage.setItem('adventures', JSON.stringify(adventures));
|
||||||
|
visitCount.update((n) => n - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function saveEdit(adventure:Adventure) {
|
export function saveEdit(adventure:Adventure) {
|
||||||
|
@ -61,15 +68,13 @@ export function saveEdit(adventure:Adventure) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNumberOfAdventures() {
|
|
||||||
return adventures.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function clearAdventures() {
|
export function clearAdventures() {
|
||||||
adventures = [];
|
adventures = [];
|
||||||
if (isBrowser) {
|
if (isBrowser) {
|
||||||
localStorage.setItem('adventures', JSON.stringify(adventures));
|
localStorage.setItem('adventures', JSON.stringify(adventures));
|
||||||
|
visitCount.set(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
24
startup.sh
Normal file
24
startup.sh
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# Function to check if the database is ready
|
||||||
|
wait_for_db() {
|
||||||
|
echo "Waiting for the database to start up..."
|
||||||
|
while ! nc -z db 5432; do
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
echo "Database is now available."
|
||||||
|
}
|
||||||
|
|
||||||
|
# Start your application here
|
||||||
|
# Example: node build/index.js
|
||||||
|
# Print message
|
||||||
|
echo "Starting AdventureLog"
|
||||||
|
|
||||||
|
# Wait for the database to start up
|
||||||
|
wait_for_db
|
||||||
|
|
||||||
|
# Run database migration
|
||||||
|
npm run migrate
|
||||||
|
|
||||||
|
# Start the application
|
||||||
|
node build/index.js
|
Loading…
Add table
Add a link
Reference in a new issue