mirror of
https://github.com/D4M13N-D3V/neroshitron.git
synced 2025-06-16 21:29:16 +00:00
Compare commits
230 Commits
Author | SHA1 | Date | |
---|---|---|---|
2e19d5fdeb | |||
63f31e0f4c | |||
f75d889ee8 | |||
8877362484 | |||
082c161959 | |||
5d96002a2e | |||
65ddd704f0 | |||
b12d095e3e | |||
581ceb028a | |||
7ac84fc0cf | |||
164aec1c51 | |||
420e029d66 | |||
d94f3b825b | |||
7635178e3c | |||
a9968ccb03 | |||
4d86b8aeed | |||
19bee6998a | |||
fcf83c6435 | |||
32ba288463 | |||
334db37d18 | |||
1112191b61 | |||
52b7771994 | |||
9e76f9315b | |||
c9bf8e8431 | |||
691292becc | |||
e8fa3d2ce0 | |||
fd76220269 | |||
e9e4f25520 | |||
234cc989f1 | |||
e6a81a3bdf | |||
96aeca6242 | |||
a6d050c35f | |||
f790a03c27 | |||
6f5bf90a0b | |||
e5daff376a | |||
a0a38389a6 | |||
85c066baec | |||
9c6bdddd22 | |||
87ba2e032d | |||
28414630a4 | |||
534cbf2957 | |||
481b4f698c | |||
172a3015af | |||
6564be1a60 | |||
fdcaccfbd6 | |||
6541bd94fe | |||
82fdd61170 | |||
caca715cc0 | |||
74335ff6cf | |||
3206a19f7a | |||
e48d3ebafb | |||
168c835a23 | |||
0127d00021 | |||
02872252b5 | |||
b6736651c5 | |||
78a25ab398 | |||
58d384a3fc | |||
76a09c8e8c | |||
73836c5893 | |||
4c972778cd | |||
795fc0f5f7 | |||
e4dde90da4 | |||
fa6bf10249 | |||
cd5d0bf304 | |||
4a3c7023ba | |||
ea3a14a6e4 | |||
451bdd1106 | |||
2b21c2feff | |||
02e85c54fc | |||
ac4007a82e | |||
e584a43145 | |||
b232be9377 | |||
46a20bbd7e | |||
894fb58c29 | |||
2c59660566 | |||
666e377cdb | |||
da6fc56b86 | |||
5daa585a9e | |||
d33f36adaf | |||
e03816928a | |||
de08c2ddd0 | |||
9de286f920 | |||
45d3b459d8 | |||
712e1ce5cd | |||
912fa157e2 | |||
394163198c | |||
f74d7a8fa9 | |||
cfe47be428 | |||
bd334bcbea | |||
54ec36cebc | |||
f175b31976 | |||
9b5c3d44c5 | |||
97f2a31951 | |||
4c564df94a | |||
2edf752b05 | |||
d7f3330dc2 | |||
afe4076874 | |||
f86c618b1d | |||
7fec3450d9 | |||
41c90c2a58 | |||
bef53cadce | |||
f30d2c5a2a | |||
f2bd76487e | |||
92c2317af1 | |||
0b390b7658 | |||
8a994123af | |||
dcfe7c5676 | |||
21fa376190 | |||
23137d4e04 | |||
b99f3fa256 | |||
2c036794ff | |||
ee1272b520 | |||
2cccc65a9a | |||
e17aba510c | |||
381009d5c9 | |||
401e3d41dc | |||
82728cbc97 | |||
de0a5a8e73 | |||
057c20cd21 | |||
b2f700280a | |||
e8161fc226 | |||
10f8e5d289 | |||
54a771b47f | |||
e82305954e | |||
fe09172881 | |||
caac354273 | |||
ea21548c68 | |||
eb8df7bed7 | |||
4b0060e5dd | |||
08ce73e64e | |||
af0dd625b4 | |||
43432a8bcd | |||
5e5678c280 | |||
c0a382e4a7 | |||
ab59264d84 | |||
ea68c28b2e | |||
6cd71b64e8 | |||
b93f3945bf | |||
53fcbb76f6 | |||
8ad20079de | |||
10f36e54ff | |||
e930b2ce73 | |||
b5a796d3ff | |||
abab8c9336 | |||
82399d1bc3 | |||
cb37b333b0 | |||
adfab3585b | |||
052bc21604 | |||
1647474a74 | |||
cf7e485f4e | |||
ab0198df01 | |||
a48488a128 | |||
82efd1f10e | |||
70ea1d8a9c | |||
97eba7457d | |||
8eedebfee2 | |||
9f205dd034 | |||
f7cef69b5b | |||
090630c507 | |||
6af5a0ee5d | |||
323ba05fda | |||
8f41b42cf4 | |||
58a10bcc41 | |||
b1bd8ab67e | |||
f53ea97c3e | |||
21307711e6 | |||
7780a3a0d1 | |||
7bf385f8c0 | |||
867af6ac1d | |||
0203f848b1 | |||
02f95efe7b | |||
4fcb80fd75 | |||
eafa726b43 | |||
50fcd06c17 | |||
ef5f02176e | |||
b12d3e1752 | |||
812c01e518 | |||
4c16ebd1d7 | |||
246eb848f8 | |||
8cf5e0b827 | |||
1286003442 | |||
3291d70361 | |||
b14c9d54ad | |||
d8e30415cb | |||
a3382a6434 | |||
396bb68b14 | |||
138f34169e | |||
e6fd4cf83b | |||
b8146d70a0 | |||
884ea73565 | |||
ca13aa4ae9 | |||
7a568aa8d0 | |||
0b4dc1a1e3 | |||
72a7a12cce | |||
c9e044baaa | |||
5b06ac56ff | |||
9b23070399 | |||
8579f80012 | |||
30db6f1275 | |||
1b5e1da64d | |||
91ea64d20f | |||
a347dc9593 | |||
77bfdc0b0b | |||
ea8a876b6f | |||
f6871f4934 | |||
cc194b239b | |||
fac7ebd382 | |||
6cdc511b38 | |||
4c402955fe | |||
0099cced35 | |||
a3de797bcb | |||
d2c314687a | |||
92823e9d7f | |||
161b6d8247 | |||
33dd9d8062 | |||
7b29c0f8fb | |||
63ceb7a8ae | |||
3039d4eca4 | |||
9bd8962ea4 | |||
663e0c8421 | |||
14ea434a23 | |||
a4dbe3e624 | |||
5c4a48ad11 | |||
f804bda157 | |||
c45f89d4a8 | |||
1df09fa2c4 | |||
c58a57c31a | |||
acc0e0d846 | |||
56ce967c4c | |||
c6fed79f5a |
2
.default.env
Normal file
2
.default.env
Normal file
@ -0,0 +1,2 @@
|
||||
NEXT_PUBLIC_SUPABASE_URL=http://localhost:54321
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
|
2
.env
Normal file
2
.env
Normal file
@ -0,0 +1,2 @@
|
||||
NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0
|
4
.env.example
Normal file
4
.env.example
Normal file
@ -0,0 +1,4 @@
|
||||
# Update these with your Supabase details from your project settings > API
|
||||
# https://app.supabase.com/project/_/settings/api
|
||||
NEXT_PUBLIC_SUPABASE_URL=your-project-url
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
|
2
.env.production
Normal file
2
.env.production
Normal file
@ -0,0 +1,2 @@
|
||||
NEXT_PUBLIC_SUPABASE_URL=https://cgnmpfjcbhtgdcizgfnc.supabase.co
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImNnbm1wZmpjYmh0Z2RjaXpnZm5jIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MTY4NTkyNDIsImV4cCI6MjAzMjQzNTI0Mn0.oGf2jp-Twr1qP7GQI4D87iu5EWV6UhL51OEaCLvSMxk
|
12
.gitignore
vendored
12
.gitignore
vendored
@ -14,8 +14,16 @@ yarn-error.log*
|
||||
/.next
|
||||
|
||||
/data
|
||||
|
||||
/supabase/volumes/db/data/*
|
||||
#local env files
|
||||
.env*.local
|
||||
|
||||
/maildev
|
||||
/owncast
|
||||
/coverage
|
||||
/supabase/volumes/db/data
|
||||
/supabase/volumes/storage
|
||||
supabase.zip
|
||||
.idea/copilot/chatSessions/00000000000.xd
|
||||
.idea/copilot/chatSessions/blobs/version
|
||||
.idea/copilot/chatSessions/xd.lck
|
||||
.idea/workspace.xml
|
||||
|
5
.idea/.gitignore
generated
vendored
Normal file
5
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# GitHub Copilot persisted chat sessions
|
||||
/copilot/chatSessions
|
1
.idea/.name
generated
Normal file
1
.idea/.name
generated
Normal file
@ -0,0 +1 @@
|
||||
page.tsx
|
17
.idea/aws.xml
generated
Normal file
17
.idea/aws.xml
generated
Normal file
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="accountSettings">
|
||||
<option name="activeProfile" value="profile:default" />
|
||||
<option name="activeRegion" value="us-east-1" />
|
||||
<option name="recentlyUsedProfiles">
|
||||
<list>
|
||||
<option value="profile:default" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="recentlyUsedRegions">
|
||||
<list>
|
||||
<option value="us-east-1" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
4
.idea/encodings.xml
generated
Normal file
4
.idea/encodings.xml
generated
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding" addBOMForNewFiles="with BOM under Windows, with no BOM otherwise" />
|
||||
</project>
|
6
.idea/misc.xml
generated
Normal file
6
.idea/misc.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_22" default="true" project-jdk-name="openjdk-22" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/neroshitron.iml" filepath="$PROJECT_DIR$/.idea/neroshitron.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
11
.idea/neroshitron.iml
generated
Normal file
11
.idea/neroshitron.iml
generated
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.idea/copilot/chatSessions" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3
.vscode/extensions.json
vendored
Normal file
3
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"recommendations": ["denoland.vscode-deno"]
|
||||
}
|
10
.vscode/settings.json
vendored
Normal file
10
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"deno.enablePaths": [
|
||||
"supabase/functions"
|
||||
],
|
||||
"deno.lint": true,
|
||||
"deno.unstable": true,
|
||||
"[typescript]": {
|
||||
"editor.defaultFormatter": "vscode.typescript-language-features"
|
||||
}
|
||||
}
|
58
README.md
58
README.md
@ -1,12 +1,54 @@
|
||||
# Neroshitron
|
||||

|
||||

|
||||
|
||||
## Development
|
||||
### Documentation For Initial Project Setup
|
||||
- https://tamagui.dev/docs/guides/next-js
|
||||
|
||||
# Documentation For Technical Stack
|
||||
- https://nextjs.org/docs
|
||||
- https://supabase.com/docs/
|
||||
- https://owncast.online/docs/
|
||||
- https://docs.docker.com/engine/install/
|
||||
|
||||
# Running Backend
|
||||
You will need docker installed.
|
||||
- https://docs.docker.com/engine/install/
|
||||
|
||||
You will need supabase CLI.
|
||||
- https://docs.docker.com/engine/install/
|
||||
|
||||
You need npm and nodejs installed. See documentation at start of document.
|
||||
- https://docs.npmjs.com/downloading-and-installing-node-js-and-npm
|
||||
|
||||
1) Open your terminal and navigate to the root of the git repository.
|
||||
2) Make sure that docker and docker compose are installed.
|
||||
3) Run `docker-compose --env-file ./docker.env up` which will start up OwnCast.
|
||||
4) Run `supabase start`
|
||||
5) Open your terminal and navigate to the root folder of the git repository.
|
||||
6) Run the command `npm update`.
|
||||
7) Once the depedencies are pulled and installed you can run the command `npm run dev` to run the application in development mode.
|
||||
8) Open http://localhost:3000/
|
||||
|
||||
|
||||
|
||||
### Updating the database/Seeding data
|
||||
Run `supabase db reset`. This will wipe data.
|
||||
https://supabase.com/docs/guides/cli/local-development?queryGroups=access-method&access-method=kong#database-migrations
|
||||
|
||||
** Once the data is seeded you will need to go to the galleries bucket and add images to the folders that exist in it for the seeded galleries. **
|
||||
|
||||
|
||||
## inbucket
|
||||
http://localhost:54324su/monitor
|
||||
This is where all mail being sent shows up from the application for developers.
|
||||
|
||||
## OwnCast
|
||||
http://localhost:8080/
|
||||
Configuration is done through the Owncast administration page located on your server under /admin. The login username is admin and the password is your stream key, the default being abc123.
|
||||
|
||||
# User Flow Diagram
|
||||

|
||||
|
||||
# Database Diagram
|
||||

|
||||
|
||||
|
||||
### Setting Up For Development
|
||||
1) Open your terminal and navigate to the root folder of the git repository.
|
||||
2) Run the command `npm update`.
|
||||
3) Once the depedencies are pulled and installed you can run the command `npm run dev` to run the application in development mode.
|
||||
4) Open http://localhost:3000/
|
||||
|
4
app/_middleware.tsx
Normal file
4
app/_middleware.tsx
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
import { middleware } from './middleware/path-header'
|
||||
|
||||
export default middleware
|
41
app/admin/page.tsx
Normal file
41
app/admin/page.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
"use client";
|
||||
import { createClient } from "@/utils/supabase/client";
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
function PageComponent() {
|
||||
const supabase = createClient();
|
||||
const getData = async () => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
const router = useRouter();
|
||||
return (
|
||||
<div className="w-full text-white flex justify-center items-center animate-in">
|
||||
<div className="w-2/3 lg:w-1/3 rounded-md bg-primary p-8 mt-32 shadow-lg opacity-90 backdrop-blur-lg">
|
||||
<div className="w-full flex justify-center">
|
||||
<span className="text-2xl pb-4">System Settings</span>
|
||||
</div>
|
||||
<div className="flex justify-center ">
|
||||
<button onClick={()=>{ router.push("/admin/tiers") }} className="bg-secondary hover:bg-secondary-dark rounded p-2 mr-1 w-full">Tiers Management</button>
|
||||
<button onClick={()=>{ router.push("/gallery/admin") }} className="ml-1 bg-secondary hover:bg-secondary-dark rounded p-2 w-full">Gallery Management</button>
|
||||
|
||||
</div>
|
||||
<div className="flex justify-center pt-2">
|
||||
<button onClick={()=>{ router.push("/admin/theme") }} className="mr-1 bg-secondary hover:bg-secondary-dark rounded p-2 mr-1 w-full">Theme Settings</button>
|
||||
<button className="bg-secondary hover:bg-secondary-dark rounded p-2 ml-1 w-full">User Management</button>
|
||||
</div>
|
||||
<div className="flex justify-center pt-2">
|
||||
<button className="bg-secondary hover:bg-secondary-dark rounded p-2 w-full mr-1">Payment/Payout Settings</button>
|
||||
<button className="bg-secondary hover:bg-secondary-dark rounded p-2 w-full ml-1">Comissions Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PageComponent;
|
||||
|
||||
|
||||
|
474
app/admin/theme/page.tsx
Normal file
474
app/admin/theme/page.tsx
Normal file
@ -0,0 +1,474 @@
|
||||
"use client";
|
||||
import { createClient } from "@/utils/supabase/client";
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
function PageComponent() {
|
||||
const router = useRouter();
|
||||
const supabase = createClient();
|
||||
|
||||
const [primary, setPrimary] = useState('#201240');
|
||||
const [primaryLight, setPrimaryLight] = useState('#403260');
|
||||
const [primaryDark, setPrimaryDark] = useState('#100120');
|
||||
const [secondary, setSecondary] = useState('#4F3D70');
|
||||
const [secondaryLight, setSecondaryLight] = useState('#6F5D90');
|
||||
const [secondaryDark, setSecondaryDark] = useState('#2F1D50');
|
||||
const [error, setError] = useState('#862117');
|
||||
const [errorLight, setErrorLight] = useState('#C44C4C');
|
||||
const [errorDark, setErrorDark] = useState('#5C0D0D');
|
||||
const [changed, setChanged] = useState(false);
|
||||
const [success, setSuccess] = useState('#00C9A6');
|
||||
const [successLight, setSuccessLight] = useState('#20E9C6');
|
||||
const [successDark, setSuccessDark] = useState('#00A986');
|
||||
const [warning, setWarning] = useState('#E17558');
|
||||
const [warningLight, setWarningLight] = useState('#E39578');
|
||||
const [warningDark, setWarningDark] = useState('#C15538');
|
||||
const [info, setInfo] = useState('#222140');
|
||||
const [infoLight, setInfoLight] = useState('#424260');
|
||||
const [infoDark, setInfoDark] = useState('#020120');
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
const getData = async () => {
|
||||
var primaryConfig = await getColorConfig('primary');
|
||||
setPrimary(primaryConfig.value);
|
||||
var primaryLightConfig = await getColorConfig('primary-light');
|
||||
setPrimaryLight(primaryLightConfig.value);
|
||||
var primaryDarkConfig = await getColorConfig('primary-dark');
|
||||
setPrimaryDark(primaryDarkConfig.value);
|
||||
var secondaryConfig = await getColorConfig('secondary');
|
||||
setSecondary(secondaryConfig.value);
|
||||
var secondaryLightConfig = await getColorConfig('secondary-light');
|
||||
setSecondaryLight(secondaryLightConfig.value);
|
||||
var secondaryDarkConfig = await getColorConfig('secondary-dark');
|
||||
setSecondaryDark(secondaryDarkConfig.value);
|
||||
var errorConfig = await getColorConfig('error');
|
||||
setError(errorConfig.value);
|
||||
var errorLightConfig = await getColorConfig('error-light');
|
||||
setErrorLight(errorLightConfig.value);
|
||||
var errorDarkConfig = await getColorConfig('error-dark');
|
||||
setErrorDark(errorDarkConfig.value);
|
||||
var successConfig = await getColorConfig('success');
|
||||
setSuccess(successConfig.value);
|
||||
var successLightConfig = await getColorConfig('success-light');
|
||||
setSuccessLight(successLightConfig.value);
|
||||
var successDarkConfig = await getColorConfig('success-dark');
|
||||
setSuccessDark(successDarkConfig.value);
|
||||
var warningConfig = await getColorConfig('warning');
|
||||
setWarning(warningConfig.value);
|
||||
var warningLightConfig = await getColorConfig('warning-light');
|
||||
setWarningLight(warningLightConfig.value);
|
||||
var warningDarkConfig = await getColorConfig('warning-dark');
|
||||
setWarningDark(warningDarkConfig.value);
|
||||
var infoConfig = await getColorConfig('info');
|
||||
setInfo(infoConfig.value);
|
||||
var infoLightConfig = await getColorConfig('info-light');
|
||||
setInfoLight(infoLightConfig.value);
|
||||
var infoDarkConfig = await getColorConfig('info-dark');
|
||||
setInfoDark(infoDarkConfig.value);
|
||||
}
|
||||
|
||||
const getColorConfig = async (name: string) => {
|
||||
try {
|
||||
const response = await fetch(`/api/admin/interface-configs?name=${name}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to call GET request');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw new Error('Failed to call GET request');
|
||||
}
|
||||
}
|
||||
|
||||
const setColorConfig = async (name: string, value:string) => {
|
||||
try {
|
||||
const response = await fetch(`/api/admin/interface-configs`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ name, value }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to call GET request');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
throw new Error('Failed to call GET request');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const save = async () => {
|
||||
setSaving(true);
|
||||
await Promise.all([
|
||||
setColorConfig('primary', primary),
|
||||
setColorConfig('primary-light', primaryLight),
|
||||
setColorConfig('primary-dark', primaryDark),
|
||||
setColorConfig('secondary', secondary),
|
||||
setColorConfig('secondary-light', secondaryLight),
|
||||
setColorConfig('secondary-dark', secondaryDark),
|
||||
setColorConfig('error', error),
|
||||
setColorConfig('error-light', errorLight),
|
||||
setColorConfig('error-dark', errorDark),
|
||||
setColorConfig('success', success),
|
||||
setColorConfig('success-light', successLight),
|
||||
setColorConfig('success-dark', successDark),
|
||||
setColorConfig('warning', warning),
|
||||
setColorConfig('warning-light', warningLight),
|
||||
setColorConfig('warning-dark', warningDark),
|
||||
setColorConfig('info', info),
|
||||
setColorConfig('info-light', infoLight),
|
||||
setColorConfig('info-dark', infoDark)
|
||||
]);
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
|
||||
const colorChange = async ()=>{
|
||||
setChanged(true)
|
||||
document.documentElement.style.setProperty(`--color-primary`, primary);
|
||||
document.documentElement.style.setProperty(`--color-primary-light`, primaryLight);
|
||||
document.documentElement.style.setProperty(`--color-primary-dark`, primaryDark);
|
||||
document.documentElement.style.setProperty(`--color-secondary`, secondary);
|
||||
document.documentElement.style.setProperty(`--color-secondary-light`, secondaryLight);
|
||||
document.documentElement.style.setProperty(`--color-secondary-dark`, secondaryDark);
|
||||
document.documentElement.style.setProperty(`--color-error`, error);
|
||||
document.documentElement.style.setProperty(`--color-error-light`, errorLight);
|
||||
document.documentElement.style.setProperty(`--color-error-dark`, errorDark);
|
||||
document.documentElement.style.setProperty(`--color-success`, success);
|
||||
document.documentElement.style.setProperty(`--color-success-light`, successLight);
|
||||
document.documentElement.style.setProperty(`--color-success-dark`, successDark);
|
||||
document.documentElement.style.setProperty(`--color-warning`, warning);
|
||||
document.documentElement.style.setProperty(`--color-warning-light`, warningLight);
|
||||
document.documentElement.style.setProperty(`--color-warning-dark`, warningDark);
|
||||
document.documentElement.style.setProperty(`--color-info`, info);
|
||||
document.documentElement.style.setProperty(`--color-info-light`, infoLight);
|
||||
document.documentElement.style.setProperty(`--color-info-dark`, infoDark);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-5/6 h-1/2 text-white lg:flex justify-center items-center animate-in overflow-y-hidden">
|
||||
<div className=" w-5/6 md:w-4/6 lg:w-3/6 xl:w-2/6 rounded-md bg-primary opacity-90 p-12 m-1 mt-24 shadow-lg backdrop-blur">
|
||||
<div className="w-full relative">
|
||||
<span className="text-2xl pb-4">Color Settings</span>
|
||||
<button onClick={()=>{router.push("/admin")}} className={`float-right bg-error hover:bg-error-light ml-2 rounded p-2`}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor"
|
||||
className="md:hidden size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9 15 3 9m0 0 6-6M3 9h12a6 6 0 0 1 0 12h-3" />
|
||||
</svg>
|
||||
<span className="hidden md:block">Back</span>
|
||||
</button>
|
||||
<button onClick={save} disabled={!changed}
|
||||
className={`float-right ${changed ? "bg-success hover:bg-success-light" : "bg-success-dark"} rounded p-2`}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor"
|
||||
className="md:hidden size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="m4.5 12.75 6 6 9-13.5" />
|
||||
</svg>
|
||||
<span className="hidden md:block">{saving?"Saving...":"Save"}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div className="w-full relative">
|
||||
<label htmlFor="primaryInput">Primary Color</label>
|
||||
<div className="flex">
|
||||
<input
|
||||
value={primary}
|
||||
required
|
||||
type="text"
|
||||
className="w-full rounded-md rounded-r-none bg-info-bright p-2 text-black shadow-lg"
|
||||
onChange={(e) => { setPrimary(e.target.value); colorChange(); }}
|
||||
placeholder="Choose the primary color"
|
||||
/>
|
||||
<input
|
||||
value={primary}
|
||||
onChange={(e) => { setPrimary(e.target.value); colorChange(); }}
|
||||
required
|
||||
|
||||
type="color"
|
||||
className="w-10 h-10 rounded-r p-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full relative">
|
||||
<label htmlFor="primaryInput">Primary Light Color</label>
|
||||
<div className="flex">
|
||||
<input
|
||||
value={primaryLight}
|
||||
required
|
||||
type="text"
|
||||
className="w-full rounded-md rounded-r-none bg-info-bright p-2 text-black shadow-lg"
|
||||
onChange={(e) => { setPrimaryLight(e.target.value); colorChange(); }}
|
||||
placeholder="Choose the primary color"
|
||||
/>
|
||||
<input
|
||||
value={primaryLight}
|
||||
onChange={(e) => { setPrimaryLight(e.target.value); colorChange(); }}
|
||||
required
|
||||
|
||||
type="color"
|
||||
className="w-10 h-10 rounded-r p-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full relative">
|
||||
<label htmlFor="primaryInput">Primary Dark Color</label>
|
||||
<div className="flex">
|
||||
<input
|
||||
value={primaryDark}
|
||||
required
|
||||
type="text"
|
||||
className="w-full rounded-md rounded-r-none bg-info-bright p-2 text-black shadow-lg"
|
||||
onChange={(e) => { setPrimaryDark(e.target.value); colorChange(); }}
|
||||
placeholder="Choose the primary color"
|
||||
/>
|
||||
<input
|
||||
value={primaryDark}
|
||||
onChange={(e) => { setPrimaryDark(e.target.value); colorChange(); }}
|
||||
required
|
||||
|
||||
type="color"
|
||||
className="w-10 h-10 rounded-r p-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div className="w-full relative">
|
||||
<label htmlFor="primaryInput">Secondary Color</label>
|
||||
<div className="flex">
|
||||
<input
|
||||
value={secondary}
|
||||
required
|
||||
type="text"
|
||||
className="w-full rounded-md rounded-r-none bg-info-bright p-2 text-black shadow-lg"
|
||||
onChange={(e) => { setSecondary(e.target.value); colorChange(); }}
|
||||
placeholder="Choose the primary color"
|
||||
/>
|
||||
<input
|
||||
value={secondary}
|
||||
onChange={(e) => { setSecondary(e.target.value); colorChange(); }}
|
||||
required
|
||||
|
||||
type="color"
|
||||
className="w-10 h-10 rounded-r p-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full relative">
|
||||
<label htmlFor="primaryInput">Secondary Dark Color</label>
|
||||
<div className="flex">
|
||||
<input
|
||||
value={secondaryDark}
|
||||
required
|
||||
type="text"
|
||||
className="w-full rounded-md rounded-r-none bg-info-bright p-2 text-black shadow-lg"
|
||||
onChange={(e) => { setSecondaryDark(e.target.value); colorChange(); }}
|
||||
placeholder="Choose the primary color"
|
||||
/>
|
||||
<input
|
||||
value={secondaryDark}
|
||||
onChange={(e) => { setSecondaryDark(e.target.value); colorChange(); }}
|
||||
required
|
||||
|
||||
type="color"
|
||||
className="w-10 h-10 rounded-r p-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full relative">
|
||||
<label htmlFor="primaryInput">Secondary Light Color</label>
|
||||
<div className="flex">
|
||||
<input
|
||||
value={secondaryLight}
|
||||
required
|
||||
type="text"
|
||||
className="w-full rounded-md rounded-r-none bg-info-bright p-2 text-black shadow-lg"
|
||||
onChange={(e) => { setSecondaryLight(e.target.value); colorChange(); }}
|
||||
placeholder="Choose the primary color"
|
||||
/>
|
||||
<input
|
||||
value={secondaryLight}
|
||||
onChange={(e) => { setSecondaryLight(e.target.value); colorChange(); }}
|
||||
required
|
||||
|
||||
type="color"
|
||||
className="w-10 h-10 rounded-r p-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div className="w-full relative">
|
||||
<label htmlFor="primaryInput">Error Color</label>
|
||||
<div className="flex">
|
||||
<input
|
||||
value={error}
|
||||
required
|
||||
type="text"
|
||||
className="w-full rounded-md rounded-r-none bg-info-bright p-2 text-black shadow-lg"
|
||||
onChange={(e) => { setError(e.target.value); colorChange(); }}
|
||||
placeholder="Choose the primary color"
|
||||
/>
|
||||
<input
|
||||
value={error}
|
||||
onChange={(e) => { setError(e.target.value); colorChange(); }}
|
||||
required
|
||||
|
||||
type="color"
|
||||
className="w-10 h-10 rounded-r p-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full relative">
|
||||
<label htmlFor="primaryInput">Error Dark Color</label>
|
||||
<div className="flex">
|
||||
<input
|
||||
value={errorDark}
|
||||
required
|
||||
type="text"
|
||||
className="w-full rounded-md rounded-r-none bg-info-bright p-2 text-black shadow-lg"
|
||||
onChange={(e) => { setErrorDark(e.target.value); colorChange(); }}
|
||||
placeholder="Choose the primary color"
|
||||
/>
|
||||
<input
|
||||
value={errorDark}
|
||||
onChange={(e) => { setErrorDark(e.target.value); colorChange(); }}
|
||||
required
|
||||
|
||||
type="color"
|
||||
className="w-10 h-10 rounded-r p-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full relative">
|
||||
<label htmlFor="primaryInput">Error Light Color</label>
|
||||
<div className="flex">
|
||||
<input
|
||||
value={errorLight}
|
||||
required
|
||||
type="text"
|
||||
className="w-full rounded-md rounded-r-none bg-info-bright p-2 text-black shadow-lg"
|
||||
onChange={(e) => { setErrorLight(e.target.value); colorChange(); }}
|
||||
placeholder="Choose the primary color"
|
||||
/>
|
||||
<input
|
||||
value={errorLight}
|
||||
onChange={(e) => { setErrorLight(e.target.value); colorChange(); }}
|
||||
required
|
||||
|
||||
type="color"
|
||||
className="w-10 h-10 rounded-r p-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div className="w-full relative">
|
||||
<label htmlFor="primaryInput">Success Color</label>
|
||||
<div className="flex">
|
||||
<input
|
||||
value={success}
|
||||
required
|
||||
type="text"
|
||||
className="w-full rounded-md rounded-r-none bg-info-bright p-2 text-black shadow-lg"
|
||||
onChange={(e) => { setSuccess(e.target.value); colorChange(); }}
|
||||
placeholder="Choose the primary color"
|
||||
/>
|
||||
<input
|
||||
value={success}
|
||||
onChange={(e) => { setSuccess(e.target.value); colorChange(); }}
|
||||
required
|
||||
|
||||
type="color"
|
||||
className="w-10 h-10 rounded-r p-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full relative">
|
||||
<label htmlFor="primaryInput">Success Dark Color</label>
|
||||
<div className="flex">
|
||||
<input
|
||||
value={successDark}
|
||||
required
|
||||
type="text"
|
||||
className="w-full rounded-md rounded-r-none bg-info-bright p-2 text-black shadow-lg"
|
||||
onChange={(e) => { setSuccessDark(e.target.value); colorChange(); }}
|
||||
placeholder="Choose the primary color"
|
||||
/>
|
||||
<input
|
||||
value={successDark}
|
||||
onChange={(e) => { setSuccessDark(e.target.value); colorChange(); }}
|
||||
required
|
||||
|
||||
type="color"
|
||||
className="w-10 h-10 rounded-r p-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full relative">
|
||||
<label htmlFor="primaryInput">Success Light Color</label>
|
||||
<div className="flex">
|
||||
<input
|
||||
value={successLight}
|
||||
required
|
||||
type="text"
|
||||
className="w-full rounded-md rounded-r-none bg-info-bright p-2 text-black shadow-lg"
|
||||
onChange={(e) => { setSuccessLight(e.target.value); colorChange(); }}
|
||||
placeholder="Choose the primary color"
|
||||
/>
|
||||
<input
|
||||
value={successLight}
|
||||
onChange={(e) => { setSuccessLight(e.target.value); colorChange(); }}
|
||||
required
|
||||
|
||||
type="color"
|
||||
className="w-10 h-10 rounded-r p-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PageComponent;
|
||||
|
||||
|
||||
|
124
app/admin/tiers/create/page.tsx
Normal file
124
app/admin/tiers/create/page.tsx
Normal file
@ -0,0 +1,124 @@
|
||||
"use client";
|
||||
import { createClient } from "@/utils/supabase/client";
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
function PageComponent() {
|
||||
const supabase = createClient();
|
||||
const router = useRouter();
|
||||
const [name, setName] = useState<string>('');
|
||||
const [price, setPrice] = useState<number>(0);
|
||||
const [description, setDescription] = useState<string>('');
|
||||
const [color, setColor] = useState<string>('#000000');
|
||||
|
||||
const getData = async () => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const data = {
|
||||
name,
|
||||
price,
|
||||
color,
|
||||
description
|
||||
};
|
||||
const response = await fetch('/api/tiers', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const responseData = await response.json();
|
||||
window.location.href = "/admin/tiers";
|
||||
} else {
|
||||
console.log(response);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="w-full p-8 h-1/2 text-white lg:flex justify-center items-center animate-in">
|
||||
<div className="w-full lg:w-1/3 rounded-md bg-primary opacity-90 p-12 m-1 mt-32 shadow-lg backdrop-blur">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="w-full flex">
|
||||
<span className="text-2xl pb-4">Creating New Tier</span>
|
||||
</div>
|
||||
<div className="w-full flex">
|
||||
<input
|
||||
value={name}
|
||||
required
|
||||
type="text"
|
||||
onChange={(e) => { setName(e.target.value) }}
|
||||
className="mr-2 rounded-md bg-info-bright p-2 w-1/2 text-black shadow-lg"
|
||||
placeholder="Tag Name"
|
||||
/>
|
||||
<div className="flex border border-gray-300 w-1/2 rounded-md">
|
||||
<span className="flex items-center bg-gray-100 rounded-l-md border-r px-3 text-gray-500">
|
||||
$
|
||||
</span>
|
||||
<input
|
||||
value={price}
|
||||
onChange={(e) => { setPrice(Number(e.target.value)) }}
|
||||
required
|
||||
placeholder="Price in USD per month"
|
||||
type="number"
|
||||
className="flex-1 min-w-0 bg-info-bright rounded-r-md px-3 py-2 text-black focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full pt-2 justify-center flex">
|
||||
<textarea
|
||||
value={description}
|
||||
onChange={(e) => { setDescription(e.target.value) }}
|
||||
required
|
||||
placeholder="Description of the tier and what the user gets from subscribing."
|
||||
rows={3}
|
||||
className="w-full rounded-md bg-info-bright p-2 w-1/2 text-black shadow-lg"
|
||||
></textarea>
|
||||
</div>
|
||||
<div className="w-full pt-2 justify-center flex">
|
||||
<div className="w-1/2 relative">
|
||||
<input
|
||||
value={color}
|
||||
required
|
||||
type="text"
|
||||
className="w-full rounded-md bg-info-bright p-2 text-black shadow-lg"
|
||||
onChange={(e) => { setColor(e.target.value) }}
|
||||
placeholder="Choose the tiers color"
|
||||
/>
|
||||
<input
|
||||
value={color}
|
||||
onChange={(e) => { setColor(e.target.value) }}
|
||||
required
|
||||
id="colorInput"
|
||||
type="color"
|
||||
className="absolute right-0 top-0 w-10 h-full rounded-r p-1"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="submit"
|
||||
className="hover:scale-95 ml-2 shadow-lg w-1/2 h-10 text-center bg-success hover:bg-success-light text-white font-bold rounded flex items-center justify-center"
|
||||
>
|
||||
Create
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => { router.push("/admin/tiers") }}
|
||||
className="hover:scale-95 shadow-lg ml-2 w-1/2 h-10 text-center bg-error-dark hover:bg-error text-white font-bold rounded flex items-center justify-center"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PageComponent;
|
55
app/admin/tiers/page.tsx
Normal file
55
app/admin/tiers/page.tsx
Normal file
@ -0,0 +1,55 @@
|
||||
"use client";
|
||||
import { createClient } from "@/utils/supabase/client";
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
function PageComponent() {
|
||||
const router = useRouter();
|
||||
const supabase = createClient();
|
||||
const [tiers, setTiers] = useState<any[]>([]);
|
||||
const getData = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/tiers');
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setTiers(data);
|
||||
} else {
|
||||
console.error('failed to fetch tiers');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching users:', error);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-2/3 p-8 h-1/2 text-white lg:flex justify-center items-center animate-in">
|
||||
<div className="w-full lg:w-1/3 rounded-md bg-primary opacity-90 p-8 m-1 mt-32 shadow-lg backdrop-blur">
|
||||
<div className="w-full flex justify-center">
|
||||
<span className="text-2xl pb-4">Tiers Management</span>
|
||||
</div>
|
||||
<div className="w-full flex justify-center">
|
||||
<button onClick={() => { router.push("/admin/tiers/create") }} className="bg-success hover:bg-success-light rounded p-2 w-full">New Tier</button>
|
||||
<button onClick={() => { router.push("/admin") }} className="bg-error hover:bg-error-light rounded p-2 w-full ml-2">Back</button>
|
||||
</div>
|
||||
<div className="w-full justify-center pt-8">
|
||||
{tiers.map((item, index) => (
|
||||
<div className="w-full flex justify-center">
|
||||
<div key={index} className="text-white w-full text-stroke mt-2">
|
||||
<button onClick={() => { router.push("/admin/tiers/view?name=" + item.name) }} className="py-2 w-full rounded hover:scale-105" style={{ backgroundColor: item.color }}>{item.name} - ${item.price}/month</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PageComponent;
|
||||
|
||||
|
||||
|
141
app/admin/tiers/view/page.tsx
Normal file
141
app/admin/tiers/view/page.tsx
Normal file
@ -0,0 +1,141 @@
|
||||
"use client";
|
||||
import { createClient } from "@/utils/supabase/client";
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
function PageComponent() {
|
||||
const router = useRouter();
|
||||
const supabase = createClient();
|
||||
const [tier, setTier] = useState<any[]>([]);
|
||||
const [users, setUsers] = useState<any[]>([]);
|
||||
const [name, setName] = useState<string>('');
|
||||
const [price, setPrice] = useState<number>(0);
|
||||
const [description, setDescription] = useState<string>('');
|
||||
const [color, setColor] = useState<string>('#000000');
|
||||
const getData = async () => {
|
||||
try {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const name = searchParams.get('name');
|
||||
const response = await fetch('/api/tiers/'+name);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setTier(data);
|
||||
setName(data.name);
|
||||
setPrice(data.price);
|
||||
setDescription(data.description);
|
||||
setColor(data.color);
|
||||
} else {
|
||||
console.error('failed to fetch tiers');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching users:', error);
|
||||
}
|
||||
}
|
||||
|
||||
const handleSubmit = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const data = {
|
||||
newName:name,
|
||||
price,
|
||||
color,
|
||||
description
|
||||
};
|
||||
const response = await fetch('/api/tiers/'+name, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const responseData = await response.json();
|
||||
window.location.href = "/admin/tiers";
|
||||
} else {
|
||||
console.log(response);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="w-full p-8 h-1/2 text-white lg:flex justify-center items-center animate-in">
|
||||
<div className="w-full lg:w-1/3 rounded-md bg-primary opacity-90 p-12 m-1 mt-32 shadow-lg backdrop-blur">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="w-full flex">
|
||||
<span className="text-2xl pb-4">Editing Existing Tier</span>
|
||||
</div>
|
||||
<div className="w-full flex">
|
||||
<input
|
||||
value={name}
|
||||
required
|
||||
type="text"
|
||||
onChange={(e) => { setName(e.target.value) }}
|
||||
className="mr-2 rounded-md bg-info-bright p-2 w-1/2 text-black shadow-lg"
|
||||
placeholder="Tag Name"
|
||||
/>
|
||||
<div className="flex border border-gray-300 w-1/2 rounded-md">
|
||||
<span className="flex items-center bg-gray-100 rounded-l-md border-r px-3 text-gray-500">
|
||||
$
|
||||
</span>
|
||||
<input
|
||||
value={price}
|
||||
onChange={(e) => { setPrice(Number(e.target.value)) }}
|
||||
required
|
||||
placeholder="Price in USD per month"
|
||||
type="number"
|
||||
className="flex-1 min-w-0 bg-info-bright rounded-r-md px-3 py-2 text-black focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full pt-2 justify-center flex">
|
||||
<textarea
|
||||
value={description}
|
||||
onChange={(e) => { setDescription(e.target.value) }}
|
||||
required
|
||||
placeholder="Description of the tier and what the user gets from subscribing."
|
||||
rows={3}
|
||||
className="w-full rounded-md bg-info-bright p-2 w-1/2 text-black shadow-lg"
|
||||
></textarea>
|
||||
</div>
|
||||
<div className="w-full pt-2 justify-center flex">
|
||||
<div className="w-1/2 relative">
|
||||
<input
|
||||
value={color}
|
||||
required
|
||||
type="text"
|
||||
className="w-full rounded-md bg-info-bright p-2 text-black shadow-lg"
|
||||
onChange={(e) => { setColor(e.target.value) }}
|
||||
placeholder="Choose the tiers color"
|
||||
/>
|
||||
<input
|
||||
value={color}
|
||||
onChange={(e) => { setColor(e.target.value) }}
|
||||
required
|
||||
id="colorInput"
|
||||
type="color"
|
||||
className="absolute right-0 top-0 w-10 h-full rounded-r p-1"
|
||||
/>
|
||||
</div>
|
||||
<button onClick={() => { }} className="hover:scale-95 shadow-lg ml-2 w-1/2 h-10 text-center bg-warning hover:bg-warning-light text-white font-bold rounded flex items-center justify-center">
|
||||
Update
|
||||
</button>
|
||||
<button type="button" onClick={() => { }} className="hover:scale-95 shadow-lg ml-2 w-1/2 h-10 text-center bg-error hover:bg-error-light text-white font-bold rounded flex items-center justify-center">
|
||||
Delete
|
||||
</button>
|
||||
<button type="button" onClick={() => { router.push("/admin/tiers") }} className="hover:scale-95 shadow-lg ml-2 w-1/2 h-10 text-center bg-error-dark hover:bg-error text-white font-bold rounded flex items-center justify-center">
|
||||
Back
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PageComponent;
|
||||
|
||||
|
||||
|
26
app/api/admin/interface-configs/route.tsx
Normal file
26
app/api/admin/interface-configs/route.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
|
||||
export async function PUT(request: Request) {
|
||||
const body = await request.json();
|
||||
console.log(body)
|
||||
const supabase = createClient();
|
||||
var value = body.value;
|
||||
const { error } = await supabase.from('interface_configurations').update({ value }).eq('name', body.name);
|
||||
console.log(error)
|
||||
if (error) {
|
||||
return NextResponse.error();
|
||||
}
|
||||
return NextResponse.json({});
|
||||
}
|
||||
|
||||
export async function GET(request: Request) {
|
||||
|
||||
const url = new URL(request.url as string, 'http://localhost');
|
||||
const name = url.searchParams.get('name') || '';
|
||||
const supabase = createClient();
|
||||
const { data, error } = await supabase.from('interface_configurations').select('*').eq('name', name).single();
|
||||
return NextResponse.json(data);
|
||||
}
|
17
app/api/admin/users/route.tsx
Normal file
17
app/api/admin/users/route.tsx
Normal file
@ -0,0 +1,17 @@
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
try {
|
||||
const supabase = createClient();
|
||||
const { data, error } = await supabase.auth.admin.listUsers();
|
||||
console.log(error)
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
return NextResponse.json(data);
|
||||
} catch (error) {
|
||||
return NextResponse.error();
|
||||
}
|
||||
}
|
27
app/api/galleries/[id]/images/count/route.ts
Normal file
27
app/api/galleries/[id]/images/count/route.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: { id: string } }
|
||||
) {
|
||||
const galleryId = params.id;
|
||||
const supabase = createClient();
|
||||
|
||||
const { data: gallery, error: galleryError } = await supabase
|
||||
.from('galleries')
|
||||
.select('*')
|
||||
.eq('name', galleryId)
|
||||
.single();
|
||||
// List all files in the galleryId path
|
||||
let { data: files, error } = await supabase.storage.from('galleries').list(params.id.toLowerCase().replace(/\s+/g, '_'));
|
||||
|
||||
if (files==null || error) {
|
||||
//console.error('Error listing files:', error);
|
||||
return NextResponse.error();
|
||||
}
|
||||
|
||||
|
||||
// Return a JSON response with the array of URLs
|
||||
return new Response(JSON.stringify(files.length), { headers: { 'content-type': 'application/json' } });
|
||||
}
|
34
app/api/galleries/[id]/images/names/route.ts
Normal file
34
app/api/galleries/[id]/images/names/route.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: { id: string } }
|
||||
) {
|
||||
const galleryId = params.id;
|
||||
const supabase = createClient();
|
||||
|
||||
const { data: gallery, error: galleryError } = await supabase
|
||||
.from('galleries')
|
||||
.select('*')
|
||||
.eq('name', galleryId)
|
||||
.single();
|
||||
|
||||
// List all files in the galleryId path
|
||||
let { data: files, error } = await supabase.storage
|
||||
.from('galleries')
|
||||
.list(params.id.toLowerCase().replace(/\s+/g, '_'));
|
||||
|
||||
if (files == null || error) {
|
||||
//console.error('Error listing files:', error);
|
||||
return NextResponse.error();
|
||||
}
|
||||
|
||||
// Extract file names from the list of files
|
||||
const fileNames = files.map((file) => file.name);
|
||||
|
||||
// Return a JSON response with the array of file names
|
||||
return new Response(JSON.stringify(fileNames), {
|
||||
headers: { 'content-type': 'application/json' },
|
||||
});
|
||||
}
|
84
app/api/galleries/[id]/images/route.ts
Normal file
84
app/api/galleries/[id]/images/route.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import sharp from 'sharp';
|
||||
|
||||
|
||||
async function blurImage(blob: Buffer): Promise<Buffer> {
|
||||
// Convert the blob to a sharp object
|
||||
const image = sharp(blob);
|
||||
|
||||
// Blur the image
|
||||
const blurredImage = await image.blur(75).toBuffer();
|
||||
|
||||
return blurredImage;
|
||||
}
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: { id: string } }
|
||||
) {
|
||||
|
||||
const galleryId = params.id; const supabase = createClient();
|
||||
const user = await supabase.auth.getUser();
|
||||
|
||||
|
||||
const { data: gallery, error: galleryError } = await supabase
|
||||
.from('galleries')
|
||||
.select('*')
|
||||
.eq('name', params.id)
|
||||
.single();
|
||||
|
||||
// List all files in the params.id path
|
||||
let { data: files, error } = await supabase.storage.from('galleries').list(galleryId);
|
||||
|
||||
if (files==null || error) {
|
||||
//console.error('Error listing files:', error);
|
||||
return NextResponse.error();
|
||||
}
|
||||
|
||||
const urls = [];
|
||||
|
||||
// Loop through each file, download it, convert it to base64, and add the data URL to the array
|
||||
for (const file of files) {
|
||||
let { data: blobdata, error } = await supabase.storage.from('galleries').download(galleryId+"/"+file.name);
|
||||
|
||||
if (error || blobdata==null) {
|
||||
//console.error('Error downloading file:', error);
|
||||
continue;
|
||||
}
|
||||
let blobBuffer = Buffer.from(await blobdata.arrayBuffer());
|
||||
|
||||
let userId = user.data.user?.id;
|
||||
let { data: subscription, error: rolesError } = await supabase
|
||||
.from('user_subscriptions')
|
||||
.select('*')
|
||||
.eq('user_id', userId)
|
||||
.single();
|
||||
switch(gallery.tier){
|
||||
case "Tier 3":
|
||||
if(subscription?.tier!="Tier 3"){
|
||||
blobBuffer = await blurImage(blobBuffer);
|
||||
}
|
||||
break;
|
||||
case "Tier 2":
|
||||
if(subscription?.tier!="Tier 3" && subscription?.tier!="Tier 2"){
|
||||
blobBuffer = await blurImage(blobBuffer);
|
||||
}
|
||||
break;
|
||||
case "Tier 1":
|
||||
if(subscription?.tier!="Tier 3" && subscription?.tier!="Tier 2" && subscription?.tier!="Tier 1"){
|
||||
blobBuffer = await blurImage(blobBuffer);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const contentType = file.name.endsWith('.png') ? 'image/png' : 'image/jpeg';
|
||||
const dataUrl = `data:${contentType};base64,${blobBuffer.toString('base64')}`;
|
||||
|
||||
urls.push(dataUrl);
|
||||
}
|
||||
|
||||
// Return a JSON response with the array of URLs
|
||||
return new Response(JSON.stringify(urls), { headers: { 'content-type': 'application/json' } });
|
||||
}
|
64
app/api/galleries/[id]/thumbnail/route.ts
Normal file
64
app/api/galleries/[id]/thumbnail/route.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import sharp from 'sharp';
|
||||
|
||||
|
||||
async function blurImage(blob: Buffer): Promise<Buffer> {
|
||||
// Convert the blob to a sharp object
|
||||
const image = sharp(blob);
|
||||
|
||||
// Blur the image
|
||||
const blurredImage = await image.blur(75).toBuffer();
|
||||
|
||||
return blurredImage;
|
||||
}
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: { id: string } }
|
||||
) {
|
||||
const supabase = createClient();
|
||||
const user = await supabase.auth.getUser();
|
||||
const url = new URL(request.url);
|
||||
const search = url.searchParams.get("nsfw");
|
||||
const nsfw = search === "true";
|
||||
|
||||
const { data: gallery, error: galleryError } = await supabase
|
||||
.from('galleries')
|
||||
.select('*')
|
||||
.eq('name', params.id)
|
||||
.single();
|
||||
|
||||
var thumbnailFile = gallery.thumbnail_file;
|
||||
if(thumbnailFile==null || thumbnailFile==""){
|
||||
let { data: files, error } = await supabase.storage.from('galleries').list(params.id);
|
||||
if (files == null || files?.length == 0) {
|
||||
return NextResponse.error();
|
||||
}
|
||||
thumbnailFile = files[0].name;
|
||||
}
|
||||
|
||||
// Loop through each file, download it, convert it to base64, and add the data URL to the array
|
||||
let { data: blobdata, error: fileError } = await supabase.storage.from('galleries').download(params.id + "/" + thumbnailFile);
|
||||
if (fileError || blobdata == null) {
|
||||
//console.error('Error downloading file:', error);
|
||||
return NextResponse.error();
|
||||
}
|
||||
let blobBuffer = Buffer.from(await blobdata.arrayBuffer());
|
||||
|
||||
let userId = user.data.user?.id;
|
||||
let { data: subscription, error: rolesError } = await supabase
|
||||
.from('user_subscriptions')
|
||||
.select('*')
|
||||
.eq('user_id', userId)
|
||||
.single();
|
||||
if(nsfw && gallery.nsfw){
|
||||
blobBuffer = await blurImage(blobBuffer);
|
||||
}
|
||||
const contentType = thumbnailFile.endsWith('.png') ? 'image/png' : 'image/jpeg';
|
||||
const dataUrl = `data:${contentType};base64,${blobBuffer.toString('base64')}`;
|
||||
|
||||
|
||||
// Return a JSON response with the array of URLs
|
||||
return new Response(dataUrl);
|
||||
}
|
110
app/api/galleries/admin/[id]/route.ts
Normal file
110
app/api/galleries/admin/[id]/route.ts
Normal file
@ -0,0 +1,110 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import path from 'path';
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: { id: string } }
|
||||
) {
|
||||
const id = params.id;
|
||||
const supabase = createClient();
|
||||
const { data: gallery, error } = await supabase.from('galleries').select("*").eq('name', id).single();
|
||||
return NextResponse.json({ gallery });
|
||||
}
|
||||
|
||||
|
||||
|
||||
export async function PUT(
|
||||
request: Request,
|
||||
{ params }: { params: { id: string } }){
|
||||
|
||||
const supabase = createClient();
|
||||
const formData = await request.formData();
|
||||
const tags = JSON.parse(formData.getAll('tags').toString()) as string[];
|
||||
const originalName = formData.get('originalName');
|
||||
const name = formData.get('name')?.toString();
|
||||
const nsfw = formData.get('nsfw')?.toString();
|
||||
const tier = formData.get('tier')?.toString();
|
||||
const thumbnail = formData.get('thumbnail');
|
||||
|
||||
const { error } = await supabase.from('galleries').update({name, tags, nsfw, tier, thumbnail_file:thumbnail}).eq('name', originalName ?? '');
|
||||
|
||||
async function renameFolder(oldFolderName: any, newFolderName: string) {
|
||||
// Get a list of all files in the old folder
|
||||
let { data: oldFiles, error } = await supabase.storage.from('galleries').list(oldFolderName);
|
||||
if (error) {
|
||||
console.error('Error fetching files:', error);
|
||||
return;
|
||||
}
|
||||
|
||||
// Move each file to the new folder
|
||||
if (oldFiles) {
|
||||
for (let file of oldFiles) {
|
||||
let oldPath = file.name;
|
||||
let newPath = newFolderName + '/' + oldPath.split('/').pop();
|
||||
|
||||
let { error: moveError } = await supabase.storage.from('galleries').move(oldPath, newPath);
|
||||
if (moveError) {
|
||||
console.error(`Error moving file ${oldPath} to ${newPath}:`, moveError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the old folder
|
||||
let { error: deleteError } = await supabase.storage.from('galleries').remove([oldFolderName]);
|
||||
if (deleteError) {
|
||||
console.error('Error deleting old folder:', deleteError);
|
||||
}
|
||||
}
|
||||
|
||||
renameFolder(originalName, name ?? '');
|
||||
|
||||
if(error){
|
||||
return NextResponse.error();
|
||||
}
|
||||
let { data: galleries, error:galleriesError } = await supabase
|
||||
.from('galleries')
|
||||
.select('*');
|
||||
return NextResponse.json({ success: true, galleries });
|
||||
}
|
||||
|
||||
|
||||
export async function DELETE(
|
||||
request: Request,
|
||||
{ params }: { params: { id: string } }
|
||||
) {
|
||||
const id =params.id;
|
||||
const supabase = createClient();
|
||||
const { data: gallery, error } = await supabase.from('galleries').delete().eq('name', id).single();
|
||||
let { data: galleries, error:galleriesError } = await supabase
|
||||
.from('galleries')
|
||||
.select('*');
|
||||
return NextResponse.json({ success: true, galleries });
|
||||
}
|
||||
|
||||
// const tagsResponse = await fetch(`/api/galleries/tags?search=${search}`);
|
||||
// const tagsData = await tagsResponse.json();
|
||||
// const galleriesWithTagData = galleriesData.map((gallery: any) => {
|
||||
// const tags = tagsData.filter((tag: any) => gallery.tags.includes(tag.name));
|
||||
// return { ...gallery, tags };
|
||||
// });
|
||||
|
||||
|
||||
// const formData = new FormData();
|
||||
// formData.append('name', name);
|
||||
// formData.append('tags', JSON.stringify(tags));
|
||||
// files.forEach((file: File) => {
|
||||
// formData.append('files', file);
|
||||
// });
|
||||
|
||||
// const response = await fetch('/api/galleries', {
|
||||
// method: 'POST',
|
||||
// body: formData,
|
||||
// });
|
||||
|
||||
// if (response.ok) {
|
||||
// const data = await response.json();
|
||||
// // Handle success
|
||||
// } else {
|
||||
// // Handle error
|
||||
// }
|
37
app/api/galleries/admin/route.ts
Normal file
37
app/api/galleries/admin/route.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import path from 'path';
|
||||
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const supabase = createClient();
|
||||
let { data: galleries, error } = await supabase
|
||||
.from('galleries')
|
||||
.select('*');
|
||||
return NextResponse.json(galleries);
|
||||
}
|
||||
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const supabase = createClient();
|
||||
const formData = await request.formData();
|
||||
const files = formData.getAll('files');
|
||||
const tags = JSON.parse(formData.getAll('tags').toString()) as string[];
|
||||
const name = formData.get('name');
|
||||
const nsfw = formData.get('nsfw');
|
||||
const tier = formData.get('tier');
|
||||
const thumbnail = formData.get('thumbnail');
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i] as File; // Cast 'file' to 'File' type
|
||||
supabase.storage.from('galleries').upload(`${name}/${file.name}`, file);
|
||||
}
|
||||
const { data: gallery, error } = await supabase.from('galleries').insert({ name, tags, nsfw, thumbnail_file:thumbnail, tier, column_number: 3 }).single();
|
||||
|
||||
let { data: galleries, error: galleriesError } = await supabase
|
||||
.from('galleries')
|
||||
.select('*');
|
||||
|
||||
return NextResponse.json({ success: true, galleries });
|
||||
}
|
||||
|
35
app/api/galleries/route.ts
Normal file
35
app/api/galleries/route.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const supabase = createClient();
|
||||
const url = new URL(request.url);
|
||||
const search = url.searchParams.get("search");
|
||||
const data = await request.json();
|
||||
const tags = data.tags as string[];
|
||||
if(tags.length === 0){
|
||||
let { data: galleries, error } = await supabase
|
||||
.from('galleries')
|
||||
.select('*')
|
||||
.ilike('name', `%${search}%`)
|
||||
return NextResponse.json(galleries);
|
||||
}
|
||||
else{
|
||||
// Rest of the code...
|
||||
let { data: galleries, error } = await supabase
|
||||
.from('galleries')
|
||||
.select('*')
|
||||
.contains('tags', tags) // Fix: Use contains instead of overlaps
|
||||
.ilike('name', `%${search}%`)
|
||||
|
||||
return NextResponse.json(galleries);
|
||||
}
|
||||
}
|
||||
|
||||
// const tagsResponse = await fetch(`/api/galleries/tags?search=${search}`);
|
||||
// const tagsData = await tagsResponse.json();
|
||||
// const galleriesWithTagData = galleriesData.map((gallery: any) => {
|
||||
// const tags = tagsData.filter((tag: any) => gallery.tags.includes(tag.name));
|
||||
// return { ...gallery, tags };
|
||||
// });
|
32
app/api/galleries/tags/route.ts
Normal file
32
app/api/galleries/tags/route.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const supabase = createClient();
|
||||
let { data: tags, error } = await supabase
|
||||
.from('tags')
|
||||
.select('*')
|
||||
.order('name', { ascending: true });
|
||||
return NextResponse.json(tags)
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const supabase = createClient();
|
||||
const data = await request.json();
|
||||
const { data: tag, error } = await supabase.from('tags').insert({ name: data.tag }).single();
|
||||
if (error) {
|
||||
return NextResponse.error();
|
||||
}
|
||||
return NextResponse.json(tag);
|
||||
}
|
||||
|
||||
export async function PUT(request: Request) {
|
||||
const supabase = createClient();
|
||||
const data = await request.json();
|
||||
const { data: tag, error } = await supabase.from('tags').delete().eq('name', data.tag).single();
|
||||
if (error) {
|
||||
return NextResponse.error();
|
||||
}
|
||||
return NextResponse.json(tag);
|
||||
}
|
36
app/api/tiers/[name]/route.ts
Normal file
36
app/api/tiers/[name]/route.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
|
||||
export async function GET(
|
||||
request: Request,
|
||||
{ params }: { params: { name: string } }
|
||||
) {
|
||||
const supabase = createClient();
|
||||
|
||||
const { data: tier, error: galleryError } = await supabase
|
||||
.from('tiers')
|
||||
.select('*')
|
||||
.eq('name', params.name)
|
||||
.single();
|
||||
|
||||
if(galleryError) {
|
||||
return NextResponse.error();
|
||||
}
|
||||
|
||||
return NextResponse.json(tier);
|
||||
}
|
||||
export async function PUT(
|
||||
request: Request,
|
||||
{ params }: { params: { name: string } }
|
||||
) {
|
||||
const supabase = createClient();
|
||||
const { newName, price, color, description } = await request.json();
|
||||
console.log(newName)
|
||||
const { error } = await supabase.from('tiers')
|
||||
.update({ name:newName, price, color, description }).eq('name', params.name);
|
||||
if (error) {
|
||||
console.error('Error updating tier:', error);
|
||||
return NextResponse.error();
|
||||
}
|
||||
return NextResponse.json({});
|
||||
}
|
26
app/api/tiers/route.ts
Normal file
26
app/api/tiers/route.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const supabase = createClient();
|
||||
const { data, error } = await supabase.from('tiers').select('*');
|
||||
if (error) {
|
||||
console.error('Error fetching tiers:', error);
|
||||
return NextResponse.error();
|
||||
}
|
||||
const tiers = data ?? [];
|
||||
return NextResponse.json(tiers);
|
||||
}
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const supabase = createClient();
|
||||
const { name, price, color, description } = await request.json();
|
||||
const { data, error } = await supabase.from('tiers').insert([{ name, price, color, description }]);
|
||||
if (error) {
|
||||
console.error('Error inserting tier:', error);
|
||||
return NextResponse.error();
|
||||
}
|
||||
return NextResponse.json(data);
|
||||
}
|
||||
|
19
app/auth/callback/route.ts
Normal file
19
app/auth/callback/route.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
// The `/auth/callback` route is required for the server-side auth flow implemented
|
||||
// by the SSR package. It exchanges an auth code for the user's session.
|
||||
// https://supabase.com/docs/guides/auth/server-side/nextjs
|
||||
const requestUrl = new URL(request.url);
|
||||
const code = requestUrl.searchParams.get("code");
|
||||
const origin = requestUrl.origin;
|
||||
|
||||
if (code) {
|
||||
const supabase = createClient();
|
||||
await supabase.auth.exchangeCodeForSession(code);
|
||||
}
|
||||
|
||||
// URL to redirect to after sign up process completes
|
||||
return NextResponse.redirect(`${origin}/protected`);
|
||||
}
|
20
app/commissions/page.tsx
Normal file
20
app/commissions/page.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default async function Commissions() {
|
||||
const supabase = createClient();
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
|
||||
if (!user) {
|
||||
return redirect("/login");
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex-1 w-full flex flex-col gap-20 items-center animate-in">
|
||||
<h1>This is protected.</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
BIN
app/favicon.ico
Normal file
BIN
app/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
168
app/gallery/admin/create/page.tsx
Normal file
168
app/gallery/admin/create/page.tsx
Normal file
@ -0,0 +1,168 @@
|
||||
"use client";
|
||||
import { createClient } from "@/utils/supabase/client";
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import Masonry from "react-masonry-css";
|
||||
import SearchInput from "@/components/neroshitron/search_input";
|
||||
|
||||
function PageComponent() {
|
||||
const router = useRouter();
|
||||
const [selectedGallery, setSelectedGallery] = useState<string | null>(null);
|
||||
const [filePreviews, setFilePreviews] = useState<string[]>([]);
|
||||
const [name, setName] = useState<string>('');
|
||||
const [nsfw, setNsfw] = useState<boolean>(false);
|
||||
const [tags, setTags] = useState<string[]>([]);
|
||||
const [tier, setTier] = useState<string>('Free');
|
||||
const [thumbnail, setThumbnail] = useState<string>("");
|
||||
const [files, setFiles] = useState<FileList>();
|
||||
|
||||
const [tiers, setTiers] = useState<any[]>([]);
|
||||
const supabase = createClient();
|
||||
const user = supabase.auth.getUser();
|
||||
const getData = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/tiers');
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setTiers(data);
|
||||
} else {
|
||||
console.error('failed to fetch tiers');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching users:', error);
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, [selectedGallery]);
|
||||
|
||||
const closeGallery = () => {
|
||||
setSelectedGallery(null);
|
||||
}
|
||||
|
||||
const createGallery = async () => {
|
||||
const formData = new FormData();
|
||||
formData.append('name', name);
|
||||
if (files) {
|
||||
Array.from(files).forEach((file: File) => {
|
||||
formData.append('files', file);
|
||||
});
|
||||
}
|
||||
formData.append('tags', JSON.stringify(tags));
|
||||
formData.append('nsfw', nsfw.toString());
|
||||
formData.append('thumbnail', thumbnail);
|
||||
formData.append('tier', tier);
|
||||
const response = await fetch('/api/galleries/admin', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
window.location.href = "/gallery/admin/view?id="+name;
|
||||
} else {
|
||||
console.log(response)
|
||||
}
|
||||
}
|
||||
|
||||
const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const files = event.target.files;
|
||||
if (files) {
|
||||
const previews: string[] = [];
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files[i];
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
if (e.target && e.target.result) {
|
||||
previews.push(e.target.result.toString());
|
||||
if (previews.length === files.length) {
|
||||
setFiles(files);
|
||||
setFilePreviews(previews);
|
||||
}
|
||||
}
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="w-full p-8 text-white flex justify-center items-center animate-in">
|
||||
<div className="w-full lg:w-1/2 rounded-md bg-primary opacity-90 backdrop-blur-lg p-12 mt-32 shadow-lg">
|
||||
<div className="w-full flex pb-4">
|
||||
<span className="text-2xl">Creating New Gallery</span>
|
||||
</div>
|
||||
<div className="w-full flex">
|
||||
<input
|
||||
type="text"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
className="mb-8 mr-2 rounded-md bg-secondary p-2 w-1/2 text-white shadow-lg"
|
||||
placeholder="Gallery Name"
|
||||
/>
|
||||
<div className="w-1/4">
|
||||
<button onClick={() => router.push("/gallery/admin")} className="w-full bg-error hover:bg-error-light text-white rounded-md p-2 shadow-lg">
|
||||
Back
|
||||
</button>
|
||||
</div>
|
||||
<div className="w-1/4">
|
||||
<button onClick={()=>{createGallery()}} className="w-full bg-success hover:bg-success-light text-white rounded-md p-2 ml-2 shadow-lg ">
|
||||
<span></span>Create
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full lg:flex">
|
||||
<div className="w-full lg:w-1/2">
|
||||
<div className="w-1/2 absolute pr-14">
|
||||
<SearchInput
|
||||
placeholderTags={[
|
||||
{ value: "tags", label: "❗️ click here to add tags" },
|
||||
]}
|
||||
startingTags={tags}
|
||||
nsfwButtonEnabled={true}
|
||||
searchChanged={(search) => { }}
|
||||
nsfwChanged={(nsfw) => { }}
|
||||
tagsChanged={(tags) => { setTags(tags) }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full lg:w-1/2 lg:pt-0 pt-4">
|
||||
<select value={nsfw ? "NSFW" : "SFW"} className="mb-2 shadow-lg rounded-md bg-secondary p-2 w-full text-white" onChange={e=>{
|
||||
setNsfw(e.target.value === "NSFW");
|
||||
}}>
|
||||
<option value="NSFW" selected={nsfw}>NSFW</option>
|
||||
<option value="SFW" selected={nsfw}>SFW</option>
|
||||
</select>
|
||||
<select onChange={e=>{
|
||||
setTier(e.target.value);
|
||||
}} className="mb-2 shadow-lg mr-2 rounded-md bg-secondary p-2 w-full text-white">
|
||||
<option value="" disabled >Select New Tier</option>
|
||||
{tiers.map((tier, index) => (
|
||||
<option key={index} value={tier.name}>{tier.name}</option>
|
||||
))}
|
||||
</select>
|
||||
<select onChange={e=>{setThumbnail(e.target.value)}} className="mb-2 shadow-lg mr-2 rounded-md bg-secondary p-2 w-full text-white">
|
||||
<option value="" disabled selected>Select Thumbnail</option>
|
||||
{files && Array.from(files).map((file: File, index: number) => (
|
||||
<option key={index} value={file.name}>{file.name}</option>
|
||||
))}
|
||||
</select>
|
||||
<input
|
||||
className="relative m-0 block w-full min-w-0 flex-auto cursor-pointer rounded border border-solid border-secondary-lighter bg-transparent bg-clip-padding px-3 py-[0.32rem] text-base font-normal text-surface transition duration-300 ease-in-out file:-mx-3 file:-my-[0.32rem] file:me-3 file:cursor-pointer file:overflow-hidden file:rounded-none file:border-0 file:border-e file:border-solid file:border-inherit file:bg-transparent file:px-3 file:py-[0.32rem] file:text-surface focus:border-primary focus:text-gray-700 focus:shadow-inset focus:outline-none dark:border-white/70 dark:text-white file:dark:text-white"
|
||||
type="file"
|
||||
id="formFileMultiple"
|
||||
multiple
|
||||
onChange={handleFileChange}
|
||||
/>
|
||||
<Masonry breakpointCols={3} className="my-masonry-grid pl-6 col-span-2">
|
||||
{filePreviews.map((preview, index) => (
|
||||
<img key={index} src={preview} alt={`Preview ${index}`} />
|
||||
))}
|
||||
</Masonry>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default PageComponent;
|
161
app/gallery/admin/page.tsx
Normal file
161
app/gallery/admin/page.tsx
Normal file
@ -0,0 +1,161 @@
|
||||
"use client";
|
||||
import { createClient } from "@/utils/supabase/client";
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import SearchInput from "@/components/neroshitron/search_input";
|
||||
import { useRouter } from 'next/navigation';
|
||||
|
||||
function PageComponent() {
|
||||
const router = useRouter();
|
||||
const supabase = createClient();
|
||||
const user = supabase.auth.getUser();
|
||||
const [tags, setTags] = useState<any[]>([]);
|
||||
const [nsfwState, setNsfwState] = useState<boolean>(false);
|
||||
const [tagsState, setTagsState] = useState<string[]>([]);
|
||||
const [searchState, setSearchState] = useState<string>("");
|
||||
const [galleries, setGalleries] = useState([]);
|
||||
const [tagSearch, setTagSearch] = useState<string>('');
|
||||
const [newTagName, setNewTagName] = useState<string>('');
|
||||
const getData = async () => {
|
||||
const tagsResponse = await fetch(`/api/galleries/tags`);
|
||||
const tagsData = await tagsResponse.json();
|
||||
setTags(tagsData);
|
||||
const galleriesResponse = await fetch(`/api/galleries?search=` + searchState + '&nsfw=' + nsfwState, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ tags: tagsState })
|
||||
});
|
||||
const galleriesData = await galleriesResponse.json();
|
||||
setGalleries(galleriesData);
|
||||
}
|
||||
|
||||
const createTag = async () => {
|
||||
let formattedTag = newTagName.toLowerCase().replace(" ", "_");
|
||||
const tagsResponse = await fetch(`/api/galleries/tags`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ tag: formattedTag })
|
||||
});
|
||||
const tagsData = await tagsResponse.json();
|
||||
setNewTagName('');
|
||||
getData();
|
||||
}
|
||||
|
||||
const deleteTag = async (tagParam: string) => {
|
||||
const tagsResponse = await fetch(`/api/galleries/tags`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ tag:tagParam })
|
||||
});
|
||||
const tagsData = await tagsResponse.json();
|
||||
getData();
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, [tagsState, newTagName]);
|
||||
|
||||
|
||||
return (
|
||||
<div className="w-full p-8 h-max text-white lg:flex justify-center items-start animate-in mt-32">
|
||||
<div className="w-full h-max lg:w-1/3 rounded-md bg-primary opacity-90 p-8 m-1 shadow-lg backdrop-blur">
|
||||
<span className="text-2xl">Tags Management</span>
|
||||
<div className="w-full flex pt-4">
|
||||
<form onSubmit={createTag} className="flex w-full">
|
||||
|
||||
<input value={newTagName} required type="text" onChange={(e)=>{setNewTagName(e.target.value)}} className=" mb-8 mr-2 rounded-md bg-info-bright p-2 w-1/2 text-black shadow-lg" placeholder="Tag Name" />
|
||||
<button className=" ml-2 shadow-lg w-1/2 h-10 text-center bg-success hover:bg-success-light text-white font-bold rounded flex items-center justify-center">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="lg:hidden size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
|
||||
<span className="lg:hidden block">Tag</span>
|
||||
<span className="lg:block hidden">New Tag</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div className="w-full flex">
|
||||
<input type="text" value={tagSearch} onChange={(e)=>{setTagSearch(e.target.value)}} className=" mb-8 shadow-lg mr-2 rounded-md bg-info-bright p-2 w-full text-black" placeholder="Search all tags by name" />
|
||||
</div>
|
||||
<div className="w-full h-96 overflow-y-scroll no-scrollbar">
|
||||
<table className="w-full bg-primary-light rounded">
|
||||
<tbody>
|
||||
{tags.filter((value,index,array)=>{
|
||||
return value.name.toLowerCase().includes(tagSearch.toLowerCase());
|
||||
}).map((item:any) => (
|
||||
<tr key={item.name} className="hover:bg-secondary-dark animate-in shadow">
|
||||
<td className="px-4 py-2">{item.name}</td>
|
||||
<td className="px-4 py-2">
|
||||
<button onClick={()=>{deleteTag(item.name)}} className=" bg-error shadow-lg hover:bg-error-light text-white font-bold py-2 px-4 rounded float-right">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full h-max lg:w-1/2 rounded-md bg-primary opacity-90 backdrop-blur-lg p-8 m-1 shadow-lg">
|
||||
<div className="w-full pb-2 flex justify-between">
|
||||
<span className="text-2xl">Galleries Management</span>
|
||||
<div>
|
||||
<button onClick={()=>{router.push("/admin/")}} className="ml-2 p-2 shadow-lg h-10 text-center bg-error hover:bg-error-light text-white font-bold rounded">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="xl:hidden size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
|
||||
<span className="xl:block hidden">Back</span>
|
||||
</button>
|
||||
<button onClick={()=>{router.push("/gallery/admin/create")}} className="ml-2 p-2 shadow-lg h-10 text-center bg-success hover:bg-success-light text-white font-bold rounded">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="xl:hidden size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
|
||||
</svg>
|
||||
|
||||
<span className="xl:block hidden">New Gallery</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full pb-2 flex">
|
||||
<div className="absolute w-full z-20 pr-16">
|
||||
<SearchInput
|
||||
startingTags={[]}
|
||||
placeholderTags={[
|
||||
{ value: "tags", label: "❗️ click here to add tags to search" }
|
||||
]} nsfwButtonEnabled={false} searchChanged={(search) => { setSearchState(search) }} nsfwChanged={(nsfw) => { setNsfwState(nsfw) }} tagsChanged={(tags) => { setTagsState(tags) }} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full h-96 overflow-y-scroll no-scrollbar">
|
||||
<table className="w-full mt-20 bg-primary-light rounded">
|
||||
<tbody>
|
||||
{/* Replace this with your data mapping logic */}
|
||||
{galleries.map((item: { name: string, imageCount: number, tier: string }) => (
|
||||
<tr key={item.name} className="hover:bg-secondary-dark shadow animate-in">
|
||||
<td className="px-4 py-2" style={{ width: '65%' }}>{item.name}</td>
|
||||
<td className="px-4 py-2">{item.imageCount}</td>
|
||||
<td className="px-4 py-2">{item.tier}</td>
|
||||
<td className="px-4 py-2">
|
||||
<button onClick={()=>{ router.push(`/gallery/admin/view?id=${encodeURIComponent(item.name)}`)}} className="bg-secondary shadow-lg hover:bg-secondary-light text-white font-bold py-2 px-4 rounded float-right">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-1.5A1.125 1.125 0 0 1 13.5 7.125v-1.5a3.375 3.375 0 0 0-3.375-3.375H8.25m5.231 13.481L15 17.25m-4.5-15H5.625c-.621 0-1.125.504-1.125 1.125v16.5c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 0 0-9-9Zm3.75 11.625a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z" />
|
||||
</svg>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default PageComponent;
|
271
app/gallery/admin/view/page.tsx
Normal file
271
app/gallery/admin/view/page.tsx
Normal file
@ -0,0 +1,271 @@
|
||||
"use client";
|
||||
import { createClient } from "@/utils/supabase/client";
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import Gallery from "@/components/neroshitron/gallery";
|
||||
import SearchInput from "@/components/neroshitron/search_input";
|
||||
import GalleryThumbnail from "@/components/neroshitron/gallery_thumbnail";
|
||||
|
||||
function PageComponent() {
|
||||
const [filePreviews, setFilePreviews] = useState<string[]>([]);
|
||||
const supabase = createClient();
|
||||
const user = supabase.auth.getUser();
|
||||
const [gallery , setGallery] = useState<any>(null);
|
||||
const [originalName, setOriginalGalleryName] = useState<string>('');
|
||||
const [galleryName, setGalleryName] = useState<string>('');
|
||||
const [nsfw, setNsfw] = useState<boolean>(false);
|
||||
const [tags, setTags] = useState<string[]>([]);
|
||||
const [tier, setTier] = useState<string>('Free');
|
||||
const [thumbnail, setThumbnail] = useState<string>();
|
||||
const [fileNames, setFileNames] = useState<string[]>([]);
|
||||
const [selectedTags, setSelectedTags] = useState<string[]>([]);
|
||||
const router = useRouter();
|
||||
|
||||
const [tiers, setTiers] = useState<any[]>([]);
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
|
||||
|
||||
const [images, setImages] = useState<string[]>([]);
|
||||
const getData = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/tiers');
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setTiers(data);
|
||||
} else {
|
||||
console.error('failed to fetch tiers');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching users:', error);
|
||||
}
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const id = urlParams.get('id');
|
||||
const galleryResponse = await fetch(`/api/galleries/admin/${id}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
const galleryData = await galleryResponse.json();
|
||||
setGallery(galleryData.gallery);
|
||||
|
||||
const filesResponse = await fetch(`/api/galleries/${id}/images/names`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
const filesData = await filesResponse.json();
|
||||
setFileNames(filesData);
|
||||
|
||||
setNsfw(galleryData.gallery.nsfw);
|
||||
setTags(galleryData.gallery.tags);
|
||||
setTier(galleryData.gallery.tier);
|
||||
setGalleryName(galleryData.gallery.name);
|
||||
if(originalName === ''){
|
||||
setOriginalGalleryName(galleryData.gallery.name);
|
||||
}
|
||||
const imagesResponse = await fetch('/api/galleries/' + galleryData.gallery.name+ '/images');
|
||||
const imagesUrls = await imagesResponse.json() as string[];
|
||||
setImages(imagesUrls);
|
||||
}
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
}, [gallery]);
|
||||
|
||||
useEffect(() => {
|
||||
}, [gallery, ]);
|
||||
useEffect(() => {
|
||||
}, [ nsfw ]);
|
||||
useEffect(() => {
|
||||
}, [tags ]);
|
||||
useEffect(() => {
|
||||
}, [galleryName]);
|
||||
useEffect(() => {
|
||||
}, [ tier]);
|
||||
|
||||
const updateGallery = async () => {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const id = urlParams.get('id');
|
||||
const formData = new FormData();
|
||||
formData.append('id', gallery.name);
|
||||
formData.append('name', galleryName);
|
||||
formData.append('thumbnail', thumbnail ?? '');
|
||||
formData.append('originalName', originalName);
|
||||
formData.append('tags', JSON.stringify(selectedTags));
|
||||
formData.append('nsfw', nsfw.toString());
|
||||
formData.append('tier', tier);
|
||||
const response = await fetch(`/api/galleries/admin/${originalName}`, {
|
||||
method: 'PUT',
|
||||
body: formData
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
console.log(response)
|
||||
const data = await response.json();
|
||||
} else {
|
||||
console.log(response)
|
||||
}
|
||||
if(originalName != galleryName){
|
||||
router.push(`/gallery/admin/view?id=${galleryName}`)
|
||||
}
|
||||
else{
|
||||
window.location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
const deleteGallery = async () => {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const id = urlParams.get('id');
|
||||
const response = await fetch(`/api/gallery/admin/${gallery.name}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
router.push("/gallery/admin");
|
||||
} else {
|
||||
console.log(response)
|
||||
}
|
||||
}
|
||||
|
||||
const tierObj = tiers.find((tier) => tier.name == gallery.tier);
|
||||
const subscriptionColor = tier ? tierObj.color : null;
|
||||
return (
|
||||
<div className="w-full p-8 h-screen text-white flex justify-center items-center animate-in">
|
||||
<div className="w-full lg:w-1/2 rounded-md p-12 mt-14 ">
|
||||
<div className="w-full lg:pt-0 pt-32 flex pb-60 justify-center"> {/* Center the gallery thumbnail */}
|
||||
{gallery != null && (
|
||||
<GalleryThumbnail
|
||||
key={"galleryThumbnail"+galleryName+"-"+tags.join("")}
|
||||
id={originalName}
|
||||
columns={3}
|
||||
onSelect={function (id: string, columns: number): void { setOpen(true) }}
|
||||
title={galleryName}
|
||||
subscription={tier}
|
||||
tags={tags}
|
||||
subscriptionColor={subscriptionColor}
|
||||
showNsfw={false}
|
||||
nsfw={nsfw}
|
||||
></GalleryThumbnail>
|
||||
)}
|
||||
</div>
|
||||
<div className="w-full opacity-90 backdrop-blur-lg bg-primary shadow-lg p-8 pb-0 rounded">
|
||||
<span className="text-2xl">Editing Gallery</span>
|
||||
<div className="w-full flex justify-end">
|
||||
<div className="w-1/2 flex">
|
||||
<input
|
||||
type="text"
|
||||
className="mb-8 mr-2 rounded-md bg-secondary p-2 w-full text-white"
|
||||
placeholder="Gallery Name"
|
||||
value={galleryName}
|
||||
onChange={(e) => setGalleryName(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="w-1/2 flex">
|
||||
<button
|
||||
onClick={() => deleteGallery()}
|
||||
className="h-10 text-center w-full bg-error hover:bg-error-light text-white rounded-md p-2 flex items-center justify-center"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5}
|
||||
stroke="currentColor" className="md:hidden size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
||||
</svg>
|
||||
|
||||
<span className="md:block hidden">Delete</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => (router.push("/gallery/admin"))}
|
||||
className="h-10 w-full bg-error-dark hover:bg-error text-white rounded-md p-2 ml-2 flex items-center justify-center"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5}
|
||||
stroke="currentColor" className="md:hidden size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9 15 3 9m0 0 6-6M3 9h12a6 6 0 0 1 0 12h-3" />
|
||||
</svg>
|
||||
|
||||
<span className="md:block hidden">Back</span>
|
||||
</button>
|
||||
<button onClick={()=>{updateGallery()}} className="h-10 w-full bg-warning hover:bg-warning-light text-white rounded-md p-2 ml-2">
|
||||
<span>Update</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full lg:flex opacity-90 backdrop-blur-lg bg-primary shadow-lg p-8 pt-0 rounded">
|
||||
<div className="w-full lg:w-1/2 mr-44">
|
||||
<div className="w-1/2 fixed mr-8">
|
||||
|
||||
{gallery &&(
|
||||
<SearchInput
|
||||
placeholderTags={[
|
||||
{ value: "tags", label: "❗️ click here to add tags" },
|
||||
]}
|
||||
startingTags={gallery.tags}
|
||||
nsfwButtonEnabled={true}
|
||||
searchChanged={(search) => {}}
|
||||
nsfwChanged={(nsfw) => {}}
|
||||
tagsChanged={(tags) => { setSelectedTags(tags) }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full lg:w-1/2 pt-4">
|
||||
{gallery != null && (<>
|
||||
<select value={nsfw ? "NSFW" : "SFW"} className="mb-2 shadow-lg rounded-md bg-secondary p-2 w-full text-white" onChange={e=>{
|
||||
setNsfw(e.target.value == "NSFW");
|
||||
}}>
|
||||
<option value="" disabled >Set NSFW</option>
|
||||
<option value="NSFW" selected={nsfw}>NSFW</option>
|
||||
<option value="SFW" selected={!nsfw}>SFW</option>
|
||||
</select>
|
||||
<select onChange={e=>{
|
||||
setTier(e.target.value);
|
||||
|
||||
}} className="mb-2 shadow-lg mr-2 rounded-md bg-secondary p-2 w-full text-white">
|
||||
<option value="" disabled >Select New Tier</option>
|
||||
{tiers.map((tier, index) => (
|
||||
<option selected={tier.name==gallery.tier} key={index} value={tier.name}>{tier.name}</option>
|
||||
))}
|
||||
</select>
|
||||
<select onChange={e=>{setThumbnail(e.target.value)}} className="mb-2 shadow-lg mr-2 rounded-md bg-secondary p-2 w-full text-white">
|
||||
<option value="" disabled selected>Select New Thumbnail</option>
|
||||
{fileNames.map((name, index) => (
|
||||
<option selected={name==gallery.thumbnail_file} key={index} value={name}>{name}</option>
|
||||
))}
|
||||
</select>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{(open) && (
|
||||
<>
|
||||
{/*
|
||||
This is the modal for holding the gallery
|
||||
*/}
|
||||
<div
|
||||
className={`fixed inset-0 transition-opacity z-30 animate-in`}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div
|
||||
className="absolute w-full h-full inset-0 bg-secondary-dark opacity-70 z-30"
|
||||
onClick={() => setOpen(true)}
|
||||
></div>
|
||||
<div className="absolute inset-0 overflow-y-auto overflow-x-hidden no-scrollbar pt-2 w-full p-20 h-full z-30">
|
||||
<Gallery
|
||||
id={gallery.name}
|
||||
columns={3}
|
||||
closeMenu={() => setOpen(false)}
|
||||
></Gallery>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default PageComponent;
|
58
app/gallery/page.tsx
Normal file
58
app/gallery/page.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
"use client";
|
||||
import { createClient } from "@/utils/supabase/client";
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import Search from "@/components/neroshitron/search";
|
||||
import Gallery from "@/components/neroshitron/gallery";
|
||||
import Link from "next/link";
|
||||
|
||||
function PageComponent() {
|
||||
|
||||
const [selectedGallery, setSelectedGallery] = useState<string | null>(null);
|
||||
const supabase = createClient();
|
||||
|
||||
const getData = async () => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, [selectedGallery]);
|
||||
|
||||
const closeGallery = () => {
|
||||
setSelectedGallery(null);
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className="w-full">
|
||||
<div className="w-2/4">
|
||||
<Search gallerySelected={(gallery:string)=>{setSelectedGallery(gallery)}}/>
|
||||
</div>
|
||||
|
||||
{selectedGallery!=null ? (
|
||||
<>
|
||||
{/*
|
||||
This is the modal for holding the gallery
|
||||
*/}
|
||||
<div
|
||||
className={`fixed inset-0 transition-opacity z-30 animate-in`}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div
|
||||
className="absolute inset-0 bg-secondary-dark opacity-70 z-30"
|
||||
onClick={() => closeGallery()}
|
||||
></div>
|
||||
<div className="absolute inset-0 overflow-y-auto overflow-x-hidden no-scrollbar pt-2 w-full p-20 z-30">
|
||||
<Gallery
|
||||
id={selectedGallery as string}
|
||||
columns={3}
|
||||
closeMenu={() => closeGallery()}
|
||||
></Gallery>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PageComponent;
|
111
app/globals.css
Normal file
111
app/globals.css
Normal file
@ -0,0 +1,111 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
|
||||
@keyframes expandFromLeft {
|
||||
0% {
|
||||
width: 0;
|
||||
}
|
||||
100% {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hide scrollbar for Chrome, Safari and Opera */
|
||||
.no-scrollbar::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Hide scrollbar for IE, Edge and Firefox */
|
||||
.no-scrollbar {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
@keyframes fadeOut {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0; }
|
||||
}
|
||||
.fade-out {
|
||||
animation: fadeOut 0.5s forwards;
|
||||
}
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 200 20% 98%;
|
||||
--btn-background: 200 10% 91%;
|
||||
--btn-background-hover: 200 10% 89%;
|
||||
--foreground: 200 50% 3%;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--background: 200 50% 3%;
|
||||
--btn-background: 200 10% 9%;
|
||||
--btn-background-hover: 200 10% 12%;
|
||||
--foreground: 200 20% 96%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.my-masonry-grid {
|
||||
display: -webkit-box; /* Not needed if autoprefixing */
|
||||
display: -ms-flexbox; /* Not needed if autoprefixing */
|
||||
display: flex;
|
||||
margin-left: -30px; /* gutter size offset */
|
||||
width: auto;
|
||||
}
|
||||
.my-masonry-grid_column {
|
||||
padding-left: 30px; /* gutter size */
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
/* Style your items */
|
||||
.my-masonry-grid_column > div { /* change div to reference your elements you put in <Masonry> */
|
||||
background: grey;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.animate-in {
|
||||
animation: animateIn 0.3s ease 0.15s both;
|
||||
}
|
||||
|
||||
@keyframes animateIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
button:disabled {
|
||||
filter: grayscale(50%);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
:root {
|
||||
--color-primary: #201240;
|
||||
--color-primary-light: #403260;
|
||||
--color-primary-dark: #100120;
|
||||
--color-secondary: #4F3D70;
|
||||
--color-secondary-light: #6F5D90;
|
||||
--color-secondary-dark: #2F1D50;
|
||||
--color-error: #862117;
|
||||
--color-error-light: #C44C4C;
|
||||
--color-error-dark: #5C0D0D;
|
||||
--color-success: #00C9A6;
|
||||
--color-success-light: #20E9C6;
|
||||
--color-success-dark: #00A986;
|
||||
--color-warning: #E17558;
|
||||
--color-warning-light: #E39578;
|
||||
--color-warning-dark: #C15538;
|
||||
--color-info: #222140;
|
||||
--color-info-light: #424260;
|
||||
--color-info-dark: #020120;
|
||||
}
|
44
app/layout.tsx
Normal file
44
app/layout.tsx
Normal file
@ -0,0 +1,44 @@
|
||||
import { GeistSans } from "geist/font/sans";
|
||||
import "./globals.css";
|
||||
import { createClient } from "@/utils/supabase/client";
|
||||
import NavigationBar from "@/components/neroshitron/navigation_bar";
|
||||
import { SpeedInsights } from "@vercel/speed-insights/next"
|
||||
import { Analytics } from "@vercel/analytics/react"
|
||||
import RightHandLayoutImage from "@/components/neroshitron/right_hand_layout_image";
|
||||
import Theme from "@/components/theme";
|
||||
const defaultUrl = process.env.VERCEL_URL
|
||||
? `https://${process.env.VERCEL_URL}`
|
||||
: "http://localhost:3000";
|
||||
|
||||
export const metadata = {
|
||||
metadataBase: new URL(defaultUrl),
|
||||
title: "Next.js and Supabase Starter Kit",
|
||||
description: "The fastest way to build apps with Next.js and Supabase",
|
||||
};
|
||||
|
||||
const supabase = createClient();
|
||||
|
||||
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="en" className={GeistSans.className}>
|
||||
<body className="bg-background text-foreground">
|
||||
<Theme/>
|
||||
<RightHandLayoutImage/>
|
||||
<div className="w-full fixed z-30 text-white white">
|
||||
<NavigationBar/>
|
||||
<SpeedInsights/>
|
||||
<Analytics/>
|
||||
</div>
|
||||
<main className="min-h-screen flex flex-col items-center bg-gradient-to-r from-primary to-secondary overflow-hidden">
|
||||
{children}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
33
app/livestream/page.tsx
Normal file
33
app/livestream/page.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
function PageComponent() {
|
||||
|
||||
const getData = async () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="p-40 h-full w-full animate-in"> {/* This adds padding top of 20px */}
|
||||
<div className="flex">
|
||||
<iframe
|
||||
className="flex-grow"
|
||||
style={{flexBasis: '90%'}} // Video takes up 90% of the width
|
||||
src="http://localhost:8080/embed/video"
|
||||
title="Owncast"
|
||||
height={720}
|
||||
referrerPolicy="origin"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
<iframe
|
||||
className="flex-2"
|
||||
style={{flexBasis: '10%'}} // Chat takes up 10% of the width
|
||||
src="http://localhost:8080/embed/chat/readwrite"
|
||||
title="Owncast"
|
||||
referrerPolicy="origin"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PageComponent;
|
128
app/login/page.tsx
Normal file
128
app/login/page.tsx
Normal file
@ -0,0 +1,128 @@
|
||||
import Link from "next/link";
|
||||
import { headers } from "next/headers";
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { redirect } from "next/navigation";
|
||||
import { SubmitButton } from "./submit-button";
|
||||
|
||||
export default async function Login({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: { message: string };
|
||||
}) {
|
||||
const supabase = createClient();
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
|
||||
if (user) {
|
||||
return redirect("/gallery");
|
||||
}
|
||||
const signIn = async (formData: FormData) => {
|
||||
"use server";
|
||||
|
||||
const email = formData.get("email") as string;
|
||||
const password = formData.get("password") as string;
|
||||
const supabase = createClient();
|
||||
|
||||
const { data:data, error } = await supabase.auth.signInWithPassword({
|
||||
email,
|
||||
password,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
return redirect("/login?message=Could not authenticate user");
|
||||
}
|
||||
|
||||
return redirect("/gallery");
|
||||
};
|
||||
|
||||
const signUp = async (formData: FormData) => {
|
||||
"use server";
|
||||
|
||||
const origin = headers().get("origin");
|
||||
const email = formData.get("email") as string;
|
||||
const password = formData.get("password") as string;
|
||||
const supabase = createClient();
|
||||
|
||||
const { error } = await supabase.auth.signUp({
|
||||
email,
|
||||
password,
|
||||
options: {
|
||||
emailRedirectTo: `${origin}/auth/callback`,
|
||||
},
|
||||
});
|
||||
|
||||
if (error) {
|
||||
return redirect("/login?message=Could not authenticate user");
|
||||
}
|
||||
|
||||
return redirect("/login?message=Check email to continue sign in process");
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
<div className="flex-1 w-full flex flex-col gap-20 items-center animate-in"> <div className="flex-1 flex flex-col w-full px-8 sm:max-w-md justify-center gap-2">
|
||||
|
||||
<form className="animate-in flex-1 flex flex-col w-full my-32 gap-2 text-white">
|
||||
|
||||
<Link
|
||||
href="/"
|
||||
className="absolute left-1 top-44 py-2 px-4 rounded-md no-underline text-white flex items-center group text-sm"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="mr-2 h-4 w-4 transition-transform group-hover:-translate-x-1"
|
||||
>
|
||||
<polyline points="15 18 9 12 15 6" />
|
||||
</svg>{" "}
|
||||
Back
|
||||
</Link>
|
||||
<input
|
||||
className="rounded-md px-4 py-2 bg-inherit border mb-2 mx-1 w-full sm:w-auto"
|
||||
name="email"
|
||||
placeholder="Email Address"
|
||||
required
|
||||
/>
|
||||
<input
|
||||
className="rounded-md px-4 py-2 bg-inherit border mb-2 mx-1 w-full sm:w-auto"
|
||||
type="password"
|
||||
name="password"
|
||||
placeholder="Password "
|
||||
required
|
||||
/>
|
||||
<div className="flex text-white white">
|
||||
<SubmitButton
|
||||
formAction={signIn}
|
||||
className="bg-success hover:bg-success-light rounded-md px-4 py-2 text-white mb-2 mx-1 w-1/2"
|
||||
pendingText="Signing In..."
|
||||
>
|
||||
Sign In
|
||||
</SubmitButton>
|
||||
<SubmitButton
|
||||
formAction={signUp}
|
||||
className="bg-info hover:bg-info-light border border-foreground/20 rounded-md px-4 py-2 text-white mb-2 mx-1 w-1/2"
|
||||
pendingText="Signing Up..."
|
||||
>
|
||||
Sign Up
|
||||
</SubmitButton>
|
||||
</div>
|
||||
{searchParams?.message && (
|
||||
<p className="mt-4 bg-foreground/10 mt-14 p-2 text-white text-center">
|
||||
{searchParams.message}
|
||||
</p>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
20
app/login/submit-button.tsx
Normal file
20
app/login/submit-button.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
"use client";
|
||||
|
||||
import { useFormStatus } from "react-dom";
|
||||
import { type ComponentProps } from "react";
|
||||
|
||||
type Props = ComponentProps<"button"> & {
|
||||
pendingText?: string;
|
||||
};
|
||||
|
||||
export function SubmitButton({ children, pendingText, ...props }: Props) {
|
||||
const { pending, action } = useFormStatus();
|
||||
|
||||
const isPending = pending && action === props.formAction;
|
||||
|
||||
return (
|
||||
<button {...props} type="submit" aria-disabled={pending}>
|
||||
{isPending ? pendingText : children}
|
||||
</button>
|
||||
);
|
||||
}
|
12
app/middleware/path-header.tsx
Normal file
12
app/middleware/path-header.tsx
Normal file
@ -0,0 +1,12 @@
|
||||
import { NextRequest, NextResponse } from 'next/server'
|
||||
|
||||
export function middleware(req:NextRequest, res:NextResponse) {
|
||||
const requestHeaders = new Headers(req.headers)
|
||||
requestHeaders.set('x-path', req.nextUrl.pathname)
|
||||
|
||||
return NextResponse.next({
|
||||
request: {
|
||||
headers: requestHeaders
|
||||
}
|
||||
})
|
||||
}
|
19
app/page.tsx
Normal file
19
app/page.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default async function Index() {
|
||||
const canInitSupabaseClient = () => {
|
||||
// This function is just for the interactive tutorial.
|
||||
// Feel free to remove it once you have Supabase connected.
|
||||
try {
|
||||
createClient();
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const isSupabaseConnected = canInitSupabaseClient();
|
||||
|
||||
return redirect("/gallery")
|
||||
}
|
20
app/protected/page.tsx
Normal file
20
app/protected/page.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default async function ProtectedPage() {
|
||||
const supabase = createClient();
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
|
||||
if (!user) {
|
||||
return redirect("/login");
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex-1 w-full flex flex-col gap-20 items-center animate-in">
|
||||
<h1>This is protected.</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
20
app/subscriptions/page.jsx
Normal file
20
app/subscriptions/page.jsx
Normal file
@ -0,0 +1,20 @@
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
export default async function Subscriptions() {
|
||||
const supabase = createClient();
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
|
||||
if (!user) {
|
||||
return redirect("/login");
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex-1 w-full flex flex-col gap-20 items-center animate-in">
|
||||
<h1>This is protected.</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
81
components/neroshitron/galleries.tsx
Normal file
81
components/neroshitron/galleries.tsx
Normal file
@ -0,0 +1,81 @@
|
||||
"use client;"
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import GalleryThumbnail from './gallery_thumbnail';
|
||||
|
||||
interface TagProps {
|
||||
nsfw: boolean;
|
||||
tags: string[];
|
||||
search: string;
|
||||
gallerySelected: (gallery: string) => void;
|
||||
}
|
||||
|
||||
const Galleries = ({ nsfw, tags, search, gallerySelected }: TagProps) => {
|
||||
|
||||
const [galleries, setGalleries] = useState([]);
|
||||
const [nsfwState, setNsfwState] = useState<boolean>(nsfw);
|
||||
const [tagsState, setTagsState] = useState<string[]>(tags);
|
||||
const [searchState, setSearchState] = useState<string>(search);
|
||||
|
||||
const [selectedGallery, setSelectedGallery] = useState<string | null>(null);
|
||||
const [tiers, setTiers] = useState<any[]>([]);
|
||||
|
||||
const selectGallery = (gallery: string) => {
|
||||
setSelectedGallery(gallery);
|
||||
gallerySelected(gallery);
|
||||
};
|
||||
|
||||
|
||||
const getData = async () => {
|
||||
try {
|
||||
const response = await fetch('/api/tiers');
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
setTiers(data);
|
||||
} else {
|
||||
console.error('failed to fetch tiers');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching users:', error);
|
||||
}
|
||||
const galleriesResponse = await fetch(`/api/galleries?search=` + searchState + '&nsfw=' + nsfwState, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ tags: tagsState })
|
||||
});
|
||||
const galleriesData = await galleriesResponse.json();
|
||||
setGalleries(galleriesData);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, [tagsState]);
|
||||
|
||||
return (
|
||||
<div className="absolute inset-0 mx-auto ml-16 md:ml-0 pt-48 p-4 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-y-48 gap-x-4 animate-in overflow-y-scroll no-scrollbar z-0">
|
||||
|
||||
{galleries && galleries.map((gallery: any, index) => {
|
||||
const tier = tiers.find((tier) => tier.name == gallery.tier);
|
||||
const subscriptionColor = tier ? tier.color : null;
|
||||
|
||||
return (
|
||||
<GalleryThumbnail
|
||||
key={gallery.name + " " + nsfw}
|
||||
id={gallery.name}
|
||||
title={gallery.name}
|
||||
tags={gallery.tags}
|
||||
columns={gallery.columns}
|
||||
showNsfw={nsfw}
|
||||
subscription={gallery.tier as string}
|
||||
subscriptionColor={subscriptionColor}
|
||||
onSelect={selectGallery}
|
||||
nsfw={gallery.nsfw}
|
||||
></GalleryThumbnail>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Galleries;
|
222
components/neroshitron/gallery.tsx
Normal file
222
components/neroshitron/gallery.tsx
Normal file
@ -0,0 +1,222 @@
|
||||
import { use, useState, useRef } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import Masonry from 'react-masonry-css';
|
||||
import PanZoom, { PanZoomRef } from 'react-easy-panzoom';
|
||||
|
||||
interface GalleryProps {
|
||||
id: string;
|
||||
columns: number;
|
||||
closeMenu: () => void;
|
||||
}
|
||||
|
||||
const Gallery = ({ id, columns, closeMenu }: GalleryProps) => {
|
||||
|
||||
const [selectedImage, setSelectedImage] = useState<string | null>(null);
|
||||
const [images, setImages] = useState<string[]>([]);
|
||||
const [galleryId, setGalleryId] = useState(id as string);
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
const panZoomRef = useRef<any>(null);
|
||||
|
||||
const next = () => {
|
||||
if (currentIndex < images.length - 1) {
|
||||
setCurrentIndex(currentIndex + 1);
|
||||
} else {
|
||||
setCurrentIndex(0);
|
||||
}
|
||||
}
|
||||
|
||||
const previous = () => {
|
||||
if (currentIndex > 0) {
|
||||
setCurrentIndex(currentIndex - 1);
|
||||
} else {
|
||||
setCurrentIndex(images.length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
const handleDownload = (image: string) => {
|
||||
const link = document.createElement('a');
|
||||
link.href = image;
|
||||
link.download = 'image.jpg'; // or any other filename
|
||||
link.style.display = 'none';
|
||||
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
};
|
||||
|
||||
const getData = async () => {
|
||||
const thumbnailResponse = await fetch('/api/galleries/' + String(galleryId) + '/images');
|
||||
const thumbnailUrl = await thumbnailResponse.json() as string[];
|
||||
setImages(thumbnailUrl);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
switch (event.key) {
|
||||
case 'ArrowLeft':
|
||||
case 'a':
|
||||
case 'A':
|
||||
previous();
|
||||
break;
|
||||
case 'ArrowRight':
|
||||
case 'd':
|
||||
case 'D':
|
||||
next();
|
||||
break;
|
||||
case 'Escape':
|
||||
close();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
setSelectedImage(images[currentIndex]);
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
|
||||
// Clean up the event listener when the component is unmounted
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
|
||||
}, [selectedImage, currentIndex]);
|
||||
|
||||
const handleClick = (image: string) => {
|
||||
setSelectedImage(image);
|
||||
setCurrentIndex(images.indexOf(image));
|
||||
};
|
||||
|
||||
const resetPanZoom = () => {
|
||||
panZoomRef.current.autoCenter();
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
if (selectedImage != null) {
|
||||
setSelectedImage(null);
|
||||
setImages([]);
|
||||
}
|
||||
else {
|
||||
closeMenu();
|
||||
}
|
||||
};
|
||||
const back_page = () => {
|
||||
if (selectedImage != null) {
|
||||
setSelectedImage(null);
|
||||
setImages([]);
|
||||
}
|
||||
};
|
||||
|
||||
const renderButtons = () => {
|
||||
return (
|
||||
<div className="z-20 bottom-10 fixed text-white pt-4 bg-primary bg-opacity-90 animate-in rounded-md" style={{ backdropFilter: 'blur(10px)' }}>
|
||||
<div className='grid grid-cols-5 pl-4 gap-4 pr-4'>
|
||||
<button
|
||||
className={`justify-center text-center w-full animate-in animate-once animate-duration-1000 animate-ease-out animate-reverse mb-4 py-2 px-4 rounded-lg no-underline flex items-center z-50 bg-error hover:bg-error-light`}
|
||||
onClick={() => close()}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18 18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
className={`justify-center text-center w-full animate-in animate-once animate-duration-1000 animate-ease-out animate-reverse mb-4 py-2 px-4 rounded-lg no-underline flex items-center z-50 ${!selectedImage ? 'opacity-50 cursor-not-allowed bg-gray-800' : 'bg-secondary hover:bg-secondary-light'}`}
|
||||
onClick={() => resetPanZoom()}
|
||||
disabled={!selectedImage}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9 9V4.5M9 9H4.5M9 9 3.75 3.75M9 15v4.5M9 15H4.5M9 15l-5.25 5.25M15 9h4.5M15 9V4.5M15 9l5.25-5.25M15 15h4.5M15 15v4.5m0-4.5 5.25 5.25" />
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
<button
|
||||
className={`justify-center text-center w-full animate-in animate-once animate-duration-1000 animate-ease-out animate-reverse mb-4 py-2 px-4 rounded-lg no-underline flex items-center z-50 ${!selectedImage ? 'opacity-50 cursor-not-allowed bg-gray-800' : 'bg-secondary hover:bg-secondary-light'}`}
|
||||
onClick={() => previous()}
|
||||
disabled={!selectedImage}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="m18.75 4.5-7.5 7.5 7.5 7.5m-6-15L5.25 12l7.5 7.5" />
|
||||
</svg>
|
||||
|
||||
</button>
|
||||
<button
|
||||
className={`justify-center text-center w-full animate-in animate-once animate-duration-1000 animate-ease-out animate-reverse mb-4 py-2 px-4 rounded-lg no-underline flex items-center z-50 ${!selectedImage ? 'opacity-50 cursor-not-allowed bg-gray-800' : 'bg-secondary hover:bg-secondary-light'}`}
|
||||
onClick={() => next()}
|
||||
disabled={!selectedImage}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5" />
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
className={`justify-center text-center w-full animate-in animate-once animate-duration-1000 animate-ease-out animate-reverse mb-4 py-2 px-4 rounded-lg no-underline flex items-center z-50 ${!selectedImage ? 'opacity-50 cursor-not-allowed bg-gray-800' : 'bg-success hover:bg-success-light'}`}
|
||||
onClick={() => selectedImage && handleDownload(selectedImage)}
|
||||
disabled={!selectedImage}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="m9 13.5 3 3m0 0 3-3m-3 3v-6m1.06-4.19-2.12-2.12a1.5 1.5 0 0 0-1.061-.44H4.5A2.25 2.25 0 0 0 2.25 6v12a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18V9a2.25 2.25 0 0 0-2.25-2.25h-5.379a1.5 1.5 0 0 1-1.06-.44Z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div >
|
||||
<div className="z-20" style={{ width: selectedImage ? "100%" : "auto", height: selectedImage ? "100%" : "auto" }}>
|
||||
<div className='flex justify-center items-center pt-2 pb-20'>
|
||||
{renderButtons()}
|
||||
</div>
|
||||
{selectedImage ? (
|
||||
<>
|
||||
<PanZoom
|
||||
key={selectedImage}
|
||||
autoCenter={true}
|
||||
ref={panZoomRef}
|
||||
>
|
||||
<div id="image-container" >
|
||||
<img
|
||||
src={images[currentIndex]}
|
||||
style={{ objectFit: "contain", maxWidth: "100%", maxHeight: "calc(100vh - 20px)", pointerEvents: "none" }}
|
||||
className="cursor-pointer animate-in w-full h-auto"
|
||||
>
|
||||
</img>
|
||||
</div>
|
||||
</PanZoom>
|
||||
</>
|
||||
) : (
|
||||
<div
|
||||
className="z-30"
|
||||
style={{
|
||||
display: selectedImage ? "flex" : "block",
|
||||
alignItems: "flex-start",
|
||||
}}
|
||||
> <div className='flex justify-center items-center pt-2 '>
|
||||
|
||||
<Masonry
|
||||
breakpointCols={3}
|
||||
className="my-masonry-grid pl-6 "
|
||||
style={{ width: selectedImage ? "50%" : "100%" }}
|
||||
>
|
||||
{images
|
||||
.filter((img) => img !== selectedImage)
|
||||
.map((image, index) => (
|
||||
<img
|
||||
key={index}
|
||||
src={image}
|
||||
onClick={() => handleClick(image)}
|
||||
className={`animate-in animate-once animate-duration-1000 animate-ease-out animate-reverse hover:scale-105 p-2 cursor-pointer my-2 transition-all opacity-100 duration-500 ease-in-out transform`}
|
||||
/>
|
||||
))}
|
||||
</Masonry>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Gallery;
|
106
components/neroshitron/gallery_thumbnail.tsx
Normal file
106
components/neroshitron/gallery_thumbnail.tsx
Normal file
@ -0,0 +1,106 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
interface GalleryThumbnailProps {
|
||||
id: string;
|
||||
columns: number;
|
||||
onSelect: (id: string, columns: number) => void;
|
||||
title: string;
|
||||
subscription: string;
|
||||
subscriptionColor: string;
|
||||
tags: string[];
|
||||
showNsfw: boolean;
|
||||
nsfw: boolean;
|
||||
}
|
||||
|
||||
const GalleryThumbnail = ({ id, columns, onSelect, title, showNsfw, nsfw, subscription, subscriptionColor, tags }: GalleryThumbnailProps) => {
|
||||
const [galleryId, setGalleryId] = useState<string>(id);
|
||||
const [thumbnailUrl, setThumbnailUrl] = useState<string>('');
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true);
|
||||
const [galleryCollumns, setColumns] = useState<number>(columns);
|
||||
const [imageCount, setImageCount] = useState<number>(0);
|
||||
const [nsfwState, setNsfw] = useState<boolean>(nsfw);
|
||||
const [showNsfwState, setShowNsfw] = useState<boolean>(showNsfw);
|
||||
const [subscriptionState, setSubscription] = useState<string>(subscription);
|
||||
const [tagsState, setTags] = useState<string[]>(tags);
|
||||
console.log(subscriptionColor)
|
||||
const openGallery = () => {
|
||||
onSelect(galleryId, galleryCollumns);
|
||||
};
|
||||
|
||||
const getData = async () => {
|
||||
setIsLoading(true);
|
||||
const thumbnailResponse = await fetch('/api/galleries/' + id + '/thumbnail?nsfw=' + showNsfwState);
|
||||
const thumbnailUrl = await thumbnailResponse.text();
|
||||
const imagesCountResponse = await fetch('/api/galleries/' + id + '/images/count');
|
||||
const imageCount = await imagesCountResponse.json() as number;
|
||||
setImageCount(imageCount);
|
||||
setThumbnailUrl(thumbnailUrl);
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, [galleryId]);
|
||||
|
||||
return (
|
||||
<div className=" py-3 sm:max-w-xl sm:mx-auto flex-3 animate-fade-up animate-once animate-duration-1000 animate-ease-out animate-normal animate-fill-forwards">
|
||||
<div className="h-48 overflow-visible w-full relative hover:scale-95 rounded-3xl" style={{ cursor: 'pointer'}}>
|
||||
{!isLoading ? (
|
||||
<>
|
||||
<img
|
||||
className={`aspect-content rounded-3xl shadow-lg`}
|
||||
src={thumbnailUrl}
|
||||
alt=""
|
||||
onClick={openGallery}
|
||||
key={galleryId}
|
||||
style={{ width: '20rem', height: '20rem', objectFit: 'cover' }}
|
||||
/>
|
||||
<div className="bottom-0 left-0 w-full h-10% p-2 rounded-md flex flex-col justify-end">
|
||||
<div className="text-white flex justify-between">
|
||||
<div>
|
||||
<div className="flex">
|
||||
<h3 className=" pr-4 text-lg font-bold break-words" style={{ lineHeight: '2rem', textShadow: '0 0 2px black' }}>{title}</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-white flex justify-between">
|
||||
<div className="flex items-center">
|
||||
<span className="bg-secondary text-white mr-2 px-2 py-1 rounded-md text-sm flex items-center h-full">
|
||||
<span className="text-center">{imageCount}</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth="1.5" stroke="currentColor" className="pl-2 size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z" />
|
||||
</svg>
|
||||
</span>
|
||||
{nsfwState && (
|
||||
<span className=" bg-error text-white px-2 py-1 mr-2 rounded-md text-sm h-full flex items-center">NSFW</span>
|
||||
)}
|
||||
<span className="text-white px-2 py-1 rounded-md text-sm h-full flex items-center" style={{ cursor: 'pointer', backgroundColor: subscriptionColor }}>Free</span>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className="text-white flex justify-between">
|
||||
<div>
|
||||
<div className="flex">
|
||||
{tagsState.map((tag, index) => (
|
||||
<span
|
||||
key={index}
|
||||
className={`pr-4 text-sm font-bold break-words"
|
||||
style={{ lineHeight: '2rem', textShadow: '0 0 2px black' }`}
|
||||
>
|
||||
{tag}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="animate-pulse bg-secondary-light rounded-3xl" style={{ width: '20rem', height: '20rem' }}></div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default GalleryThumbnail;
|
149
components/neroshitron/navigation_bar.tsx
Normal file
149
components/neroshitron/navigation_bar.tsx
Normal file
@ -0,0 +1,149 @@
|
||||
import { createClient } from "@/utils/supabase/server";
|
||||
import Link from "next/link";
|
||||
import { redirect, useRouter } from "next/navigation";
|
||||
import crypto from 'crypto';
|
||||
import { headers } from "next/headers";
|
||||
|
||||
|
||||
export default async function AuthButton() {
|
||||
const supabase = createClient();
|
||||
|
||||
const {
|
||||
data: { user },
|
||||
} = await supabase.auth.getUser();
|
||||
|
||||
const signOut = async () => {
|
||||
"use server";
|
||||
|
||||
const supabase = createClient();
|
||||
await supabase.auth.signOut();
|
||||
return redirect("/login");
|
||||
};
|
||||
|
||||
const heads = headers()
|
||||
const currentPage = heads.get('x-path')
|
||||
const getGravatarUrl = () => {
|
||||
if (user == null) {
|
||||
return;
|
||||
}
|
||||
let email = user.email;
|
||||
if (email != null) {
|
||||
const emailHash = crypto.createHash('md5').update(email.trim().toLowerCase()).digest('hex');
|
||||
return `https://www.gravatar.com/avatar/${emailHash}`;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
const url = getGravatarUrl();
|
||||
|
||||
const admins = await supabase.from('admins').select('user_id');
|
||||
let isAdmin = false;
|
||||
if(!admins.error) {
|
||||
for (const admin of admins.data) {
|
||||
if (admin.user_id == user?.id) {
|
||||
isAdmin = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex justify-center items-center pt-2 ">
|
||||
<nav className="w-auto bg-primary bg-opacity-40 flex justify-center z-10 h-16 animate-in rounded-md shadow-lg" style={{ backdropFilter: 'blur(10px)' }}>
|
||||
<div className="w-auto flex justify-between items-center p-3 text-sm">
|
||||
<div className="flex items-center gap-2 z-10">
|
||||
|
||||
{/* This is admin stuff */}
|
||||
|
||||
{(isAdmin) && (
|
||||
<>
|
||||
<Link
|
||||
href="/gallery/admin/"
|
||||
className={`py-2 px-3 w-38 text-center flex rounded-md no-underline bg-secondary hover:bg-secondary-light`}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="lg:hidden size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M11.42 15.17 17.25 21A2.652 2.652 0 0 0 21 17.25l-5.877-5.877M11.42 15.17l2.496-3.03c.317-.384.74-.626 1.208-.766M11.42 15.17l-4.655 5.653a2.548 2.548 0 1 1-3.586-3.586l6.837-5.63m5.108-.233c.55-.164 1.163-.188 1.743-.14a4.5 4.5 0 0 0 4.486-6.336l-3.276 3.277a3.004 3.004 0 0 1-2.25-2.25l3.276-3.276a4.5 4.5 0 0 0-6.336 4.486c.091 1.076-.071 2.264-.904 2.95l-.102.085m-1.745 1.437L5.909 7.5H4.5L2.25 3.75l1.5-1.5L7.5 4.5v1.409l4.26 4.26m-1.745 1.437 1.745-1.437m6.615 8.206L15.75 15.75M4.867 19.125h.008v.008h-.008v-.008Z" />
|
||||
</svg>
|
||||
<span className="hidden lg:block">Gallery Admin</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/admin/"
|
||||
className={`py-2 px-3 w-38 text-center flex rounded-md no-underline bg-secondary hover:bg-secondary-light`}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="lg:hidden size-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.241-.438.613-.43.992a7.723 7.723 0 0 1 0 .255c-.008.378.137.75.43.991l1.004.827c.424.35.534.955.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.47 6.47 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.991a6.932 6.932 0 0 1 0-.255c.007-.38-.138-.751-.43-.992l-1.004-.827a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z" />
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
|
||||
</svg>
|
||||
<span className="hidden lg:block">System Settings</span>
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Link
|
||||
href="/gallery"
|
||||
className={`py-2 px-3 flex rounded-md no-underline ${currentPage!="gallery" ? 'bg-primary hover:bg-primary-light' : 'bg-secondary hover:bg-secondary-light'}`}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6 lg:hidden block">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="m2.25 15.75 5.159-5.159a2.25 2.25 0 0 1 3.182 0l5.159 5.159m-1.5-1.5 1.409-1.409a2.25 2.25 0 0 1 3.182 0l2.909 2.909m-18 3.75h16.5a1.5 1.5 0 0 0 1.5-1.5V6a1.5 1.5 0 0 0-1.5-1.5H3.75A1.5 1.5 0 0 0 2.25 6v12a1.5 1.5 0 0 0 1.5 1.5Zm10.5-11.25h.008v.008h-.008V8.25Zm.375 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z" />
|
||||
</svg>
|
||||
|
||||
<span className="hidden lg:block">Gallery</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/livestream"
|
||||
className={`py-2 px-3 flex rounded-md no-underline ${currentPage!="livestream" ? 'bg-primary hover:bg-primary-light' : 'bg-secondary hover:bg-secondary-light'}`}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6 lg:hidden block">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="m15.75 10.5 4.72-4.72a.75.75 0 0 1 1.28.53v11.38a.75.75 0 0 1-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 0 0 2.25-2.25v-9a2.25 2.25 0 0 0-2.25-2.25h-9A2.25 2.25 0 0 0 2.25 7.5v9a2.25 2.25 0 0 0 2.25 2.25Z" />
|
||||
</svg>
|
||||
<span className="hidden lg:block">Livestream</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/commissions"
|
||||
className={`py-2 px-3 flex rounded-md no-underline ${currentPage!="commissions" ? 'bg-primary hover:bg-primary-light' : 'bg-secondary hover:bg-secondary-light'}`}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6 lg:hidden block">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M15.75 10.5V6a3.75 3.75 0 1 0-7.5 0v4.5m11.356-1.993 1.263 12c.07.665-.45 1.243-1.119 1.243H4.25a1.125 1.125 0 0 1-1.12-1.243l1.264-12A1.125 1.125 0 0 1 5.513 7.5h12.974c.576 0 1.059.435 1.119 1.007ZM8.625 10.5a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm7.5 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Z" />
|
||||
</svg>
|
||||
<span className="hidden lg:block">Commissions</span>
|
||||
</Link>
|
||||
<Link
|
||||
href="/subscriptions"
|
||||
className={`py-2 px-3 flex rounded-md no-underline ${currentPage!="subscriptions" ? 'bg-primary hover:bg-primary-light' : 'bg-secondary hover:bg-secondary-light'}`}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6 lg:hidden block">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99" />
|
||||
</svg>
|
||||
<span className="hidden lg:block">Subscription</span>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{(user != null) ? (
|
||||
<>
|
||||
<form action={signOut}>
|
||||
<button className="py-2 px-4 ml-2 rounded-md no-underline bg-error hover:bg-error-light">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6 lg:hidden ">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M13.5 10.5V6.75a4.5 4.5 0 1 1 9 0v3.75M3.75 21.75h10.5a2.25 2.25 0 0 0 2.25-2.25v-6.75a2.25 2.25 0 0 0-2.25-2.25H3.75a2.25 2.25 0 0 0-2.25 2.25v6.75a2.25 2.25 0 0 0 2.25 2.25Z" />
|
||||
</svg>
|
||||
<span className="hidden lg:block">Logout</span>
|
||||
</button>
|
||||
</form>
|
||||
<a href="https://gravatar.com/" target="_blank">
|
||||
<img src={url} alt="Profile" className="w-10 h-10 object-cover rounded-full cursor-pointer" />
|
||||
</a>
|
||||
</>
|
||||
) : (
|
||||
<Link
|
||||
href="/subscriptions"
|
||||
className={`ml-2 py-2 px-3 flex rounded-md no-underline bg-success hover:bg-success-light`}
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="size-6 lg:hidden block">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0 3.181 3.183a8.25 8.25 0 0 0 13.803-3.7M4.031 9.865a8.25 8.25 0 0 1 13.803-3.7l3.181 3.182m0-4.991v4.99" />
|
||||
</svg>
|
||||
<span className="hidden lg:block">Login</span>
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</div>)
|
||||
}
|
16
components/neroshitron/right_hand_layout_image.tsx
Normal file
16
components/neroshitron/right_hand_layout_image.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
"use client;"
|
||||
import React from 'react';
|
||||
|
||||
const RightHandLayoutImage: React.FC = () => {
|
||||
return (
|
||||
<div className="fixed w-full h-full overflow-hidden z-0 animate-fade-left animate-once animate-duration-[2000ms] animate-normal animate-fill-forwards">
|
||||
<img
|
||||
src="/gallery_girl.png"
|
||||
className="float-right object-cover h-screen w-full lg:w-5/6 xl:w-3/6 opacity-50 overflow-hidden"
|
||||
alt="Background"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RightHandLayoutImage;
|
60
components/neroshitron/search.tsx
Normal file
60
components/neroshitron/search.tsx
Normal file
@ -0,0 +1,60 @@
|
||||
"use client;"
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import SearchInput from '@/components/neroshitron/search_input';
|
||||
import Galleries from './galleries';
|
||||
|
||||
interface SearchProps {
|
||||
gallerySelected: (gallery: string) => void;
|
||||
}
|
||||
|
||||
const Search = ({ gallerySelected }: SearchProps) => {
|
||||
const [tags, setTags] = useState<string[]>([]);
|
||||
const [search, setSearch] = useState<string>('');
|
||||
const [nsfw, setNsfw] = useState<boolean>(false);
|
||||
const [gallery, setGallery] = useState<string | null>(null);
|
||||
|
||||
const getData = async () => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, [search]);
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, [nsfw]);
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, [tags]);
|
||||
useEffect(() => {
|
||||
getData();
|
||||
if (gallery != null)
|
||||
gallerySelected(gallery);
|
||||
}, [gallery]);
|
||||
//TRY TESTING WITH THIS REMOVED!
|
||||
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Galleries gallerySelected={(gallery: string) => { setGallery(gallery) }} key={search + "-" + tags.length + "-" + nsfw} search={search} nsfw={nsfw} tags={tags} />
|
||||
<section className="fixed flex items-center w-full p-8 pt-20 opacity-90 animate-in animate-once animate-duration-500">
|
||||
<div className="container mx-auto py-8">
|
||||
<SearchInput
|
||||
|
||||
startingTags={[]}
|
||||
placeholderTags={[
|
||||
{ value: "neroshi", label: "🧑🎨 neroshi" },
|
||||
{ value: "neroshi", label: "❗️ click here for tags to search!" },
|
||||
]} nsfwButtonEnabled={true} searchChanged={(search) => { setSearch(search) }} nsfwChanged={(nsfw) => { setNsfw(nsfw) }} tagsChanged={(tags) => { setTags(tags); }} />
|
||||
</div>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Search;
|
190
components/neroshitron/search_input.tsx
Normal file
190
components/neroshitron/search_input.tsx
Normal file
@ -0,0 +1,190 @@
|
||||
"use client;"
|
||||
import React, { useState, useEffect, useRef, forwardRef } from 'react';
|
||||
import TagSelector from '../neroshitron/tag_selector';
|
||||
import Select from "react-tailwindcss-select";
|
||||
import { SelectValue } from 'react-tailwindcss-select/dist/components/type';
|
||||
import { Option } from 'react-tailwindcss-select/dist/components/type';
|
||||
|
||||
interface SearchInputProps {
|
||||
tagsChanged: (tags: string[]) => void;
|
||||
searchChanged: (search: string) => void;
|
||||
nsfwChanged: (nsfw: boolean) => void;
|
||||
nsfwButtonEnabled: boolean | null;
|
||||
placeholderTags: Option[];
|
||||
startingTags: string[] | null;
|
||||
}
|
||||
|
||||
const SearchInput = ({ tagsChanged, searchChanged, nsfwChanged, nsfwButtonEnabled, placeholderTags, startingTags }: SearchInputProps) => {
|
||||
|
||||
|
||||
|
||||
|
||||
const [tagSearch, setTagSearch] = useState<string>('');
|
||||
const [nsfw, setNsfw] = useState<boolean>(false);
|
||||
const [selectedTags, setSelectedTags] = useState<string[]>(startingTags ?? []);
|
||||
const [selectedTagsInput, setSelectedTagsInput] = useState<Option[]>([...placeholderTags, ...(startingTags ?? []).map((tag) => ({ value: tag, label: tag }))]);
|
||||
const [selectingTags, setSelectingTags] = useState<boolean>(false);
|
||||
const tagSelectorRef = React.useRef(null);
|
||||
const [tags, setTags] = useState<any[]>([]);
|
||||
|
||||
const getData = async () => {
|
||||
const tagsResponse = await fetch(`/api/galleries/tags`);
|
||||
const tagsData = await tagsResponse.json();
|
||||
setTags(tagsData);
|
||||
}
|
||||
|
||||
const updateTags = (newTags: string[]) => {
|
||||
setSelectedTags(newTags)
|
||||
}
|
||||
|
||||
const onTagsClosed = (tags: string[]) => {
|
||||
setSelectingTags(false);
|
||||
}
|
||||
|
||||
const openTags = () => {
|
||||
setSelectingTags(true);
|
||||
if (selectingTags) {
|
||||
onTagsClosed(selectedTags);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
tagsChanged(selectedTags.filter(tag => tag != "neroshi"));
|
||||
}, [selectedTags]);
|
||||
useEffect(() => {
|
||||
nsfwChanged(nsfw);
|
||||
}, [nsfw]);
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
const [color, setColor] = useState('black');
|
||||
const selectRef = useRef(null);
|
||||
const [currentTag, setCurrentTag] = useState<string>('');
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
|
||||
if (event.key === 'ArrowUp') {
|
||||
const currentIndex = tags.findIndex(tag => tag.name === currentTag);
|
||||
const newIndex = currentIndex === 0 ? tags.length - 1 : currentIndex - 1;
|
||||
setCurrentTag(tags[newIndex].name);
|
||||
} else if (event.key === 'ArrowDown') {
|
||||
const currentIndex = tags.findIndex(tag => tag.name === currentTag);
|
||||
const newIndex = currentIndex === tags.length - 1 ? 0 : currentIndex + 1;
|
||||
setCurrentTag(tags[newIndex].name);
|
||||
} else if (event.key === 'Enter') {
|
||||
const currentIndex = tags.findIndex(tag => tag.name === currentTag);
|
||||
if (currentIndex !== -1 && !selectedTags.includes(tags[currentIndex].name)) {
|
||||
setSelectedTags([...selectedTags, tags[currentIndex].name]);
|
||||
const tagsInput = selectedTagsInput;
|
||||
tagsInput.push({ value: tags[currentIndex].name, label: tags[currentIndex].name });
|
||||
setSelectedTagsInput(tagsInput);
|
||||
setCurrentTag('');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('keydown', handleKeyDown);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('keydown', handleKeyDown);
|
||||
};
|
||||
}, [currentTag, tags]);
|
||||
|
||||
|
||||
const tagOptions = tags.map((tag: { name: string; }) => ({ value: tag.name, label: tag.name }));
|
||||
return (
|
||||
<>
|
||||
<div className={` opacity 0 relative w-full flex flex-col items-center justify-center z-10`}>
|
||||
<div className="search-box mx-auto my-auto w-full">
|
||||
<div className={`flex flex-row`}>
|
||||
|
||||
{(selectingTags) ? (
|
||||
<>
|
||||
<input autoFocus value={tagSearch} onChange={(e) => setTagSearch(e.target.value)} className="rounded-l-md h-16 bg-gray-100 text-grey-darker py-2 font-normal text-grey-darkest border border-gray-100 font-bold w-full py-1 px-2 outline-none text-lg text-gray-600" type="text" placeholder="Looking for specific tag?" />
|
||||
|
||||
<span className="flex items-center bg-gray-100 rounded rounded-l-none border-0 px-3 font-bold text-grey-100">
|
||||
<button key="back" onClick={() => { openTags() }} type="button" className={`animate-in bg-pink-900 hover:bg-pink-800 text-lg text-white font-bold py-3 px-6 rounded`}>
|
||||
Back
|
||||
</button>
|
||||
|
||||
</span>
|
||||
</>
|
||||
)
|
||||
: (
|
||||
<>
|
||||
<div className="w-full top-0">
|
||||
<Select isMultiple isSearchable isClearable searchInputPlaceholder='Start typing to search tags...'
|
||||
options={tagOptions}
|
||||
placeholder="Select tags for your search"
|
||||
onChange={(value: Option | Option[] | null) => {
|
||||
if (value === null) {
|
||||
setSelectedTags([]);
|
||||
setSelectedTagsInput([]);
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
setSelectedTags(value.map((option) => option.value));
|
||||
setSelectedTagsInput(value as Option[])
|
||||
} else if (value) {
|
||||
setSelectedTags([value.value]);
|
||||
setSelectedTagsInput([value])
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
setSelectedTags(value.map((option) => option.value));
|
||||
setSelectedTagsInput(value.filter((option) => option.value !== 'placeholder'));
|
||||
} else if (value) {
|
||||
setSelectedTags([value.value]);
|
||||
setSelectedTagsInput([value]);
|
||||
}
|
||||
}}
|
||||
onSearchInputChange={(value) => {
|
||||
|
||||
}}
|
||||
classNames={{
|
||||
|
||||
menu: "bg-secondary-dark text-white pb-4 rounded",
|
||||
searchBox: "rounded-md bg-secondary w-1/2 text-white w-full mt-2 p-2 mb-2 animate-in",
|
||||
searchIcon: "hidden",
|
||||
tagItem: (value) => "hover:scale-95 bg-primary-light rounded-md pl-2 p-1 m-1 flex",
|
||||
tagItemText: "text-white animate-in",
|
||||
closeIcon: "text-white",
|
||||
tagItemIconContainer:"animate-in"
|
||||
}}
|
||||
|
||||
formatOptionLabel={data => (
|
||||
<li key={"tag-" + data.value}
|
||||
className={`animate-in block transition rounded duration-200 px-2 py-2 cursor-pointer select-none truncate pt-2 bg-primary text-white ${currentTag==data.value ? "bg-primary-light" : ""} hover:bg-primary-light
|
||||
}`}
|
||||
>
|
||||
{data.label}
|
||||
</li>
|
||||
)}
|
||||
value={selectedTagsInput}
|
||||
primaryColor={"indigo"} />
|
||||
|
||||
</div>
|
||||
{(nsfwButtonEnabled) && (
|
||||
<span className="w-1/6 border-0 font-bold text-grey-100">
|
||||
<button
|
||||
onClick={() => { setNsfw(!nsfw) }}
|
||||
type="button"
|
||||
className={`animate-in text-sm text-white font-bold h-full w-16 px-2 rounded rounded-l-none ${nsfw ? "bg-error hover:bg-error-light" : "bg-success hover:bg-success-light"}`}
|
||||
|
||||
>
|
||||
{nsfw ? "NSFW" : "SFW"}
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{(selectingTags) &&
|
||||
<TagSelector key={tagSearch} tagSearch={tagSearch} tagsChanged={(newTags: string[]) => { updateTags(newTags) }} selectedTagsInput={selectedTags} ref={tagSelectorRef} />}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SearchInput;
|
20
components/neroshitron/tag_pill.tsx
Normal file
20
components/neroshitron/tag_pill.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
"use client;"
|
||||
import React, { useState, useEffect } from 'react';
|
||||
|
||||
interface TagProps { onTagClicked: (tag: string) => void, selected: boolean, tag: string }
|
||||
|
||||
const Tag = ({ onTagClicked, selected, tag, }: TagProps) => {
|
||||
|
||||
return (
|
||||
<button
|
||||
key={tag}
|
||||
type="button"
|
||||
className={`animate-in w-full h-8 rounded-md no-underline text-sm text-white py-1 font-medium text-center ${selected ? 'hover:bg-pink-800 bg-pink-900' : 'hover:bg-pink-600 bg-neroshi-blue-800 border-neroshi-blue-900 border-2'}`}
|
||||
onClick={() => onTagClicked(tag)}
|
||||
>
|
||||
{tag}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default Tag;
|
61
components/neroshitron/tag_selector.tsx
Normal file
61
components/neroshitron/tag_selector.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
"use client;"
|
||||
import React, { forwardRef, useState, useEffect } from 'react';
|
||||
import Tag from './tag_pill';
|
||||
|
||||
interface TagSelectorProps {
|
||||
tagSearch: string,
|
||||
selectedTagsInput: string[],
|
||||
tagsChanged: (tags: string[]) => void
|
||||
}
|
||||
|
||||
const TagSelector = forwardRef<TagSelectorProps, { tagSearch: string, selectedTagsInput: string[], tagsChanged: (tags: string[]) => void }>((props, ref) => {
|
||||
|
||||
const [tags, setTags] = useState<any[]>([]);
|
||||
const [tagSearch, setTagSearch] = useState<string>(props.tagSearch);
|
||||
const [selectedTags, setSelectedTags] = useState<string[]>(props.selectedTagsInput);
|
||||
|
||||
const handleTag = (tag: string) => {
|
||||
if (selectedTags.includes(tag)) {
|
||||
setSelectedTags(selectedTags.filter(t => t !== tag));
|
||||
} else {
|
||||
setSelectedTags([...selectedTags, tag]);
|
||||
}
|
||||
setTags(selectedTags);
|
||||
};
|
||||
|
||||
const getData = async () => {
|
||||
const tagsResponse = await fetch(`/api/galleries/tags`);
|
||||
const tagsData = await tagsResponse.json();
|
||||
setTags(tagsData);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
props.tagsChanged(selectedTags);
|
||||
getData();
|
||||
}, [selectedTags, tagSearch]);
|
||||
|
||||
useEffect(() => {
|
||||
props.tagsChanged(selectedTags);
|
||||
getData();
|
||||
}, [selectedTags, tagSearch]);
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
||||
<div className="flex md:w-full pt-4 justify-center items-center">
|
||||
{(tags.length > 0) && (
|
||||
<div className="z-10 grid p-4 grid-cols-2 md:grid-cols-4 lg:grid-cols-6 xl:grid-cols-8 gap-1 w-full max-h-96 overflow-y-scroll no-scrollbar pt-4 bg-neroshi-blue-900 rounded-md opacity-90 backdrop-filter backdrop-blur-md mx-auto">
|
||||
{tags.map((tag: any) => (
|
||||
(tagSearch === '' || tag.name.toLowerCase().includes(tagSearch.toLowerCase())) && // Updated condition
|
||||
<Tag tag={tag.name} selected={selectedTags.includes(tag.name)} onTagClicked={(tag) => handleTag(tag)} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default TagSelector;
|
37
components/theme.tsx
Normal file
37
components/theme.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
|
||||
"use client";
|
||||
import { useEffect, useState } from 'react';
|
||||
import { createClient } from '@/utils/supabase/client';
|
||||
|
||||
interface GalleryThumbnailProps {}
|
||||
|
||||
const ThemeProvider = ({}: GalleryThumbnailProps) => {
|
||||
const [data, setData] = useState<any[]>([]); // State to store the fetched data
|
||||
|
||||
const getData = async () => {
|
||||
const supabase = createClient();
|
||||
const { data, error } = await supabase.from('interface_configurations').select('*');
|
||||
if (error) {
|
||||
console.error('Error fetching data:', error);
|
||||
} else {
|
||||
setData(data || []);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// Update variables when data changes
|
||||
for (const config of data) {
|
||||
if (config.type === 'color') {
|
||||
document.documentElement.style.setProperty(`--color-${config.name}`, config.value);
|
||||
}
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
export default ThemeProvider;
|
20
components/ui/example.tsx
Normal file
20
components/ui/example.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
import { use, useState } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
interface GalleryThumbnailProps {
|
||||
}
|
||||
|
||||
const GalleryThumbnail = ({ }: GalleryThumbnailProps) => {
|
||||
const getData = async () => {
|
||||
}
|
||||
useEffect(() => {
|
||||
getData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default GalleryThumbnail;
|
@ -5,842 +5,22 @@ x-logging: &x-logging
|
||||
options:
|
||||
max-file: '5'
|
||||
max-size: '10m'
|
||||
|
||||
services:
|
||||
neroshitron:
|
||||
build:
|
||||
context: .
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 3000:3000
|
||||
# neroshitron:
|
||||
# build:
|
||||
# context: .
|
||||
# restart: unless-stopped
|
||||
# ports:
|
||||
# - 3000:3000
|
||||
|
||||
owncast:
|
||||
image: owncast/owncast:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 8080:8080
|
||||
- 1935:1935
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
|
||||
traefik:
|
||||
image: traefik:2.11
|
||||
container_name: appwrite-traefik
|
||||
<<: *x-logging
|
||||
command:
|
||||
- --providers.file.directory=/storage/config
|
||||
- --providers.file.watch=true
|
||||
- --providers.docker=true
|
||||
- --providers.docker.exposedByDefault=false
|
||||
- --providers.docker.constraints=Label(`traefik.constraint-label-stack`,`appwrite`)
|
||||
- --entrypoints.appwrite_web.address=:80
|
||||
- --entrypoints.appwrite_websecure.address=:443
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- appwrite-config:/storage/config:ro
|
||||
- appwrite-certificates:/storage/certificates:ro
|
||||
depends_on:
|
||||
- appwrite
|
||||
networks:
|
||||
- gateway
|
||||
- appwrite
|
||||
|
||||
appwrite:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
container_name: appwrite
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
labels:
|
||||
- traefik.enable=true
|
||||
- traefik.constraint-label-stack=appwrite
|
||||
- traefik.docker.network=appwrite
|
||||
- traefik.http.services.appwrite_api.loadbalancer.server.port=80
|
||||
#http
|
||||
- traefik.http.routers.appwrite_api_http.entrypoints=appwrite_web
|
||||
- traefik.http.routers.appwrite_api_http.rule=PathPrefix(`/`)
|
||||
- traefik.http.routers.appwrite_api_http.service=appwrite_api
|
||||
# https
|
||||
- traefik.http.routers.appwrite_api_https.entrypoints=appwrite_websecure
|
||||
- traefik.http.routers.appwrite_api_https.rule=PathPrefix(`/`)
|
||||
- traefik.http.routers.appwrite_api_https.service=appwrite_api
|
||||
- traefik.http.routers.appwrite_api_https.tls=true
|
||||
volumes:
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
- appwrite-cache:/storage/cache:rw
|
||||
- appwrite-config:/storage/config:rw
|
||||
- appwrite-certificates:/storage/certificates:rw
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
depends_on:
|
||||
- mariadb
|
||||
- redis
|
||||
# - clamav
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_LOCALE
|
||||
- _APP_CONSOLE_WHITELIST_ROOT
|
||||
- _APP_CONSOLE_WHITELIST_EMAILS
|
||||
- _APP_CONSOLE_WHITELIST_IPS
|
||||
- _APP_CONSOLE_HOSTNAMES
|
||||
- _APP_SYSTEM_EMAIL_NAME
|
||||
- _APP_SYSTEM_EMAIL_ADDRESS
|
||||
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- _APP_SYSTEM_RESPONSE_FORMAT
|
||||
- _APP_OPTIONS_ABUSE
|
||||
- _APP_OPTIONS_ROUTER_PROTECTION
|
||||
- _APP_OPTIONS_FORCE_HTTPS
|
||||
- _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET
|
||||
- _APP_DOMAIN_FUNCTIONS
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_SMTP_HOST
|
||||
- _APP_SMTP_PORT
|
||||
- _APP_SMTP_SECURE
|
||||
- _APP_SMTP_USERNAME
|
||||
- _APP_SMTP_PASSWORD
|
||||
- _APP_USAGE_STATS
|
||||
- _APP_STORAGE_LIMIT
|
||||
- _APP_STORAGE_PREVIEW_LIMIT
|
||||
- _APP_STORAGE_ANTIVIRUS
|
||||
- _APP_STORAGE_ANTIVIRUS_HOST
|
||||
- _APP_STORAGE_ANTIVIRUS_PORT
|
||||
- _APP_STORAGE_DEVICE
|
||||
- _APP_STORAGE_S3_ACCESS_KEY
|
||||
- _APP_STORAGE_S3_SECRET
|
||||
- _APP_STORAGE_S3_REGION
|
||||
- _APP_STORAGE_S3_BUCKET
|
||||
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||
- _APP_STORAGE_DO_SPACES_SECRET
|
||||
- _APP_STORAGE_DO_SPACES_REGION
|
||||
- _APP_STORAGE_DO_SPACES_BUCKET
|
||||
- _APP_STORAGE_BACKBLAZE_ACCESS_KEY
|
||||
- _APP_STORAGE_BACKBLAZE_SECRET
|
||||
- _APP_STORAGE_BACKBLAZE_REGION
|
||||
- _APP_STORAGE_BACKBLAZE_BUCKET
|
||||
- _APP_STORAGE_LINODE_ACCESS_KEY
|
||||
- _APP_STORAGE_LINODE_SECRET
|
||||
- _APP_STORAGE_LINODE_REGION
|
||||
- _APP_STORAGE_LINODE_BUCKET
|
||||
- _APP_STORAGE_WASABI_ACCESS_KEY
|
||||
- _APP_STORAGE_WASABI_SECRET
|
||||
- _APP_STORAGE_WASABI_REGION
|
||||
- _APP_STORAGE_WASABI_BUCKET
|
||||
- _APP_FUNCTIONS_SIZE_LIMIT
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_BUILD_TIMEOUT
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_RUNTIMES
|
||||
- _APP_EXECUTOR_SECRET
|
||||
- _APP_EXECUTOR_HOST
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_MAINTENANCE_INTERVAL
|
||||
- _APP_MAINTENANCE_DELAY
|
||||
- _APP_MAINTENANCE_RETENTION_EXECUTION
|
||||
- _APP_MAINTENANCE_RETENTION_CACHE
|
||||
- _APP_MAINTENANCE_RETENTION_ABUSE
|
||||
- _APP_MAINTENANCE_RETENTION_AUDIT
|
||||
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
|
||||
- _APP_MAINTENANCE_RETENTION_SCHEDULES
|
||||
- _APP_SMS_PROVIDER
|
||||
- _APP_SMS_FROM
|
||||
- _APP_GRAPHQL_MAX_BATCH_SIZE
|
||||
- _APP_GRAPHQL_MAX_COMPLEXITY
|
||||
- _APP_GRAPHQL_MAX_DEPTH
|
||||
- _APP_VCS_GITHUB_APP_NAME
|
||||
- _APP_VCS_GITHUB_PRIVATE_KEY
|
||||
- _APP_VCS_GITHUB_APP_ID
|
||||
- _APP_VCS_GITHUB_WEBHOOK_SECRET
|
||||
- _APP_VCS_GITHUB_CLIENT_SECRET
|
||||
- _APP_VCS_GITHUB_CLIENT_ID
|
||||
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID
|
||||
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
|
||||
- _APP_ASSISTANT_OPENAI_API_KEY
|
||||
|
||||
appwrite-realtime:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: realtime
|
||||
container_name: appwrite-realtime
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.constraint-label-stack=appwrite"
|
||||
- "traefik.docker.network=appwrite"
|
||||
- "traefik.http.services.appwrite_realtime.loadbalancer.server.port=80"
|
||||
#ws
|
||||
- traefik.http.routers.appwrite_realtime_ws.entrypoints=appwrite_web
|
||||
- traefik.http.routers.appwrite_realtime_ws.rule=PathPrefix(`/v1/realtime`)
|
||||
- traefik.http.routers.appwrite_realtime_ws.service=appwrite_realtime
|
||||
# wss
|
||||
- traefik.http.routers.appwrite_realtime_wss.entrypoints=appwrite_websecure
|
||||
- traefik.http.routers.appwrite_realtime_wss.rule=PathPrefix(`/v1/realtime`)
|
||||
- traefik.http.routers.appwrite_realtime_wss.service=appwrite_realtime
|
||||
- traefik.http.routers.appwrite_realtime_wss.tls=true
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- mariadb
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPTIONS_ABUSE
|
||||
- _APP_OPTIONS_ROUTER_PROTECTION
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_USAGE_STATS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-worker-audits:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: worker-audits
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-audits
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-worker-webhooks:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: worker-webhooks
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-webhooks
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-worker-deletes:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: worker-deletes
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-deletes
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
volumes:
|
||||
- appwrite-uploads:/storage/uploads:rw
|
||||
- appwrite-cache:/storage/cache:rw
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
- appwrite-builds:/storage/builds:rw
|
||||
- appwrite-certificates:/storage/certificates:rw
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_STORAGE_DEVICE
|
||||
- _APP_STORAGE_S3_ACCESS_KEY
|
||||
- _APP_STORAGE_S3_SECRET
|
||||
- _APP_STORAGE_S3_REGION
|
||||
- _APP_STORAGE_S3_BUCKET
|
||||
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||
- _APP_STORAGE_DO_SPACES_SECRET
|
||||
- _APP_STORAGE_DO_SPACES_REGION
|
||||
- _APP_STORAGE_DO_SPACES_BUCKET
|
||||
- _APP_STORAGE_BACKBLAZE_ACCESS_KEY
|
||||
- _APP_STORAGE_BACKBLAZE_SECRET
|
||||
- _APP_STORAGE_BACKBLAZE_REGION
|
||||
- _APP_STORAGE_BACKBLAZE_BUCKET
|
||||
- _APP_STORAGE_LINODE_ACCESS_KEY
|
||||
- _APP_STORAGE_LINODE_SECRET
|
||||
- _APP_STORAGE_LINODE_REGION
|
||||
- _APP_STORAGE_LINODE_BUCKET
|
||||
- _APP_STORAGE_WASABI_ACCESS_KEY
|
||||
- _APP_STORAGE_WASABI_SECRET
|
||||
- _APP_STORAGE_WASABI_REGION
|
||||
- _APP_STORAGE_WASABI_BUCKET
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_EXECUTOR_SECRET
|
||||
- _APP_EXECUTOR_HOST
|
||||
|
||||
appwrite-worker-databases:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: worker-databases
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-databases
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-worker-builds:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: worker-builds
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-builds
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
volumes:
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
- appwrite-builds:/storage/builds:rw
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_EXECUTOR_SECRET
|
||||
- _APP_EXECUTOR_HOST
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_VCS_GITHUB_APP_NAME
|
||||
- _APP_VCS_GITHUB_PRIVATE_KEY
|
||||
- _APP_VCS_GITHUB_APP_ID
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_BUILD_TIMEOUT
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_FUNCTIONS_SIZE_LIMIT
|
||||
- _APP_OPTIONS_FORCE_HTTPS
|
||||
- _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS
|
||||
- _APP_DOMAIN
|
||||
- _APP_STORAGE_DEVICE
|
||||
- _APP_STORAGE_S3_ACCESS_KEY
|
||||
- _APP_STORAGE_S3_SECRET
|
||||
- _APP_STORAGE_S3_REGION
|
||||
- _APP_STORAGE_S3_BUCKET
|
||||
- _APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||
- _APP_STORAGE_DO_SPACES_SECRET
|
||||
- _APP_STORAGE_DO_SPACES_REGION
|
||||
- _APP_STORAGE_DO_SPACES_BUCKET
|
||||
- _APP_STORAGE_BACKBLAZE_ACCESS_KEY
|
||||
- _APP_STORAGE_BACKBLAZE_SECRET
|
||||
- _APP_STORAGE_BACKBLAZE_REGION
|
||||
- _APP_STORAGE_BACKBLAZE_BUCKET
|
||||
- _APP_STORAGE_LINODE_ACCESS_KEY
|
||||
- _APP_STORAGE_LINODE_SECRET
|
||||
- _APP_STORAGE_LINODE_REGION
|
||||
- _APP_STORAGE_LINODE_BUCKET
|
||||
- _APP_STORAGE_WASABI_ACCESS_KEY
|
||||
- _APP_STORAGE_WASABI_SECRET
|
||||
- _APP_STORAGE_WASABI_REGION
|
||||
- _APP_STORAGE_WASABI_BUCKET
|
||||
|
||||
appwrite-worker-certificates:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: worker-certificates
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-certificates
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
volumes:
|
||||
- appwrite-config:/storage/config:rw
|
||||
- appwrite-certificates:/storage/certificates:rw
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET
|
||||
- _APP_DOMAIN_FUNCTIONS
|
||||
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-worker-functions:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: worker-functions
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-functions
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
- openruntimes-executor
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_FUNCTIONS_TIMEOUT
|
||||
- _APP_FUNCTIONS_BUILD_TIMEOUT
|
||||
- _APP_FUNCTIONS_CPUS
|
||||
- _APP_FUNCTIONS_MEMORY
|
||||
- _APP_EXECUTOR_SECRET
|
||||
- _APP_EXECUTOR_HOST
|
||||
- _APP_USAGE_STATS
|
||||
- _APP_DOCKER_HUB_USERNAME
|
||||
- _APP_DOCKER_HUB_PASSWORD
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_LOGGING_PROVIDER
|
||||
|
||||
appwrite-worker-mails:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: worker-mails
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-mails
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_SYSTEM_EMAIL_NAME
|
||||
- _APP_SYSTEM_EMAIL_ADDRESS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_SMTP_HOST
|
||||
- _APP_SMTP_PORT
|
||||
- _APP_SMTP_SECURE
|
||||
- _APP_SMTP_USERNAME
|
||||
- _APP_SMTP_PASSWORD
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
|
||||
appwrite-worker-messaging:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: worker-messaging
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-messaging
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_SMS_FROM
|
||||
- _APP_SMS_PROVIDER
|
||||
|
||||
appwrite-worker-migrations:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: worker-migrations
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-migrations
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET
|
||||
- _APP_SYSTEM_SECURITY_EMAIL_ADDRESS
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_MIGRATIONS_FIREBASE_CLIENT_ID
|
||||
- _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET
|
||||
|
||||
appwrite-maintenance:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: maintenance
|
||||
<<: *x-logging
|
||||
container_name: appwrite-maintenance
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_DOMAIN
|
||||
- _APP_DOMAIN_TARGET
|
||||
- _APP_DOMAIN_FUNCTIONS
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_MAINTENANCE_INTERVAL
|
||||
- _APP_MAINTENANCE_RETENTION_EXECUTION
|
||||
- _APP_MAINTENANCE_RETENTION_CACHE
|
||||
- _APP_MAINTENANCE_RETENTION_ABUSE
|
||||
- _APP_MAINTENANCE_RETENTION_AUDIT
|
||||
- _APP_MAINTENANCE_RETENTION_USAGE_HOURLY
|
||||
- _APP_MAINTENANCE_RETENTION_SCHEDULES
|
||||
|
||||
appwrite-worker-usage:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: worker-usage
|
||||
container_name: appwrite-worker-usage
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_USAGE_STATS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_USAGE_AGGREGATION_INTERVAL
|
||||
|
||||
appwrite-worker-usage-dump:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: worker-usage-dump
|
||||
<<: *x-logging
|
||||
container_name: appwrite-worker-usage-dump
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- redis
|
||||
- mariadb
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_USAGE_STATS
|
||||
- _APP_LOGGING_PROVIDER
|
||||
- _APP_LOGGING_CONFIG
|
||||
- _APP_USAGE_AGGREGATION_INTERVAL
|
||||
|
||||
appwrite-scheduler-functions:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: schedule-functions
|
||||
container_name: appwrite-scheduler-functions
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- mariadb
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
|
||||
appwrite-scheduler-messages:
|
||||
image: appwrite/appwrite:1.5.5
|
||||
entrypoint: schedule-messages
|
||||
container_name: appwrite-scheduler-messages
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
depends_on:
|
||||
- mariadb
|
||||
- redis
|
||||
environment:
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
- _APP_REDIS_PASS
|
||||
- _APP_DB_HOST
|
||||
- _APP_DB_PORT
|
||||
- _APP_DB_SCHEMA
|
||||
- _APP_DB_USER
|
||||
- _APP_DB_PASS
|
||||
|
||||
appwrite-assistant:
|
||||
image: appwrite/assistant:0.4.0
|
||||
container_name: appwrite-assistant
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
environment:
|
||||
- _APP_ASSISTANT_OPENAI_API_KEY
|
||||
|
||||
openruntimes-executor:
|
||||
container_name: openruntimes-executor
|
||||
hostname: appwrite-executor
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
stop_signal: SIGINT
|
||||
image: openruntimes/executor:0.4.12
|
||||
networks:
|
||||
- appwrite
|
||||
- runtimes
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- appwrite-builds:/storage/builds:rw
|
||||
- appwrite-functions:/storage/functions:rw
|
||||
# Host mount nessessary to share files between executor and runtimes.
|
||||
# It's not possible to share mount file between 2 containers without host mount (copying is too slow)
|
||||
- /tmp:/tmp:rw
|
||||
environment:
|
||||
- OPR_EXECUTOR_INACTIVE_TRESHOLD=$_APP_FUNCTIONS_INACTIVE_THRESHOLD
|
||||
- OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_FUNCTIONS_MAINTENANCE_INTERVAL
|
||||
- OPR_EXECUTOR_NETWORK=$_APP_FUNCTIONS_RUNTIMES_NETWORK
|
||||
- OPR_EXECUTOR_DOCKER_HUB_USERNAME=$_APP_DOCKER_HUB_USERNAME
|
||||
- OPR_EXECUTOR_DOCKER_HUB_PASSWORD=$_APP_DOCKER_HUB_PASSWORD
|
||||
- OPR_EXECUTOR_ENV=$_APP_ENV
|
||||
- OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES
|
||||
- OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET
|
||||
- OPR_EXECUTOR_LOGGING_PROVIDER=$_APP_LOGGING_PROVIDER
|
||||
- OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG
|
||||
- OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE
|
||||
- OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY
|
||||
- OPR_EXECUTOR_STORAGE_S3_SECRET=$_APP_STORAGE_S3_SECRET
|
||||
- OPR_EXECUTOR_STORAGE_S3_REGION=$_APP_STORAGE_S3_REGION
|
||||
- OPR_EXECUTOR_STORAGE_S3_BUCKET=$_APP_STORAGE_S3_BUCKET
|
||||
- OPR_EXECUTOR_STORAGE_DO_SPACES_ACCESS_KEY=$_APP_STORAGE_DO_SPACES_ACCESS_KEY
|
||||
- OPR_EXECUTOR_STORAGE_DO_SPACES_SECRET=$_APP_STORAGE_DO_SPACES_SECRET
|
||||
- OPR_EXECUTOR_STORAGE_DO_SPACES_REGION=$_APP_STORAGE_DO_SPACES_REGION
|
||||
- OPR_EXECUTOR_STORAGE_DO_SPACES_BUCKET=$_APP_STORAGE_DO_SPACES_BUCKET
|
||||
- OPR_EXECUTOR_STORAGE_BACKBLAZE_ACCESS_KEY=$_APP_STORAGE_BACKBLAZE_ACCESS_KEY
|
||||
- OPR_EXECUTOR_STORAGE_BACKBLAZE_SECRET=$_APP_STORAGE_BACKBLAZE_SECRET
|
||||
- OPR_EXECUTOR_STORAGE_BACKBLAZE_REGION=$_APP_STORAGE_BACKBLAZE_REGION
|
||||
- OPR_EXECUTOR_STORAGE_BACKBLAZE_BUCKET=$_APP_STORAGE_BACKBLAZE_BUCKET
|
||||
- OPR_EXECUTOR_STORAGE_LINODE_ACCESS_KEY=$_APP_STORAGE_LINODE_ACCESS_KEY
|
||||
- OPR_EXECUTOR_STORAGE_LINODE_SECRET=$_APP_STORAGE_LINODE_SECRET
|
||||
- OPR_EXECUTOR_STORAGE_LINODE_REGION=$_APP_STORAGE_LINODE_REGION
|
||||
- OPR_EXECUTOR_STORAGE_LINODE_BUCKET=$_APP_STORAGE_LINODE_BUCKET
|
||||
- OPR_EXECUTOR_STORAGE_WASABI_ACCESS_KEY=$_APP_STORAGE_WASABI_ACCESS_KEY
|
||||
- OPR_EXECUTOR_STORAGE_WASABI_SECRET=$_APP_STORAGE_WASABI_SECRET
|
||||
- OPR_EXECUTOR_STORAGE_WASABI_REGION=$_APP_STORAGE_WASABI_REGION
|
||||
- OPR_EXECUTOR_STORAGE_WASABI_BUCKET=$_APP_STORAGE_WASABI_BUCKET
|
||||
|
||||
mariadb:
|
||||
image: mariadb:10.11 # fix issues when upgrading using: mysql_upgrade -u root -p
|
||||
container_name: appwrite-mariadb
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- appwrite-mariadb:/var/lib/mysql:rw
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${_APP_DB_ROOT_PASS}
|
||||
- MYSQL_DATABASE=${_APP_DB_SCHEMA}
|
||||
- MYSQL_USER=${_APP_DB_USER}
|
||||
- MYSQL_PASSWORD=${_APP_DB_PASS}
|
||||
- MARIADB_AUTO_UPGRADE=1
|
||||
command: 'mysqld --innodb-flush-method=fsync'
|
||||
|
||||
redis:
|
||||
image: redis:7.2.4-alpine
|
||||
container_name: appwrite-redis
|
||||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
command: >
|
||||
redis-server
|
||||
--maxmemory 512mb
|
||||
--maxmemory-policy allkeys-lru
|
||||
--maxmemory-samples 5
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- appwrite-redis:/data:rw
|
||||
|
||||
# clamav:
|
||||
# image: appwrite/clamav:1.2.0
|
||||
# container_name: appwrite-clamav
|
||||
# restart: unless-stopped
|
||||
# networks:
|
||||
# - appwrite
|
||||
# volumes:
|
||||
# - appwrite-uploads:/storage/uploads
|
||||
|
||||
networks:
|
||||
gateway:
|
||||
name: gateway
|
||||
appwrite:
|
||||
name: appwrite
|
||||
runtimes:
|
||||
name: runtimes
|
||||
- ./data:/owncast/data
|
||||
|
||||
volumes:
|
||||
appwrite-mariadb:
|
||||
appwrite-redis:
|
||||
appwrite-cache:
|
||||
appwrite-uploads:
|
||||
appwrite-certificates:
|
||||
appwrite-functions:
|
||||
appwrite-builds:
|
||||
appwrite-config:
|
||||
owncast-data:
|
||||
|
||||
|
||||
db-config:
|
||||
|
218
docker.env
218
docker.env
@ -1,113 +1,105 @@
|
||||
_APP_ENV=production
|
||||
_APP_LOCALE=en
|
||||
_APP_OPTIONS_ABUSE=enabled
|
||||
_APP_OPTIONS_FORCE_HTTPS=disabled
|
||||
_APP_OPTIONS_FUNCTIONS_FORCE_HTTPS=disabled
|
||||
_APP_OPTIONS_ROUTER_PROTECTION=disabled
|
||||
_APP_OPENSSL_KEY_V1=your-secret-key
|
||||
_APP_DOMAIN=localhost
|
||||
_APP_DOMAIN_FUNCTIONS=functions.localhost
|
||||
_APP_DOMAIN_TARGET=localhost
|
||||
_APP_CONSOLE_WHITELIST_ROOT=enabled
|
||||
_APP_CONSOLE_WHITELIST_EMAILS=
|
||||
_APP_CONSOLE_WHITELIST_IPS=
|
||||
_APP_CONSOLE_HOSTNAMES=
|
||||
_APP_SYSTEM_EMAIL_NAME=Appwrite
|
||||
_APP_SYSTEM_EMAIL_ADDRESS=team@appwrite.io
|
||||
_APP_SYSTEM_RESPONSE_FORMAT=
|
||||
_APP_SYSTEM_SECURITY_EMAIL_ADDRESS=certs@appwrite.io
|
||||
_APP_USAGE_STATS=enabled
|
||||
_APP_LOGGING_PROVIDER=
|
||||
_APP_LOGGING_CONFIG=
|
||||
_APP_USAGE_AGGREGATION_INTERVAL=30
|
||||
_APP_USAGE_TIMESERIES_INTERVAL=30
|
||||
_APP_USAGE_DATABASE_INTERVAL=900
|
||||
_APP_WORKER_PER_CORE=6
|
||||
_APP_REDIS_HOST=redis
|
||||
_APP_REDIS_PORT=6379
|
||||
_APP_REDIS_USER=
|
||||
_APP_REDIS_PASS=
|
||||
_APP_DB_HOST=mariadb
|
||||
_APP_DB_PORT=3306
|
||||
_APP_DB_SCHEMA=appwrite
|
||||
_APP_DB_USER=user
|
||||
_APP_DB_PASS=password
|
||||
_APP_DB_ROOT_PASS=rootsecretpassword
|
||||
_APP_INFLUXDB_HOST=influxdb
|
||||
_APP_INFLUXDB_PORT=8086
|
||||
_APP_STATSD_HOST=telegraf
|
||||
_APP_STATSD_PORT=8125
|
||||
_APP_SMTP_HOST=
|
||||
_APP_SMTP_PORT=
|
||||
_APP_SMTP_SECURE=
|
||||
_APP_SMTP_USERNAME=
|
||||
_APP_SMTP_PASSWORD=
|
||||
_APP_SMS_PROVIDER=
|
||||
_APP_SMS_FROM=
|
||||
_APP_STORAGE_LIMIT=30000000
|
||||
_APP_STORAGE_PREVIEW_LIMIT=20000000
|
||||
_APP_STORAGE_ANTIVIRUS=disabled
|
||||
_APP_STORAGE_ANTIVIRUS_HOST=clamav
|
||||
_APP_STORAGE_ANTIVIRUS_PORT=3310
|
||||
_APP_STORAGE_DEVICE=local
|
||||
_APP_STORAGE_S3_ACCESS_KEY=
|
||||
_APP_STORAGE_S3_SECRET=
|
||||
_APP_STORAGE_S3_REGION=us-east-1
|
||||
_APP_STORAGE_S3_BUCKET=
|
||||
_APP_STORAGE_DO_SPACES_ACCESS_KEY=
|
||||
_APP_STORAGE_DO_SPACES_SECRET=
|
||||
_APP_STORAGE_DO_SPACES_REGION=us-east-1
|
||||
_APP_STORAGE_DO_SPACES_BUCKET=
|
||||
_APP_STORAGE_BACKBLAZE_ACCESS_KEY=
|
||||
_APP_STORAGE_BACKBLAZE_SECRET=
|
||||
_APP_STORAGE_BACKBLAZE_REGION=us-west-004
|
||||
_APP_STORAGE_BACKBLAZE_BUCKET=
|
||||
_APP_STORAGE_LINODE_ACCESS_KEY=
|
||||
_APP_STORAGE_LINODE_SECRET=
|
||||
_APP_STORAGE_LINODE_REGION=eu-central-1
|
||||
_APP_STORAGE_LINODE_BUCKET=
|
||||
_APP_STORAGE_WASABI_ACCESS_KEY=
|
||||
_APP_STORAGE_WASABI_SECRET=
|
||||
_APP_STORAGE_WASABI_REGION=eu-central-1
|
||||
_APP_STORAGE_WASABI_BUCKET=
|
||||
_APP_FUNCTIONS_SIZE_LIMIT=30000000
|
||||
_APP_FUNCTIONS_TIMEOUT=900
|
||||
_APP_FUNCTIONS_BUILD_TIMEOUT=900
|
||||
_APP_FUNCTIONS_CONTAINERS=10
|
||||
_APP_FUNCTIONS_CPUS=0
|
||||
_APP_FUNCTIONS_MEMORY=0
|
||||
_APP_FUNCTIONS_MEMORY_SWAP=0
|
||||
_APP_FUNCTIONS_RUNTIMES=node-16.0,php-8.0,python-3.9,ruby-3.0
|
||||
_APP_EXECUTOR_SECRET=your-secret-key
|
||||
_APP_EXECUTOR_HOST=http://appwrite-executor/v1
|
||||
_APP_EXECUTOR_RUNTIME_NETWORK=appwrite_runtimes
|
||||
_APP_FUNCTIONS_ENVS=node-16.0,php-7.4,python-3.9,ruby-3.0
|
||||
_APP_FUNCTIONS_INACTIVE_THRESHOLD=60
|
||||
DOCKERHUB_PULL_USERNAME=
|
||||
DOCKERHUB_PULL_PASSWORD=
|
||||
DOCKERHUB_PULL_EMAIL=
|
||||
OPEN_RUNTIMES_NETWORK=appwrite_runtimes
|
||||
_APP_FUNCTIONS_RUNTIMES_NETWORK=runtimes
|
||||
_APP_DOCKER_HUB_USERNAME=
|
||||
_APP_DOCKER_HUB_PASSWORD=
|
||||
_APP_FUNCTIONS_MAINTENANCE_INTERVAL=3600
|
||||
_APP_VCS_GITHUB_APP_NAME=
|
||||
_APP_VCS_GITHUB_PRIVATE_KEY=
|
||||
_APP_VCS_GITHUB_APP_ID=
|
||||
_APP_VCS_GITHUB_CLIENT_ID=
|
||||
_APP_VCS_GITHUB_CLIENT_SECRET=
|
||||
_APP_VCS_GITHUB_WEBHOOK_SECRET=
|
||||
_APP_MAINTENANCE_INTERVAL=86400
|
||||
_APP_MAINTENANCE_DELAY=0
|
||||
_APP_MAINTENANCE_RETENTION_CACHE=2592000
|
||||
_APP_MAINTENANCE_RETENTION_EXECUTION=1209600
|
||||
_APP_MAINTENANCE_RETENTION_AUDIT=1209600
|
||||
_APP_MAINTENANCE_RETENTION_ABUSE=86400
|
||||
_APP_MAINTENANCE_RETENTION_USAGE_HOURLY=8640000
|
||||
_APP_MAINTENANCE_RETENTION_SCHEDULES=86400
|
||||
_APP_GRAPHQL_MAX_BATCH_SIZE=10
|
||||
_APP_GRAPHQL_MAX_COMPLEXITY=250
|
||||
_APP_GRAPHQL_MAX_DEPTH=3
|
||||
_APP_MIGRATIONS_FIREBASE_CLIENT_ID=
|
||||
_APP_MIGRATIONS_FIREBASE_CLIENT_SECRET=
|
||||
_APP_ASSISTANT_OPENAI_API_KEY=
|
||||
############
|
||||
# Secrets
|
||||
# YOU MUST CHANGE THESE BEFORE GOING INTO PRODUCTION
|
||||
############
|
||||
|
||||
POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password
|
||||
JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long
|
||||
ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE
|
||||
SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q
|
||||
DASHBOARD_USERNAME=supabase
|
||||
DASHBOARD_PASSWORD=this_password_is_insecure_and_should_be_updated
|
||||
|
||||
############
|
||||
# Database - You can change these to any PostgreSQL database that has logical replication enabled.
|
||||
############
|
||||
|
||||
POSTGRES_HOST=db
|
||||
POSTGRES_DB=postgres
|
||||
POSTGRES_PORT=5432
|
||||
# default user is postgres
|
||||
|
||||
############
|
||||
# API Proxy - Configuration for the Kong Reverse proxy.
|
||||
############
|
||||
|
||||
KONG_HTTP_PORT=8000
|
||||
KONG_HTTPS_PORT=8443
|
||||
|
||||
|
||||
############
|
||||
# API - Configuration for PostgREST.
|
||||
############
|
||||
|
||||
PGRST_DB_SCHEMAS=public,storage,graphql_public
|
||||
|
||||
|
||||
############
|
||||
# Auth - Configuration for the GoTrue authentication server.
|
||||
############
|
||||
|
||||
## General
|
||||
SITE_URL=http://localhost:3000
|
||||
ADDITIONAL_REDIRECT_URLS=
|
||||
JWT_EXPIRY=3600
|
||||
DISABLE_SIGNUP=false
|
||||
API_EXTERNAL_URL=http://localhost:8000
|
||||
|
||||
## Mailer Config
|
||||
MAILER_URLPATHS_CONFIRMATION="/auth/v1/verify"
|
||||
MAILER_URLPATHS_INVITE="/auth/v1/verify"
|
||||
MAILER_URLPATHS_RECOVERY="/auth/v1/verify"
|
||||
MAILER_URLPATHS_EMAIL_CHANGE="/auth/v1/verify"
|
||||
|
||||
## Email auth
|
||||
ENABLE_EMAIL_SIGNUP=true
|
||||
ENABLE_EMAIL_AUTOCONFIRM=false
|
||||
SMTP_ADMIN_EMAIL=admin@example.com
|
||||
SMTP_HOST=maildev
|
||||
SMTP_PORT=1025
|
||||
SMTP_USER=fake_mail_user
|
||||
SMTP_PASS=fake_mail_password
|
||||
SMTP_SENDER_NAME=fake_sender
|
||||
ENABLE_ANONYMOUS_USERS=false
|
||||
|
||||
## Phone auth
|
||||
ENABLE_PHONE_SIGNUP=true
|
||||
ENABLE_PHONE_AUTOCONFIRM=true
|
||||
|
||||
|
||||
############
|
||||
# Studio - Configuration for the Dashboard
|
||||
############
|
||||
|
||||
STUDIO_DEFAULT_ORGANIZATION=Default Organization
|
||||
STUDIO_DEFAULT_PROJECT=Default Project
|
||||
|
||||
STUDIO_PORT=3000
|
||||
# replace if you intend to use Studio outside of localhost
|
||||
SUPABASE_PUBLIC_URL=http://localhost:8000
|
||||
|
||||
# Enable webp support
|
||||
IMGPROXY_ENABLE_WEBP_DETECTION=true
|
||||
|
||||
############
|
||||
# Functions - Configuration for Functions
|
||||
############
|
||||
# NOTE: VERIFY_JWT applies to all functions. Per-function VERIFY_JWT is not supported yet.
|
||||
FUNCTIONS_VERIFY_JWT=false
|
||||
|
||||
############
|
||||
# Logs - Configuration for Logflare
|
||||
# Please refer to https://supabase.com/docs/reference/self-hosting-analytics/introduction
|
||||
############
|
||||
|
||||
LOGFLARE_LOGGER_BACKEND_API_KEY=your-super-secret-and-long-logflare-key
|
||||
|
||||
# Change vector.toml sinks to reflect this change
|
||||
LOGFLARE_API_KEY=your-super-secret-and-long-logflare-key
|
||||
|
||||
# Docker socket location - this value will differ depending on your OS
|
||||
DOCKER_SOCKET_LOCATION=/var/run/docker.sock
|
||||
|
||||
# Google Cloud Project details
|
||||
GOOGLE_PROJECT_ID=GOOGLE_PROJECT_ID
|
||||
GOOGLE_PROJECT_NUMBER=GOOGLE_PROJECT_NUMBERs
|
503
docs/.$diagrams.drawio.bkp
Normal file
503
docs/.$diagrams.drawio.bkp
Normal file
@ -0,0 +1,503 @@
|
||||
<mxfile host="Electron" modified="2024-06-04T04:27:05.636Z" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.2.5 Chrome/120.0.6099.109 Electron/28.1.0 Safari/537.36" etag="x7V6P6bjO-UHE86F-Cl3" version="24.2.5" type="device">
|
||||
<diagram name="Page-1" id="F3YAVjulPUqdYhbqfjdd">
|
||||
<mxGraphModel dx="1877" dy="2420" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-28" value="<h1>Database Design</h1>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="332.5" y="-70" width="390" height="10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-29" value="<h1>UX Flow</h1>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="30" y="620" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-37" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-33" target="9zziB1Dtd-V9IfowJO3V-36" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-33" value="Actor" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="35" y="690" width="30" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-39" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-36" target="9zziB1Dtd-V9IfowJO3V-38" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-36" value="Open Site" style="whiteSpace=wrap;html=1;verticalAlign=top;" parent="1" vertex="1">
|
||||
<mxGeometry x="105" y="705" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-42" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-38" target="9zziB1Dtd-V9IfowJO3V-41" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-43" value="No" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-42" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.2533" y="2" relative="1" as="geometry">
|
||||
<mxPoint x="2" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-48" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-38" target="9zziB1Dtd-V9IfowJO3V-47" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-72" value="Yes" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-48" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.2273" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-73" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=1;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-38" target="9zziB1Dtd-V9IfowJO3V-71" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="265" y="740" />
|
||||
<mxPoint x="265" y="795" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-74" value="Yes" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-73" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.0411" y="1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-82" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-38" target="9zziB1Dtd-V9IfowJO3V-81" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="305" y="890" />
|
||||
<mxPoint x="93" y="890" />
|
||||
<mxPoint x="93" y="940" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-83" value="Yes" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-82" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.8649" y="-1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-92" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-38" target="9zziB1Dtd-V9IfowJO3V-91" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-93" value="Yes" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-92" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.6335" y="-2" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-38" value="<br>Logged<br>In" style="rhombus;whiteSpace=wrap;html=1;verticalAlign=top;" parent="1" vertex="1">
|
||||
<mxGeometry x="265" y="680" width="80" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-46" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-41" target="9zziB1Dtd-V9IfowJO3V-45" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-41" value="Login/Signup Page" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#a20025;strokeColor=#6F0000;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="245" y="620" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-49" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;dashed=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-45" target="9zziB1Dtd-V9IfowJO3V-47" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-50" value="Click Activation<br>Email Link" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-49" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.1683" y="1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-45" value="Send Confirmation Email" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#a20025;strokeColor=#6F0000;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="235" y="560" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-52" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-47" target="9zziB1Dtd-V9IfowJO3V-51" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="540" y="716.31" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-47" value="Gallery Page" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="440" y="705" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-54" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-51" target="9zziB1Dtd-V9IfowJO3V-53" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-51" value="Search By Title &amp;<br>Filter By Tag" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="642" y="698.02" width="120" height="45" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-55" value="Refine Search" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-53" target="9zziB1Dtd-V9IfowJO3V-51" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-57" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-53" target="9zziB1Dtd-V9IfowJO3V-56" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-53" value="Browse Galleries" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="802" y="704.27" width="120" height="32.5" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-59" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-56" target="9zziB1Dtd-V9IfowJO3V-58" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-56" value="Open Gallery" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="802" y="780.52" width="120" height="32.5" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-61" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-58" target="9zziB1Dtd-V9IfowJO3V-60" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-63" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-58" target="9zziB1Dtd-V9IfowJO3V-62" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-65" value="Directional<br>Buttons" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-63" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.1714" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-69" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-58" target="9zziB1Dtd-V9IfowJO3V-68" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="742" y="850.52" />
|
||||
<mxPoint x="742" y="840.52" />
|
||||
<mxPoint x="732" y="840.52" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-58" value="Enlarge Image &amp;&nbsp;<br>Pan/Zoom" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="802" y="840.52" width="120" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-60" value="Download Image" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="802" y="900.52" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-64" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-62" target="9zziB1Dtd-V9IfowJO3V-58" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="672" y="960.52" />
|
||||
<mxPoint x="782" y="960.52" />
|
||||
<mxPoint x="782" y="870.52" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-62" value="Next/Previous<br>Image" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="612" y="890.52" width="120" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-70" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-68" target="9zziB1Dtd-V9IfowJO3V-56" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="762" y="797.39" as="sourcePoint" />
|
||||
<mxPoint x="792" y="796.14" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="762" y="796.52" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-68" value="Close Image" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="642" y="787.52" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-76" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-71" target="9zziB1Dtd-V9IfowJO3V-75" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-78" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-71" target="9zziB1Dtd-V9IfowJO3V-77" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-71" value="Livestream Page" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#d80073;strokeColor=#A50040;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="125" y="780" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-75" value="Watch Stream" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#d80073;strokeColor=#A50040;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="125" y="840" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-77" value="Chat" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#d80073;strokeColor=#A50040;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="12.5" y="780" width="75" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-85" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" source="9zziB1Dtd-V9IfowJO3V-81" target="9zziB1Dtd-V9IfowJO3V-84" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-87" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" source="9zziB1Dtd-V9IfowJO3V-81" target="9zziB1Dtd-V9IfowJO3V-86" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-81" value="Subscriptions Page" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#6a00ff;strokeColor=#3700CC;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="32.5" y="940" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-84" value="View Current Tier" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#6a00ff;strokeColor=#3700CC;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="32.5" y="990" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-89" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" source="9zziB1Dtd-V9IfowJO3V-86" target="9zziB1Dtd-V9IfowJO3V-88" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-86" value="View Available Tiers" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#6a00ff;strokeColor=#3700CC;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="187.5" y="940" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-90" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" source="9zziB1Dtd-V9IfowJO3V-88" target="9zziB1Dtd-V9IfowJO3V-84" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-88" value="Upgrade Tier" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#6a00ff;strokeColor=#3700CC;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="187.5" y="990" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-95" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-91" target="9zziB1Dtd-V9IfowJO3V-94" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="410" y="810" />
|
||||
<mxPoint x="360" y="810" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-100" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-91" target="9zziB1Dtd-V9IfowJO3V-99" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-91" value="Commissions Page" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#60a917;strokeColor=#2D7600;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="350" y="770" width="120" height="27.48" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-97" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-94" target="9zziB1Dtd-V9IfowJO3V-96" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-98" value="Yes" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-97" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.6109" relative="1" as="geometry">
|
||||
<mxPoint x="20" y="2" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-105" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-94" target="9zziB1Dtd-V9IfowJO3V-110" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-106" value="No" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-105" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.1779" y="-2" relative="1" as="geometry">
|
||||
<mxPoint y="-2" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-94" value="Has Existing<br>Commission" style="rhombus;whiteSpace=wrap;html=1;rounded=0;fillColor=#60a917;strokeColor=#2D7600;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="310" y="830.52" width="100" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-101" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-96" target="9zziB1Dtd-V9IfowJO3V-99" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-96" value="View Existing<br>Commission Status" style="whiteSpace=wrap;html=1;rounded=0;fillColor=#60a917;strokeColor=#2D7600;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="350" y="970" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-99" value="View All Commissions" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#60a917;strokeColor=#2D7600;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="500" y="770" width="130" height="27.48" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-109" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-104" target="9zziB1Dtd-V9IfowJO3V-96" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="560" y="985" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-104" value="Request New<br>Commission" style="whiteSpace=wrap;html=1;fillColor=#60a917;strokeColor=#2D7600;rounded=0;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="470" y="817.52" width="120" height="39.48" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-111" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=1;exitDx=0;exitDy=0;entryX=0.75;entryY=0;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-110" target="9zziB1Dtd-V9IfowJO3V-96" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="440" y="930" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-112" value="No" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-111" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.0044" relative="1" as="geometry">
|
||||
<mxPoint y="5" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-113" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-110" target="9zziB1Dtd-V9IfowJO3V-104" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-114" value="Yes" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-113" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.5043" y="1" relative="1" as="geometry">
|
||||
<mxPoint x="3" y="-1" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-110" value="Requests<br>Open" style="rhombus;whiteSpace=wrap;html=1;rounded=0;fillColor=#60a917;strokeColor=#2D7600;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="440" y="860.52" width="79.48" height="79.48" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-5" value="public.tags" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#1ba1e2;fontColor=#ffffff;strokeColor=#006EAF;" vertex="1" parent="1">
|
||||
<mxGeometry x="207.5" y="440" width="140" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-6" value="name" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-5">
|
||||
<mxGeometry y="30" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-9" value="public.admins" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#1ba1e2;fontColor=#ffffff;strokeColor=#006EAF;" vertex="1" parent="1">
|
||||
<mxGeometry x="243" y="60" width="175" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-10" value="PK FK Unique uuid user_id" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-9">
|
||||
<mxGeometry y="30" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-11" value="assigned_date:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-9">
|
||||
<mxGeometry y="60" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-12" value="assigner_id:uuid?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-9">
|
||||
<mxGeometry y="90" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-17" value="auth.users" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#0050ef;fontColor=#ffffff;strokeColor=#001DBC;" vertex="1" parent="1">
|
||||
<mxGeometry x="10" y="120" width="140" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-18" value="id" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-17">
|
||||
<mxGeometry y="30" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#0050ef;strokeColor=#001DBC;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-18" target="1AZqCnQGpeGdDfHHl4o8-10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-22" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#0050ef;strokeColor=#001DBC;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-18" target="1AZqCnQGpeGdDfHHl4o8-14">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-23" value="public.tier" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#a20025;fontColor=#ffffff;strokeColor=#6F0000;" vertex="1" parent="1">
|
||||
<mxGeometry x="32.5" y="290" width="140" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-24" value="PK name:text" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-23">
|
||||
<mxGeometry y="30" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-25" value="price:decimal" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-23">
|
||||
<mxGeometry y="60" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-26" value="stripe_product_id:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-23">
|
||||
<mxGeometry y="90" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#a20025;strokeColor=#6F0000;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-24" target="1AZqCnQGpeGdDfHHl4o8-15">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-34" value="public.galleries" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#1ba1e2;fontColor=#ffffff;strokeColor=#006EAF;" vertex="1" parent="1">
|
||||
<mxGeometry x="497.5" y="320" width="140" height="180" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-35" value="PK string name" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-34">
|
||||
<mxGeometry y="30" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-37" value="FK tier string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-34">
|
||||
<mxGeometry y="60" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-38" value="string thumbnail_file" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-34">
|
||||
<mxGeometry y="90" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-41" value="bool nsfw" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-34">
|
||||
<mxGeometry y="120" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-39" value="text[] tags" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-34">
|
||||
<mxGeometry y="150" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-42" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#a20025;strokeColor=#6F0000;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-24" target="1AZqCnQGpeGdDfHHl4o8-37">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="207.5" y="335" />
|
||||
<mxPoint x="207.5" y="395" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-43" value="public.skibs" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#1ba1e2;fontColor=#ffffff;strokeColor=#006EAF;" vertex="1" parent="1">
|
||||
<mxGeometry x="499.5" width="140" height="300" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-44" value="PK AI id:&nbsp;int8" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="30" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-46" value="amount:decimal" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="60" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-49" value="user_id:uuid" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="90" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-50" value="request_date:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="120" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-51" value="accepted:bool?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="150" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-58" value="processed_date:date?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="180" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-52" value="payment_url:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="210" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-57" value="paidDate:date?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="240" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-59" value="completedDate:date?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="270" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-48" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;dashed=1;startArrow=classic;startFill=1;fillColor=#1ba1e2;strokeColor=#006EAF;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-6" target="1AZqCnQGpeGdDfHHl4o8-39">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-56" value="No FK Relationship" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontColor=#FFFFFF;labelBackgroundColor=none;" vertex="1" connectable="0" parent="1AZqCnQGpeGdDfHHl4o8-48">
|
||||
<mxGeometry x="-0.0082" y="2" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-13" value="public.user_subscriptions" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#1ba1e2;fontColor=#ffffff;strokeColor=#006EAF;" vertex="1" parent="1">
|
||||
<mxGeometry x="243" y="203" width="175" height="180" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-14" value="PK FK Unique user_id:uuid" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-13">
|
||||
<mxGeometry y="30" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-15" value="FK tier:text" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-13">
|
||||
<mxGeometry y="60" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-54" value="active:bool" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-13">
|
||||
<mxGeometry y="90" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-53" value="last_paid_date:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-13">
|
||||
<mxGeometry y="120" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-47" value="start_date:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-13">
|
||||
<mxGeometry y="150" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-55" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#0050ef;strokeColor=#001DBC;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-18" target="1AZqCnQGpeGdDfHHl4o8-49">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="197.5" y="165" />
|
||||
<mxPoint x="197.5" y="30" />
|
||||
<mxPoint x="447.5" y="30" />
|
||||
<mxPoint x="447.5" y="105" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-60" value="public.commissions" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#1ba1e2;fontColor=#ffffff;strokeColor=#006EAF;" vertex="1" parent="1">
|
||||
<mxGeometry x="697.5" y="30" width="170" height="330" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-61" value="PK AI id:&nbsp;int8" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="30" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-62" value="amount:decimal" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="60" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-63" value="user_id:uuid" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="90" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-64" value="request_date:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="120" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-65" value="accepted:bool?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="150" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-66" value="processed_date:date?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="180" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-67" value="hours:number" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="210" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-70" value="pending_approval:bool false" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="240" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-68" value="paidDate:date?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="270" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-69" value="completedDate:date?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="300" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-71" value="public.comission_messages" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#1ba1e2;fontColor=#ffffff;strokeColor=#006EAF;" vertex="1" parent="1">
|
||||
<mxGeometry x="957.5" y="180" width="210" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-72" value="PK AI id:int8" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-71">
|
||||
<mxGeometry y="30" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-73" value="FK comission_id:int8" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-71">
|
||||
<mxGeometry y="60" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-74" value="FK sender_id:uuid" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-71">
|
||||
<mxGeometry y="90" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-79" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#0050ef;strokeColor=#001DBC;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-18" target="1AZqCnQGpeGdDfHHl4o8-63">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="197.5" y="165" />
|
||||
<mxPoint x="197.5" y="30" />
|
||||
<mxPoint x="447.5" y="30" />
|
||||
<mxPoint x="447.5" y="-30" />
|
||||
<mxPoint x="667.5" y="-30" />
|
||||
<mxPoint x="667.5" y="135" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-80" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#1ba1e2;strokeColor=#006EAF;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-61" target="1AZqCnQGpeGdDfHHl4o8-73">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-81" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#0050ef;strokeColor=#001DBC;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-18" target="1AZqCnQGpeGdDfHHl4o8-74">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="197.5" y="165" />
|
||||
<mxPoint x="197.5" y="30" />
|
||||
<mxPoint x="447.5" y="30" />
|
||||
<mxPoint x="447.5" y="-30" />
|
||||
<mxPoint x="667.5" y="-30" />
|
||||
<mxPoint x="667.5" y="400" />
|
||||
<mxPoint x="897.5" y="400" />
|
||||
<mxPoint x="897.5" y="285" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
1
docs/.obsidian/app.json
vendored
Normal file
1
docs/.obsidian/app.json
vendored
Normal file
@ -0,0 +1 @@
|
||||
{}
|
3
docs/.obsidian/appearance.json
vendored
Normal file
3
docs/.obsidian/appearance.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"accentColor": ""
|
||||
}
|
30
docs/.obsidian/core-plugins-migration.json
vendored
Normal file
30
docs/.obsidian/core-plugins-migration.json
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"file-explorer": true,
|
||||
"global-search": true,
|
||||
"switcher": true,
|
||||
"graph": true,
|
||||
"backlink": true,
|
||||
"canvas": true,
|
||||
"outgoing-link": true,
|
||||
"tag-pane": true,
|
||||
"properties": false,
|
||||
"page-preview": true,
|
||||
"daily-notes": true,
|
||||
"templates": true,
|
||||
"note-composer": true,
|
||||
"command-palette": true,
|
||||
"slash-command": false,
|
||||
"editor-status": true,
|
||||
"bookmarks": true,
|
||||
"markdown-importer": false,
|
||||
"zk-prefixer": false,
|
||||
"random-note": false,
|
||||
"outline": true,
|
||||
"word-count": true,
|
||||
"slides": false,
|
||||
"audio-recorder": false,
|
||||
"workspaces": false,
|
||||
"file-recovery": true,
|
||||
"publish": false,
|
||||
"sync": false
|
||||
}
|
20
docs/.obsidian/core-plugins.json
vendored
Normal file
20
docs/.obsidian/core-plugins.json
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
[
|
||||
"file-explorer",
|
||||
"global-search",
|
||||
"switcher",
|
||||
"graph",
|
||||
"backlink",
|
||||
"canvas",
|
||||
"outgoing-link",
|
||||
"tag-pane",
|
||||
"page-preview",
|
||||
"daily-notes",
|
||||
"templates",
|
||||
"note-composer",
|
||||
"command-palette",
|
||||
"editor-status",
|
||||
"bookmarks",
|
||||
"outline",
|
||||
"word-count",
|
||||
"file-recovery"
|
||||
]
|
22
docs/.obsidian/graph.json
vendored
Normal file
22
docs/.obsidian/graph.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"collapse-filter": true,
|
||||
"search": "",
|
||||
"showTags": false,
|
||||
"showAttachments": false,
|
||||
"hideUnresolved": false,
|
||||
"showOrphans": true,
|
||||
"collapse-color-groups": true,
|
||||
"colorGroups": [],
|
||||
"collapse-display": true,
|
||||
"showArrow": false,
|
||||
"textFadeMultiplier": 0,
|
||||
"nodeSizeMultiplier": 1,
|
||||
"lineSizeMultiplier": 1,
|
||||
"collapse-forces": true,
|
||||
"centerStrength": 0.518713248970312,
|
||||
"repelStrength": 10,
|
||||
"linkStrength": 1,
|
||||
"linkDistance": 250,
|
||||
"scale": 1,
|
||||
"close": true
|
||||
}
|
155
docs/.obsidian/workspace.json
vendored
Normal file
155
docs/.obsidian/workspace.json
vendored
Normal file
@ -0,0 +1,155 @@
|
||||
{
|
||||
"main": {
|
||||
"id": "bdde2e17ec0df42a",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "dedd2ccd270be348",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "b4a8432d18575240",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "Tutorials n Documentation.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"direction": "vertical"
|
||||
},
|
||||
"left": {
|
||||
"id": "c320d60637cee9e0",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "57d6275bac376e39",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "c2afa69ba2c55138",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "file-explorer",
|
||||
"state": {
|
||||
"sortOrder": "alphabetical"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "81438d0c2baf979f",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "search",
|
||||
"state": {
|
||||
"query": "",
|
||||
"matchingCase": false,
|
||||
"explainSearch": false,
|
||||
"collapseAll": false,
|
||||
"extraContext": false,
|
||||
"sortOrder": "alphabetical"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "956885082129707c",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "bookmarks",
|
||||
"state": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"direction": "horizontal",
|
||||
"width": 300
|
||||
},
|
||||
"right": {
|
||||
"id": "c47f5eb80efc5acc",
|
||||
"type": "split",
|
||||
"children": [
|
||||
{
|
||||
"id": "25ec1b8698cf7037",
|
||||
"type": "tabs",
|
||||
"children": [
|
||||
{
|
||||
"id": "5a51e0522b80dc8c",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "backlink",
|
||||
"state": {
|
||||
"file": "Tutorials n Documentation.md",
|
||||
"collapseAll": false,
|
||||
"extraContext": false,
|
||||
"sortOrder": "alphabetical",
|
||||
"showSearch": false,
|
||||
"searchQuery": "",
|
||||
"backlinkCollapsed": false,
|
||||
"unlinkedCollapsed": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ce2e95cdf68332b3",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "outgoing-link",
|
||||
"state": {
|
||||
"file": "Tutorials n Documentation.md",
|
||||
"linksCollapsed": false,
|
||||
"unlinkedCollapsed": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "dde7495b53a68d31",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "tag",
|
||||
"state": {
|
||||
"sortOrder": "frequency",
|
||||
"useHierarchy": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "b3cfc60f37fb32d5",
|
||||
"type": "leaf",
|
||||
"state": {
|
||||
"type": "outline",
|
||||
"state": {
|
||||
"file": "Tutorials n Documentation.md"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"direction": "horizontal",
|
||||
"width": 300,
|
||||
"collapsed": true
|
||||
},
|
||||
"left-ribbon": {
|
||||
"hiddenItems": {
|
||||
"switcher:Open quick switcher": false,
|
||||
"graph:Open graph view": false,
|
||||
"canvas:Create new canvas": false,
|
||||
"daily-notes:Open today's daily note": false,
|
||||
"templates:Insert template": false,
|
||||
"command-palette:Open command palette": false
|
||||
}
|
||||
},
|
||||
"active": "b4a8432d18575240",
|
||||
"lastOpenFiles": [
|
||||
"Pasted image 20240523235540.png",
|
||||
"Tutorials n Documentation.md",
|
||||
"Welcome.md"
|
||||
]
|
||||
}
|
9
docs/Tutorials n Documentation.md
Normal file
9
docs/Tutorials n Documentation.md
Normal file
@ -0,0 +1,9 @@
|
||||
- https://supabase.com/docs/guides/getting-started/architecture
|
||||
- https://supabase.com/docs/guides/auth/social-login/auth-discord
|
||||
- https://supabase.com/docs/guides/auth/social-login/auth-twitter
|
||||
- https://github.com/vercel/nextjs-subscription-payments
|
||||
- https://postgrest.org/en/v12/
|
||||
- https://supabase.github.io/storage/
|
||||
- https://api.supabase.com/api/v1
|
||||
- https://supabase.com/docs/guides/api/sql-to-rest
|
||||
|
503
docs/diagrams.drawio
Normal file
503
docs/diagrams.drawio
Normal file
@ -0,0 +1,503 @@
|
||||
<mxfile host="Electron" modified="2024-06-04T04:27:06.049Z" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/24.2.5 Chrome/120.0.6099.109 Electron/28.1.0 Safari/537.36" etag="nuI_NnP1br-4Uuhgp7xU" version="24.2.5" type="device">
|
||||
<diagram name="Page-1" id="F3YAVjulPUqdYhbqfjdd">
|
||||
<mxGraphModel dx="1877" dy="2420" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-28" value="<h1>Database Design</h1>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="332.5" y="-70" width="390" height="10" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-29" value="<h1>UX Flow</h1>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="30" y="620" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-37" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-33" target="9zziB1Dtd-V9IfowJO3V-36" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-33" value="Actor" style="shape=umlActor;verticalLabelPosition=bottom;verticalAlign=top;html=1;outlineConnect=0;" parent="1" vertex="1">
|
||||
<mxGeometry x="35" y="690" width="30" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-39" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-36" target="9zziB1Dtd-V9IfowJO3V-38" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-36" value="Open Site" style="whiteSpace=wrap;html=1;verticalAlign=top;" parent="1" vertex="1">
|
||||
<mxGeometry x="105" y="705" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-42" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-38" target="9zziB1Dtd-V9IfowJO3V-41" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-43" value="No" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-42" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.2533" y="2" relative="1" as="geometry">
|
||||
<mxPoint x="2" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-48" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-38" target="9zziB1Dtd-V9IfowJO3V-47" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-72" value="Yes" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-48" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.2273" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-73" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=1;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-38" target="9zziB1Dtd-V9IfowJO3V-71" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="265" y="740" />
|
||||
<mxPoint x="265" y="795" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-74" value="Yes" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-73" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.0411" y="1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-82" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-38" target="9zziB1Dtd-V9IfowJO3V-81" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="305" y="890" />
|
||||
<mxPoint x="93" y="890" />
|
||||
<mxPoint x="93" y="940" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-83" value="Yes" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-82" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.8649" y="-1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-92" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-38" target="9zziB1Dtd-V9IfowJO3V-91" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-93" value="Yes" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-92" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.6335" y="-2" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-38" value="<br>Logged<br>In" style="rhombus;whiteSpace=wrap;html=1;verticalAlign=top;" parent="1" vertex="1">
|
||||
<mxGeometry x="265" y="680" width="80" height="80" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-46" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-41" target="9zziB1Dtd-V9IfowJO3V-45" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-41" value="Login/Signup Page" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#a20025;strokeColor=#6F0000;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="245" y="620" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-49" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;dashed=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-45" target="9zziB1Dtd-V9IfowJO3V-47" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-50" value="Click Activation<br>Email Link" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-49" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.1683" y="1" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-45" value="Send Confirmation Email" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#a20025;strokeColor=#6F0000;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="235" y="560" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-52" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-47" target="9zziB1Dtd-V9IfowJO3V-51" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="540" y="716.31" as="sourcePoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-47" value="Gallery Page" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="440" y="705" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-54" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-51" target="9zziB1Dtd-V9IfowJO3V-53" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-51" value="Search By Title &amp;<br>Filter By Tag" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="642" y="698.02" width="120" height="45" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-55" value="Refine Search" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-53" target="9zziB1Dtd-V9IfowJO3V-51" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-57" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-53" target="9zziB1Dtd-V9IfowJO3V-56" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-53" value="Browse Galleries" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="802" y="704.27" width="120" height="32.5" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-59" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-56" target="9zziB1Dtd-V9IfowJO3V-58" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-56" value="Open Gallery" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="802" y="780.52" width="120" height="32.5" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-61" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-58" target="9zziB1Dtd-V9IfowJO3V-60" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-63" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-58" target="9zziB1Dtd-V9IfowJO3V-62" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-65" value="Directional<br>Buttons" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-63" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.1714" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-69" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-58" target="9zziB1Dtd-V9IfowJO3V-68" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="742" y="850.52" />
|
||||
<mxPoint x="742" y="840.52" />
|
||||
<mxPoint x="732" y="840.52" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-58" value="Enlarge Image &amp;&nbsp;<br>Pan/Zoom" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="802" y="840.52" width="120" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-60" value="Download Image" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="802" y="900.52" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-64" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-62" target="9zziB1Dtd-V9IfowJO3V-58" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="672" y="960.52" />
|
||||
<mxPoint x="782" y="960.52" />
|
||||
<mxPoint x="782" y="870.52" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-62" value="Next/Previous<br>Image" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="612" y="890.52" width="120" height="40" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-70" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-68" target="9zziB1Dtd-V9IfowJO3V-56" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<mxPoint x="762" y="797.39" as="sourcePoint" />
|
||||
<mxPoint x="792" y="796.14" as="targetPoint" />
|
||||
<Array as="points">
|
||||
<mxPoint x="762" y="796.52" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-68" value="Close Image" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#1ba1e2;strokeColor=#006EAF;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="642" y="787.52" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-76" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-71" target="9zziB1Dtd-V9IfowJO3V-75" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-78" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-71" target="9zziB1Dtd-V9IfowJO3V-77" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-71" value="Livestream Page" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#d80073;strokeColor=#A50040;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="125" y="780" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-75" value="Watch Stream" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#d80073;strokeColor=#A50040;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="125" y="840" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-77" value="Chat" style="whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#d80073;strokeColor=#A50040;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="12.5" y="780" width="75" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-85" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" source="9zziB1Dtd-V9IfowJO3V-81" target="9zziB1Dtd-V9IfowJO3V-84" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-87" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" source="9zziB1Dtd-V9IfowJO3V-81" target="9zziB1Dtd-V9IfowJO3V-86" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-81" value="Subscriptions Page" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#6a00ff;strokeColor=#3700CC;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="32.5" y="940" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-84" value="View Current Tier" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#6a00ff;strokeColor=#3700CC;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="32.5" y="990" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-89" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" source="9zziB1Dtd-V9IfowJO3V-86" target="9zziB1Dtd-V9IfowJO3V-88" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-86" value="View Available Tiers" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#6a00ff;strokeColor=#3700CC;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="187.5" y="940" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-90" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" source="9zziB1Dtd-V9IfowJO3V-88" target="9zziB1Dtd-V9IfowJO3V-84" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-88" value="Upgrade Tier" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#6a00ff;strokeColor=#3700CC;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="187.5" y="990" width="120" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-95" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-91" target="9zziB1Dtd-V9IfowJO3V-94" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="410" y="810" />
|
||||
<mxPoint x="360" y="810" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-100" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-91" target="9zziB1Dtd-V9IfowJO3V-99" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-91" value="Commissions Page" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#60a917;strokeColor=#2D7600;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="350" y="770" width="120" height="27.48" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-97" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" parent="1" source="9zziB1Dtd-V9IfowJO3V-94" target="9zziB1Dtd-V9IfowJO3V-96" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-98" value="Yes" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-97" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.6109" relative="1" as="geometry">
|
||||
<mxPoint x="20" y="2" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-105" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-94" target="9zziB1Dtd-V9IfowJO3V-110" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-106" value="No" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-105" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.1779" y="-2" relative="1" as="geometry">
|
||||
<mxPoint y="-2" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-94" value="Has Existing<br>Commission" style="rhombus;whiteSpace=wrap;html=1;rounded=0;fillColor=#60a917;strokeColor=#2D7600;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="310" y="830.52" width="100" height="100" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-101" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-96" target="9zziB1Dtd-V9IfowJO3V-99" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-96" value="View Existing<br>Commission Status" style="whiteSpace=wrap;html=1;rounded=0;fillColor=#60a917;strokeColor=#2D7600;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="350" y="970" width="120" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-99" value="View All Commissions" style="rounded=0;whiteSpace=wrap;html=1;fillColor=#60a917;strokeColor=#2D7600;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="500" y="770" width="130" height="27.48" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-109" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-104" target="9zziB1Dtd-V9IfowJO3V-96" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="560" y="985" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-104" value="Request New<br>Commission" style="whiteSpace=wrap;html=1;fillColor=#60a917;strokeColor=#2D7600;rounded=0;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="470" y="817.52" width="120" height="39.48" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-111" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=1;exitDx=0;exitDy=0;entryX=0.75;entryY=0;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-110" target="9zziB1Dtd-V9IfowJO3V-96" edge="1">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="440" y="930" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-112" value="No" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-111" vertex="1" connectable="0">
|
||||
<mxGeometry x="0.0044" relative="1" as="geometry">
|
||||
<mxPoint y="5" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-113" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" parent="1" source="9zziB1Dtd-V9IfowJO3V-110" target="9zziB1Dtd-V9IfowJO3V-104" edge="1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-114" value="Yes" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="9zziB1Dtd-V9IfowJO3V-113" vertex="1" connectable="0">
|
||||
<mxGeometry x="-0.5043" y="1" relative="1" as="geometry">
|
||||
<mxPoint x="3" y="-1" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="9zziB1Dtd-V9IfowJO3V-110" value="Requests<br>Open" style="rhombus;whiteSpace=wrap;html=1;rounded=0;fillColor=#60a917;strokeColor=#2D7600;fontColor=#ffffff;" parent="1" vertex="1">
|
||||
<mxGeometry x="440" y="860.52" width="79.48" height="79.48" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-5" value="public.tags" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#1ba1e2;fontColor=#ffffff;strokeColor=#006EAF;" vertex="1" parent="1">
|
||||
<mxGeometry x="207.5" y="440" width="140" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-6" value="name" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-5">
|
||||
<mxGeometry y="30" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-9" value="public.admins" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#1ba1e2;fontColor=#ffffff;strokeColor=#006EAF;" vertex="1" parent="1">
|
||||
<mxGeometry x="243" y="60" width="175" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-10" value="PK FK Unique uuid user_id" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-9">
|
||||
<mxGeometry y="30" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-11" value="assigned_date:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-9">
|
||||
<mxGeometry y="60" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-12" value="assigner_id:uuid?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-9">
|
||||
<mxGeometry y="90" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-17" value="auth.users" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#0050ef;fontColor=#ffffff;strokeColor=#001DBC;" vertex="1" parent="1">
|
||||
<mxGeometry x="10" y="120" width="140" height="60" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-18" value="id" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-17">
|
||||
<mxGeometry y="30" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#0050ef;strokeColor=#001DBC;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-18" target="1AZqCnQGpeGdDfHHl4o8-10">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-22" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#0050ef;strokeColor=#001DBC;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-18" target="1AZqCnQGpeGdDfHHl4o8-14">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-23" value="public.tier" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#a20025;fontColor=#ffffff;strokeColor=#6F0000;" vertex="1" parent="1">
|
||||
<mxGeometry x="32.5" y="290" width="140" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-24" value="PK name:text" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-23">
|
||||
<mxGeometry y="30" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-25" value="price:decimal" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-23">
|
||||
<mxGeometry y="60" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-26" value="stripe_product_id:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-23">
|
||||
<mxGeometry y="90" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#a20025;strokeColor=#6F0000;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-24" target="1AZqCnQGpeGdDfHHl4o8-15">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-34" value="public.galleries" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#1ba1e2;fontColor=#ffffff;strokeColor=#006EAF;" vertex="1" parent="1">
|
||||
<mxGeometry x="497.5" y="320" width="140" height="180" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-35" value="PK string name" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-34">
|
||||
<mxGeometry y="30" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-37" value="FK tier string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-34">
|
||||
<mxGeometry y="60" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-38" value="string thumbnail_file" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-34">
|
||||
<mxGeometry y="90" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-41" value="bool nsfw" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-34">
|
||||
<mxGeometry y="120" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-39" value="text[] tags" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-34">
|
||||
<mxGeometry y="150" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-42" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#a20025;strokeColor=#6F0000;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-24" target="1AZqCnQGpeGdDfHHl4o8-37">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="207.5" y="335" />
|
||||
<mxPoint x="207.5" y="395" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-43" value="public.skibs" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#1ba1e2;fontColor=#ffffff;strokeColor=#006EAF;" vertex="1" parent="1">
|
||||
<mxGeometry x="499.5" width="140" height="300" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-44" value="PK AI id:&nbsp;int8" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="30" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-46" value="amount:decimal" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="60" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-49" value="user_id:uuid" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="90" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-50" value="request_date:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="120" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-51" value="accepted:bool?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="150" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-58" value="processed_date:date?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="180" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-52" value="payment_url:string" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="210" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-57" value="paidDate:date?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="240" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-59" value="completedDate:date?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-43">
|
||||
<mxGeometry y="270" width="140" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-48" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;dashed=1;startArrow=classic;startFill=1;fillColor=#1ba1e2;strokeColor=#006EAF;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-6" target="1AZqCnQGpeGdDfHHl4o8-39">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-56" value="No FK Relationship" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontColor=#FFFFFF;labelBackgroundColor=none;" vertex="1" connectable="0" parent="1AZqCnQGpeGdDfHHl4o8-48">
|
||||
<mxGeometry x="-0.0082" y="2" relative="1" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-13" value="public.user_subscriptions" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#1ba1e2;fontColor=#ffffff;strokeColor=#006EAF;" vertex="1" parent="1">
|
||||
<mxGeometry x="243" y="203" width="175" height="180" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-14" value="PK FK Unique user_id:uuid" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-13">
|
||||
<mxGeometry y="30" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-15" value="FK tier:text" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-13">
|
||||
<mxGeometry y="60" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-54" value="active:bool" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-13">
|
||||
<mxGeometry y="90" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-53" value="last_paid_date:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-13">
|
||||
<mxGeometry y="120" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-47" value="start_date:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-13">
|
||||
<mxGeometry y="150" width="175" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-55" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#0050ef;strokeColor=#001DBC;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-18" target="1AZqCnQGpeGdDfHHl4o8-49">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="197.5" y="165" />
|
||||
<mxPoint x="197.5" y="30" />
|
||||
<mxPoint x="447.5" y="30" />
|
||||
<mxPoint x="447.5" y="105" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-60" value="public.commissions" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#1ba1e2;fontColor=#ffffff;strokeColor=#006EAF;" vertex="1" parent="1">
|
||||
<mxGeometry x="697.5" y="30" width="170" height="330" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-61" value="PK AI id:&nbsp;int8" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="30" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-62" value="amount:decimal" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="60" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-63" value="user_id:uuid" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="90" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-64" value="request_date:date" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="120" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-65" value="accepted:bool?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="150" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-66" value="processed_date:date?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="180" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-67" value="hours:number" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="210" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-70" value="pending_approval:bool false" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="240" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-68" value="paidDate:date?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="270" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-69" value="completedDate:date?" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-60">
|
||||
<mxGeometry y="300" width="170" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-71" value="public.comission_messages" style="swimlane;fontStyle=0;childLayout=stackLayout;horizontal=1;startSize=30;horizontalStack=0;resizeParent=1;resizeParentMax=0;resizeLast=0;collapsible=1;marginBottom=0;whiteSpace=wrap;html=1;fillColor=#1ba1e2;fontColor=#ffffff;strokeColor=#006EAF;" vertex="1" parent="1">
|
||||
<mxGeometry x="957.5" y="180" width="210" height="120" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-72" value="PK AI id:int8" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-71">
|
||||
<mxGeometry y="30" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-73" value="FK comission_id:int8" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-71">
|
||||
<mxGeometry y="60" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-74" value="FK sender_id:uuid" style="text;strokeColor=none;fillColor=none;align=left;verticalAlign=middle;spacingLeft=4;spacingRight=4;overflow=hidden;points=[[0,0.5],[1,0.5]];portConstraint=eastwest;rotatable=0;whiteSpace=wrap;html=1;" vertex="1" parent="1AZqCnQGpeGdDfHHl4o8-71">
|
||||
<mxGeometry y="90" width="210" height="30" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-79" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#0050ef;strokeColor=#001DBC;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-18" target="1AZqCnQGpeGdDfHHl4o8-63">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="197.5" y="165" />
|
||||
<mxPoint x="197.5" y="30" />
|
||||
<mxPoint x="447.5" y="30" />
|
||||
<mxPoint x="447.5" y="-30" />
|
||||
<mxPoint x="667.5" y="-30" />
|
||||
<mxPoint x="667.5" y="135" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-80" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#1ba1e2;strokeColor=#006EAF;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-61" target="1AZqCnQGpeGdDfHHl4o8-73">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="1AZqCnQGpeGdDfHHl4o8-81" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fillColor=#0050ef;strokeColor=#001DBC;" edge="1" parent="1" source="1AZqCnQGpeGdDfHHl4o8-18" target="1AZqCnQGpeGdDfHHl4o8-74">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="197.5" y="165" />
|
||||
<mxPoint x="197.5" y="30" />
|
||||
<mxPoint x="447.5" y="30" />
|
||||
<mxPoint x="447.5" y="-30" />
|
||||
<mxPoint x="667.5" y="-30" />
|
||||
<mxPoint x="667.5" y="400" />
|
||||
<mxPoint x="897.5" y="400" />
|
||||
<mxPoint x="897.5" y="285" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
20
middleware.ts
Normal file
20
middleware.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { type NextRequest } from "next/server";
|
||||
import { updateSession } from "@/utils/supabase/middleware";
|
||||
|
||||
export async function middleware(request: NextRequest) {
|
||||
return await updateSession(request);
|
||||
}
|
||||
|
||||
export const config = {
|
||||
matcher: [
|
||||
/*
|
||||
* Match all request paths except:
|
||||
* - _next/static (static files)
|
||||
* - _next/image (image optimization files)
|
||||
* - favicon.ico (favicon file)
|
||||
* - images - .svg, .png, .jpg, .jpeg, .gif, .webp
|
||||
* Feel free to modify this pattern to include more paths.
|
||||
*/
|
||||
"/((?!_next/static|_next/image|favicon.ico|.*\\.(?:svg|png|jpg|jpeg|gif|webp)$).*)",
|
||||
],
|
||||
};
|
36
neroshitron/.gitignore
vendored
Normal file
36
neroshitron/.gitignore
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
.yarn/install-state.gz
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env*.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
93
neroshitron/README.md
Normal file
93
neroshitron/README.md
Normal file
@ -0,0 +1,93 @@
|
||||
<a href="https://demo-nextjs-with-supabase.vercel.app/">
|
||||
<img alt="Next.js and Supabase Starter Kit - the fastest way to build apps with Next.js and Supabase" src="https://demo-nextjs-with-supabase.vercel.app/opengraph-image.png">
|
||||
<h1 align="center">Next.js and Supabase Starter Kit</h1>
|
||||
</a>
|
||||
|
||||
<p align="center">
|
||||
The fastest way to build apps with Next.js and Supabase
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="#features"><strong>Features</strong></a> ·
|
||||
<a href="#demo"><strong>Demo</strong></a> ·
|
||||
<a href="#deploy-to-vercel"><strong>Deploy to Vercel</strong></a> ·
|
||||
<a href="#clone-and-run-locally"><strong>Clone and run locally</strong></a> ·
|
||||
<a href="#feedback-and-issues"><strong>Feedback and issues</strong></a>
|
||||
<a href="#more-supabase-examples"><strong>More Examples</strong></a>
|
||||
</p>
|
||||
<br/>
|
||||
|
||||
## Features
|
||||
|
||||
- Works across the entire [Next.js](https://nextjs.org) stack
|
||||
- App Router
|
||||
- Pages Router
|
||||
- Middleware
|
||||
- Client
|
||||
- Server
|
||||
- It just works!
|
||||
- supabase-ssr. A package to configure Supabase Auth to use cookies
|
||||
- Styling with [Tailwind CSS](https://tailwindcss.com)
|
||||
- Optional deployment with [Supabase Vercel Integration and Vercel deploy](#deploy-your-own)
|
||||
- Environment variables automatically assigned to Vercel project
|
||||
|
||||
## Demo
|
||||
|
||||
You can view a fully working demo at [demo-nextjs-with-supabase.vercel.app](https://demo-nextjs-with-supabase.vercel.app/).
|
||||
|
||||
## Deploy to Vercel
|
||||
|
||||
Vercel deployment will guide you through creating a Supabase account and project.
|
||||
|
||||
After installation of the Supabase integration, all relevant environment variables will be assigned to the project so the deployment is fully functioning.
|
||||
|
||||
[](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-supabase&project-name=nextjs-with-supabase&repository-name=nextjs-with-supabase&demo-title=nextjs-with-supabase&demo-description=This%20starter%20configures%20Supabase%20Auth%20to%20use%20cookies%2C%20making%20the%20user's%20session%20available%20throughout%20the%20entire%20Next.js%20app%20-%20Client%20Components%2C%20Server%20Components%2C%20Route%20Handlers%2C%20Server%20Actions%20and%20Middleware.&demo-url=https%3A%2F%2Fdemo-nextjs-with-supabase.vercel.app%2F&external-id=https%3A%2F%2Fgithub.com%2Fvercel%2Fnext.js%2Ftree%2Fcanary%2Fexamples%2Fwith-supabase&demo-image=https%3A%2F%2Fdemo-nextjs-with-supabase.vercel.app%2Fopengraph-image.png&integration-ids=oac_VqOgBHqhEoFTPzGkPd7L0iH6)
|
||||
|
||||
The above will also clone the Starter kit to your GitHub, you can clone that locally and develop locally.
|
||||
|
||||
If you wish to just develop locally and not deploy to Vercel, [follow the steps below](#clone-and-run-locally).
|
||||
|
||||
## Clone and run locally
|
||||
|
||||
1. You'll first need a Supabase project which can be made [via the Supabase dashboard](https://database.new)
|
||||
|
||||
2. Create a Next.js app using the Supabase Starter template npx command
|
||||
|
||||
```bash
|
||||
npx create-next-app -e with-supabase
|
||||
```
|
||||
|
||||
3. Use `cd` to change into the app's directory
|
||||
|
||||
```bash
|
||||
cd name-of-new-app
|
||||
```
|
||||
|
||||
4. Rename `.env.local.example` to `.env.local` and update the following:
|
||||
|
||||
```
|
||||
NEXT_PUBLIC_SUPABASE_URL=[INSERT SUPABASE PROJECT URL]
|
||||
NEXT_PUBLIC_SUPABASE_ANON_KEY=[INSERT SUPABASE PROJECT API ANON KEY]
|
||||
```
|
||||
|
||||
Both `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY` can be found in [your Supabase project's API settings](https://app.supabase.com/project/_/settings/api)
|
||||
|
||||
5. You can now run the Next.js local development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
The starter kit should now be running on [localhost:3000](http://localhost:3000/).
|
||||
|
||||
> Check out [the docs for Local Development](https://supabase.com/docs/guides/getting-started/local-development) to also run Supabase locally.
|
||||
|
||||
## Feedback and issues
|
||||
|
||||
Please file feedback and issues over on the [Supabase GitHub org](https://github.com/supabase/supabase/issues/new/choose).
|
||||
|
||||
## More Supabase examples
|
||||
|
||||
- [Next.js Subscription Payments Starter](https://github.com/vercel/nextjs-subscription-payments)
|
||||
- [Cookie-based Auth and the Next.js 13 App Router (free course)](https://youtube.com/playlist?list=PL5S4mPUpp4OtMhpnp93EFSo42iQ40XjbF)
|
||||
- [Supabase Auth and the Next.js App Router](https://github.com/supabase/supabase/tree/master/examples/auth/nextjs)
|
@ -1,16 +1,4 @@
|
||||
const { withTamagui } = require('@tamagui/next-plugin')
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {};
|
||||
|
||||
module.exports = function (name, { defaultConfig }) {
|
||||
let config = {
|
||||
...defaultConfig,
|
||||
// ...your configuration
|
||||
}
|
||||
const tamaguiPlugin = withTamagui({
|
||||
config: './tamagui.config.ts',
|
||||
components: ['tamagui'],
|
||||
})
|
||||
return {
|
||||
...config,
|
||||
...tamaguiPlugin(config),
|
||||
}
|
||||
}
|
||||
module.exports = nextConfig;
|
||||
|
15091
package-lock.json
generated
15091
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
50
package.json
50
package.json
@ -1,22 +1,44 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"@tamagui/config": "^1.98.2",
|
||||
"@tamagui/next-plugin": "^1.98.2",
|
||||
"@tamagui/next-theme": "^1.98.2",
|
||||
"next": "^14.2.3",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-native-web": "^0.19.11",
|
||||
"tamagui": "^1.98.2"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@supabase/ssr": "latest",
|
||||
"@supabase/supabase-js": "latest",
|
||||
"@tailwindcss/aspect-ratio": "^0.4.2",
|
||||
"@vercel/analytics": "^1.3.1",
|
||||
"@vercel/speed-insights": "^1.0.11",
|
||||
"autoprefixer": "10.4.17",
|
||||
"clsx": "^2.1.1",
|
||||
"framer-motion": "^11.2.6",
|
||||
"geist": "^1.2.1",
|
||||
"md5": "^2.3.0",
|
||||
"next": "latest",
|
||||
"postcss": "8.4.33",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-easy-panzoom": "^0.4.4",
|
||||
"react-masonry-css": "^1.0.16",
|
||||
"react-responsive-masonry": "^2.2.0",
|
||||
"react-select": "^5.8.0",
|
||||
"react-tailwindcss-select": "^1.8.5",
|
||||
"sharp": "^0.33.4",
|
||||
"simplex-noise": "^4.0.1",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"tailwindcss": "3.4.1",
|
||||
"tailwindcss-animated": "^1.0.1",
|
||||
"tailwindcss-textshadow": "^2.1.3",
|
||||
"typescript": "5.3.3",
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "18.3.2",
|
||||
"typescript": "5.4.5"
|
||||
"@types/node": "20.11.5",
|
||||
"@types/react": "18.2.48",
|
||||
"@types/react-dom": "18.2.18",
|
||||
"encoding": "^0.1.13"
|
||||
}
|
||||
}
|
||||
|
@ -1,69 +0,0 @@
|
||||
// Optional: add the reset to get more consistent styles across browsers
|
||||
|
||||
import '@tamagui/core/reset.css'
|
||||
import { NextThemeProvider, useRootTheme } from '@tamagui/next-theme'
|
||||
|
||||
import { AppProps } from 'next/app'
|
||||
|
||||
import Head from 'next/head'
|
||||
|
||||
import React, { useMemo } from 'react'
|
||||
|
||||
import { TamaguiProvider, createTamagui } from 'tamagui'
|
||||
import { config } from '@tamagui/config/v3'
|
||||
|
||||
const tamaguiConfig = createTamagui(config)
|
||||
|
||||
// you usually export this from a tamagui.config.ts file:
|
||||
|
||||
// import tamaguiConfig from '../tamagui.config'
|
||||
// make TypeScript type everything based on your config
|
||||
|
||||
type Conf = typeof tamaguiConfig
|
||||
|
||||
declare module '@tamagui/core' {
|
||||
|
||||
interface TamaguiCustomConfig extends Conf {}
|
||||
|
||||
}
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
|
||||
const [theme, setTheme] = useRootTheme()
|
||||
// memo to avoid re-render on dark/light change
|
||||
|
||||
const contents = useMemo(() => {
|
||||
|
||||
return <Component {...pageProps} />
|
||||
|
||||
}, [pageProps])
|
||||
return (
|
||||
|
||||
<NextThemeProvider onChangeTheme={setTheme as any}>
|
||||
|
||||
<Head>
|
||||
|
||||
<script
|
||||
dangerouslySetInnerHTML={{
|
||||
// avoid flash of animated things on enter:
|
||||
__html: `document.documentElement.classList.add('t_unmounted')`,
|
||||
}}
|
||||
/>
|
||||
|
||||
</Head>
|
||||
|
||||
<TamaguiProvider
|
||||
config={tamaguiConfig}
|
||||
disableInjectCSS
|
||||
disableRootThemeClass
|
||||
defaultTheme={theme}
|
||||
>
|
||||
|
||||
{contents}
|
||||
|
||||
</TamaguiProvider>
|
||||
|
||||
</NextThemeProvider>
|
||||
|
||||
)
|
||||
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
import NextDocument, {
|
||||
|
||||
DocumentContext,
|
||||
|
||||
Head,
|
||||
|
||||
Html,
|
||||
|
||||
Main,
|
||||
|
||||
NextScript,
|
||||
|
||||
} from 'next/document'
|
||||
|
||||
import { StyleSheet } from 'react-native'
|
||||
|
||||
import { config } from '@tamagui/config/v3'
|
||||
import { createTamagui } from 'tamagui'
|
||||
|
||||
const tamaguiConfig = createTamagui(config)
|
||||
|
||||
// you usually export this from a tamagui.config.ts file:
|
||||
|
||||
// import tamaguiConfig from '../tamagui.config'
|
||||
export default class Document extends NextDocument {
|
||||
|
||||
static async getInitialProps({ renderPage }: DocumentContext) {
|
||||
|
||||
const page = await renderPage()
|
||||
// @ts-ignore RN doesn't have this type
|
||||
|
||||
const rnwStyle = StyleSheet.getSheet()
|
||||
return {
|
||||
|
||||
...page,
|
||||
|
||||
styles: (
|
||||
|
||||
<>
|
||||
|
||||
<style
|
||||
id={rnwStyle.id}
|
||||
dangerouslySetInnerHTML={{ __html: rnwStyle.textContent }}
|
||||
/>
|
||||
|
||||
<style
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: tamaguiConfig.getCSS(),
|
||||
}}
|
||||
/>
|
||||
|
||||
</>
|
||||
|
||||
),
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
|
||||
<Html lang="en">
|
||||
|
||||
<Head>
|
||||
|
||||
<meta id="theme-color" name="theme-color" />
|
||||
|
||||
<meta name="color-scheme" content="light dark" />
|
||||
|
||||
</Head>
|
||||
|
||||
<body>
|
||||
|
||||
<Main />
|
||||
|
||||
<NextScript />
|
||||
|
||||
</body>
|
||||
|
||||
</Html>
|
||||
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
export default async function handler(req, res): Promise<any> {
|
||||
let jsonString = generateRandomStringsAndJsonify(10, 5);
|
||||
res.status(200).json(jsonString);
|
||||
|
||||
}
|
||||
function generateRandomStringsAndJsonify(length, stringLength) {
|
||||
let result = [];
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
let randomString = '';
|
||||
for (let j = 0; j < stringLength; j++) {
|
||||
randomString += characters.charAt(Math.floor(Math.random() * characters.length));
|
||||
}
|
||||
result.push(randomString);
|
||||
}
|
||||
|
||||
return JSON.stringify(result);
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
import { useState } from 'react'
|
||||
|
||||
import { Button, useIsomorphicLayoutEffect } from 'tamagui'
|
||||
|
||||
import { useThemeSetting } from '@tamagui/next-theme'
|
||||
export default function Home() {
|
||||
|
||||
const themeSetting = useThemeSetting()
|
||||
|
||||
const [clientTheme, setClientTheme] = useState<string>('dark')
|
||||
useIsomorphicLayoutEffect(() => {
|
||||
|
||||
setClientTheme(themeSetting.current || 'dark')
|
||||
|
||||
}, [themeSetting.current, themeSetting.resolvedTheme])
|
||||
return <Button onPress={themeSetting.toggle}>Change theme: {clientTheme}</Button>
|
||||
|
||||
}
|
6
postcss.config.js
Normal file
6
postcss.config.js
Normal file
@ -0,0 +1,6 @@
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
};
|
BIN
public/gallery_girl.png
Normal file
BIN
public/gallery_girl.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 MiB |
4
supabase/.gitignore
vendored
Normal file
4
supabase/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
# Supabase
|
||||
.branches
|
||||
.temp
|
||||
.env
|
171
supabase/config.toml
Normal file
171
supabase/config.toml
Normal file
@ -0,0 +1,171 @@
|
||||
# A string used to distinguish different Supabase projects on the same host. Defaults to the
|
||||
# working directory name when running `supabase init`.
|
||||
project_id = "neroshitron"
|
||||
|
||||
[api]
|
||||
enabled = true
|
||||
# Port to use for the API URL.
|
||||
port = 54321
|
||||
# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API
|
||||
# endpoints. `public` is always included.
|
||||
schemas = ["public", "graphql_public"]
|
||||
# Extra schemas to add to the search_path of every request. `public` is always included.
|
||||
extra_search_path = ["public", "extensions"]
|
||||
# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size
|
||||
# for accidental or malicious requests.
|
||||
max_rows = 1000
|
||||
|
||||
[db]
|
||||
# Port to use for the local database URL.
|
||||
port = 54322
|
||||
# Port used by db diff command to initialize the shadow database.
|
||||
shadow_port = 54320
|
||||
# The database major version to use. This has to be the same as your remote database's. Run `SHOW
|
||||
# server_version;` on the remote database to check.
|
||||
major_version = 15
|
||||
|
||||
[db.pooler]
|
||||
enabled = false
|
||||
# Port to use for the local connection pooler.
|
||||
port = 54329
|
||||
# Specifies when a server connection can be reused by other clients.
|
||||
# Configure one of the supported pooler modes: `transaction`, `session`.
|
||||
pool_mode = "transaction"
|
||||
# How many server connections to allow per user/database pair.
|
||||
default_pool_size = 20
|
||||
# Maximum number of client connections allowed.
|
||||
max_client_conn = 100
|
||||
|
||||
[realtime]
|
||||
enabled = true
|
||||
# Bind realtime via either IPv4 or IPv6. (default: IPv4)
|
||||
# ip_version = "IPv6"
|
||||
# The maximum length in bytes of HTTP request headers. (default: 4096)
|
||||
# max_header_length = 4096
|
||||
|
||||
[studio]
|
||||
enabled = true
|
||||
# Port to use for Supabase Studio.
|
||||
port = 54323
|
||||
# External URL of the API server that frontend connects to.
|
||||
api_url = "http://127.0.0.1"
|
||||
# OpenAI API Key to use for Supabase AI in the Supabase Studio.
|
||||
openai_api_key = "env(OPENAI_API_KEY)"
|
||||
|
||||
# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they
|
||||
# are monitored, and you can view the emails that would have been sent from the web interface.
|
||||
[inbucket]
|
||||
enabled = true
|
||||
# Port to use for the email testing server web interface.
|
||||
port = 54324
|
||||
# Uncomment to expose additional ports for testing user applications that send emails.
|
||||
# smtp_port = 54325
|
||||
# pop3_port = 54326
|
||||
|
||||
[storage]
|
||||
enabled = true
|
||||
# The maximum file size allowed (e.g. "5MB", "500KB").
|
||||
file_size_limit = "50MiB"
|
||||
|
||||
[storage.image_transformation]
|
||||
enabled = true
|
||||
|
||||
[auth]
|
||||
enabled = true
|
||||
# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used
|
||||
# in emails.
|
||||
site_url = "http://127.0.0.1:3000"
|
||||
# A list of *exact* URLs that auth providers are permitted to redirect to post authentication.
|
||||
additional_redirect_urls = ["https://127.0.0.1:3000"]
|
||||
# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week).
|
||||
jwt_expiry = 3600
|
||||
# If disabled, the refresh token will never expire.
|
||||
enable_refresh_token_rotation = true
|
||||
# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds.
|
||||
# Requires enable_refresh_token_rotation = true.
|
||||
refresh_token_reuse_interval = 10
|
||||
# Allow/disallow new user signups to your project.
|
||||
enable_signup = true
|
||||
# Allow/disallow anonymous sign-ins to your project.
|
||||
enable_anonymous_sign_ins = false
|
||||
# Allow/disallow testing manual linking of accounts
|
||||
enable_manual_linking = false
|
||||
|
||||
[auth.email]
|
||||
# Allow/disallow new user signups via email to your project.
|
||||
enable_signup = true
|
||||
# If enabled, a user will be required to confirm any email change on both the old, and new email
|
||||
# addresses. If disabled, only the new email is required to confirm.
|
||||
double_confirm_changes = true
|
||||
# If enabled, users need to confirm their email address before signing in.
|
||||
enable_confirmations = false
|
||||
# Controls the minimum amount of time that must pass before sending another signup confirmation or password reset email.
|
||||
max_frequency = "1s"
|
||||
|
||||
# Uncomment to customize email template
|
||||
# [auth.email.template.invite]
|
||||
# subject = "You have been invited"
|
||||
# content_path = "./supabase/templates/invite.html"
|
||||
|
||||
[auth.sms]
|
||||
# Allow/disallow new user signups via SMS to your project.
|
||||
enable_signup = true
|
||||
# If enabled, users need to confirm their phone number before signing in.
|
||||
enable_confirmations = false
|
||||
# Template for sending OTP to users
|
||||
template = "Your code is {{ .Code }} ."
|
||||
# Controls the minimum amount of time that must pass before sending another sms otp.
|
||||
max_frequency = "5s"
|
||||
|
||||
# Use pre-defined map of phone number to OTP for testing.
|
||||
# [auth.sms.test_otp]
|
||||
# 4152127777 = "123456"
|
||||
|
||||
# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used.
|
||||
# [auth.hook.custom_access_token]
|
||||
# enabled = true
|
||||
# uri = "pg-functions://<database>/<schema>/<hook_name>"
|
||||
|
||||
# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`.
|
||||
[auth.sms.twilio]
|
||||
enabled = false
|
||||
account_sid = ""
|
||||
message_service_sid = ""
|
||||
# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead:
|
||||
auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)"
|
||||
|
||||
# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`,
|
||||
# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`,
|
||||
# `twitter`, `slack`, `spotify`, `workos`, `zoom`.
|
||||
[auth.external.apple]
|
||||
enabled = false
|
||||
client_id = ""
|
||||
# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead:
|
||||
secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)"
|
||||
# Overrides the default auth redirectUrl.
|
||||
redirect_uri = ""
|
||||
# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure,
|
||||
# or any other third-party OIDC providers.
|
||||
url = ""
|
||||
# If enabled, the nonce check will be skipped. Required for local sign in with Google auth.
|
||||
skip_nonce_check = false
|
||||
|
||||
[analytics]
|
||||
enabled = false
|
||||
port = 54327
|
||||
vector_port = 54328
|
||||
# Configure one of the supported backends: `postgres`, `bigquery`.
|
||||
backend = "postgres"
|
||||
|
||||
# Experimental features may be deprecated any time
|
||||
[experimental]
|
||||
# Configures Postgres storage engine to use OrioleDB (S3)
|
||||
orioledb_version = ""
|
||||
# Configures S3 bucket URL, eg. <bucket_name>.s3-<region>.amazonaws.com
|
||||
s3_host = "env(S3_HOST)"
|
||||
# Configures S3 bucket region, eg. us-east-1
|
||||
s3_region = "env(S3_REGION)"
|
||||
# Configures AWS_ACCESS_KEY_ID for S3 bucket
|
||||
s3_access_key = "env(S3_ACCESS_KEY)"
|
||||
# Configures AWS_SECRET_ACCESS_KEY for S3 bucket
|
||||
s3_secret_key = "env(S3_SECRET_KEY)"
|
237
supabase/migrations/20240608231854_init.sql
Normal file
237
supabase/migrations/20240608231854_init.sql
Normal file
@ -0,0 +1,237 @@
|
||||
|
||||
SET statement_timeout = 0;
|
||||
SET lock_timeout = 0;
|
||||
SET idle_in_transaction_session_timeout = 0;
|
||||
SET client_encoding = 'UTF8';
|
||||
SET standard_conforming_strings = on;
|
||||
SELECT pg_catalog.set_config('search_path', '', false);
|
||||
SET check_function_bodies = false;
|
||||
SET xmloption = content;
|
||||
SET client_min_messages = warning;
|
||||
SET row_security = off;
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "pg_net" WITH SCHEMA "extensions";
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "pgsodium" WITH SCHEMA "pgsodium";
|
||||
|
||||
COMMENT ON SCHEMA "public" IS 'standard public schema';
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "pg_graphql" WITH SCHEMA "graphql";
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "pg_stat_statements" WITH SCHEMA "extensions";
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "pgcrypto" WITH SCHEMA "extensions";
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "pgjwt" WITH SCHEMA "extensions";
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "supabase_vault" WITH SCHEMA "vault";
|
||||
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA "extensions";
|
||||
|
||||
CREATE TYPE "public"."interface_config_option" AS ENUM (
|
||||
'color',
|
||||
'image'
|
||||
);
|
||||
|
||||
ALTER TYPE "public"."interface_config_option" OWNER TO "postgres";
|
||||
|
||||
CREATE TYPE "public"."tier" AS ENUM (
|
||||
'Free',
|
||||
'Tier 1',
|
||||
'Tier 2',
|
||||
'Tier 3'
|
||||
);
|
||||
|
||||
ALTER TYPE "public"."tier" OWNER TO "postgres";
|
||||
|
||||
SET default_tablespace = '';
|
||||
|
||||
SET default_table_access_method = "heap";
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."admins" (
|
||||
"user_id" "uuid" NOT NULL,
|
||||
"created_at" timestamp with time zone DEFAULT "now"() NOT NULL,
|
||||
"assigner" "uuid"
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."admins" OWNER TO "postgres";
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."galleries" (
|
||||
"name" "text" NOT NULL,
|
||||
"column_number" bigint,
|
||||
"tier" "text" DEFAULT 'Free'::"text",
|
||||
"nsfw" boolean,
|
||||
"tags" "text"[],
|
||||
"thumbnail_file" "text" DEFAULT ''::"text"
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."galleries" OWNER TO "postgres";
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."interface_configurations" (
|
||||
"name" "text" NOT NULL,
|
||||
"value" "text" NOT NULL,
|
||||
"type" "public"."interface_config_option" DEFAULT 'color'::"public"."interface_config_option" NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."interface_configurations" OWNER TO "postgres";
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."tags" (
|
||||
"name" "text" NOT NULL,
|
||||
"gallery_name" "text"
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."tags" OWNER TO "postgres";
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."tiers" (
|
||||
"name" "text" NOT NULL,
|
||||
"price" double precision NOT NULL,
|
||||
"color" "text" NOT NULL,
|
||||
"description" "text" NOT NULL
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."tiers" OWNER TO "postgres";
|
||||
|
||||
CREATE TABLE IF NOT EXISTS "public"."user_subscriptions" (
|
||||
"user_id" "uuid" NOT NULL,
|
||||
"tier" "public"."tier"
|
||||
);
|
||||
|
||||
ALTER TABLE "public"."user_subscriptions" OWNER TO "postgres";
|
||||
|
||||
ALTER TABLE ONLY "public"."admins"
|
||||
ADD CONSTRAINT "admins_pkey" PRIMARY KEY ("user_id");
|
||||
|
||||
ALTER TABLE ONLY "public"."galleries"
|
||||
ADD CONSTRAINT "galleries_pkey" PRIMARY KEY ("name");
|
||||
|
||||
ALTER TABLE ONLY "public"."interface_configurations"
|
||||
ADD CONSTRAINT "interface_configurations_pkey" PRIMARY KEY ("name");
|
||||
|
||||
ALTER TABLE ONLY "public"."tags"
|
||||
ADD CONSTRAINT "tags_pkey" PRIMARY KEY ("name");
|
||||
|
||||
ALTER TABLE ONLY "public"."tiers"
|
||||
ADD CONSTRAINT "tiers_pkey" PRIMARY KEY ("name");
|
||||
|
||||
ALTER TABLE ONLY "public"."user_subscriptions"
|
||||
ADD CONSTRAINT "user_subscriptions_pkey" PRIMARY KEY ("user_id");
|
||||
|
||||
ALTER TABLE ONLY "public"."admins"
|
||||
ADD CONSTRAINT "admins_assigner_fkey" FOREIGN KEY ("assigner") REFERENCES "auth"."users"("id");
|
||||
|
||||
ALTER TABLE ONLY "public"."admins"
|
||||
ADD CONSTRAINT "admins_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id");
|
||||
|
||||
ALTER TABLE ONLY "public"."tags"
|
||||
ADD CONSTRAINT "tags_gallery_name_fkey" FOREIGN KEY ("gallery_name") REFERENCES "public"."galleries"("name");
|
||||
|
||||
ALTER TABLE ONLY "public"."user_subscriptions"
|
||||
ADD CONSTRAINT "user_subscriptions_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id");
|
||||
|
||||
CREATE POLICY "Enable delete for admins" ON "public"."tags" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1
|
||||
FROM "public"."admins"
|
||||
WHERE ("admins"."user_id" = "auth"."uid"()))));
|
||||
|
||||
CREATE POLICY "Enable delete for users based on admins" ON "public"."galleries" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1
|
||||
FROM "public"."admins"
|
||||
WHERE ("admins"."user_id" = "auth"."uid"()))));
|
||||
|
||||
CREATE POLICY "Enable insert for admins" ON "public"."tags" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1
|
||||
FROM "public"."admins"
|
||||
WHERE ("admins"."user_id" = "auth"."uid"()))));
|
||||
|
||||
CREATE POLICY "Enable insert for users based admins" ON "public"."galleries" FOR INSERT WITH CHECK ((EXISTS ( SELECT 1
|
||||
FROM "public"."admins"
|
||||
WHERE ("admins"."user_id" = "auth"."uid"()))));
|
||||
|
||||
CREATE POLICY "Enable read access for all users" ON "public"."admins" FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Enable read access for all users" ON "public"."galleries" FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Enable read access for all users" ON "public"."interface_configurations" FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Enable read access for all users" ON "public"."tags" FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Enable read access for all users" ON "public"."tiers" FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Enable read for users based on user_id" ON "public"."user_subscriptions" FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "admin insert" ON "public"."tiers" FOR INSERT WITH CHECK ((EXISTS ( SELECT 1
|
||||
FROM "public"."admins"
|
||||
WHERE ("admins"."user_id" = "auth"."uid"()))));
|
||||
|
||||
CREATE POLICY "admin update" ON "public"."tiers" FOR UPDATE USING ((EXISTS ( SELECT 1
|
||||
FROM "public"."admins"
|
||||
WHERE ("admins"."user_id" = "auth"."uid"()))));
|
||||
|
||||
ALTER TABLE "public"."admins" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE POLICY "delete for admin" ON "public"."tiers" FOR DELETE USING ((EXISTS ( SELECT 1
|
||||
FROM "public"."admins"
|
||||
WHERE ("admins"."user_id" = "auth"."uid"()))));
|
||||
|
||||
ALTER TABLE "public"."galleries" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
ALTER TABLE "public"."interface_configurations" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
ALTER TABLE "public"."tags" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
ALTER TABLE "public"."tiers" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE POLICY "update for admin" ON "public"."galleries" FOR UPDATE USING ((EXISTS ( SELECT 1
|
||||
FROM "public"."admins"
|
||||
WHERE ("admins"."user_id" = "auth"."uid"()))));
|
||||
|
||||
CREATE POLICY "update theme admin" ON "public"."interface_configurations" FOR UPDATE USING ((EXISTS ( SELECT 1
|
||||
FROM "public"."admins"
|
||||
WHERE ("admins"."user_id" = "auth"."uid"()))));
|
||||
|
||||
ALTER TABLE "public"."user_subscriptions" ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
ALTER PUBLICATION "supabase_realtime" OWNER TO "postgres";
|
||||
|
||||
GRANT USAGE ON SCHEMA "public" TO "postgres";
|
||||
GRANT USAGE ON SCHEMA "public" TO "anon";
|
||||
GRANT USAGE ON SCHEMA "public" TO "authenticated";
|
||||
GRANT USAGE ON SCHEMA "public" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."admins" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."admins" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."admins" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."galleries" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."galleries" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."galleries" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."interface_configurations" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."interface_configurations" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."interface_configurations" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."tags" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."tags" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."tags" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."tiers" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."tiers" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."tiers" TO "service_role";
|
||||
|
||||
GRANT ALL ON TABLE "public"."user_subscriptions" TO "anon";
|
||||
GRANT ALL ON TABLE "public"."user_subscriptions" TO "authenticated";
|
||||
GRANT ALL ON TABLE "public"."user_subscriptions" TO "service_role";
|
||||
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "postgres";
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "anon";
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "authenticated";
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "service_role";
|
||||
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "postgres";
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "anon";
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "authenticated";
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "service_role";
|
||||
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "postgres";
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "anon";
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "authenticated";
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "service_role";
|
||||
|
||||
RESET ALL;
|
379
supabase/seed.sql
Normal file
379
supabase/seed.sql
Normal file
@ -0,0 +1,379 @@
|
||||
SET session_replication_role = replica;
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump
|
||||
--
|
||||
|
||||
-- Dumped from database version 15.1 (Ubuntu 15.1-1.pgdg20.04+1)
|
||||
-- Dumped by pg_dump version 15.6 (Ubuntu 15.6-1.pgdg20.04+1)
|
||||
|
||||
SET statement_timeout = 0;
|
||||
SET lock_timeout = 0;
|
||||
SET idle_in_transaction_session_timeout = 0;
|
||||
SET client_encoding = 'UTF8';
|
||||
SET standard_conforming_strings = on;
|
||||
SELECT pg_catalog.set_config('search_path', '', false);
|
||||
SET check_function_bodies = false;
|
||||
SET xmloption = content;
|
||||
SET client_min_messages = warning;
|
||||
SET row_security = off;
|
||||
|
||||
--
|
||||
-- Data for Name: audit_log_entries; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
INSERT INTO "auth"."audit_log_entries" ("instance_id", "id", "payload", "created_at", "ip_address") VALUES
|
||||
('00000000-0000-0000-0000-000000000000', 'd337a17f-a756-46eb-a0e8-8ef80fd0510d', '{"action":"user_signedup","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"team","traits":{"provider":"email"}}', '2024-05-27 14:10:29.638476+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'd3e71df0-114a-4490-aeeb-6f92c45bad74', '{"action":"login","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-05-27 14:10:29.64088+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '1eab1cf3-5656-42c2-9e0b-796222de0c55', '{"action":"logout","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account"}', '2024-05-27 14:15:04.733941+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '410c5c63-cba5-442a-a6bb-157acc0bd370', '{"action":"login","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-05-27 14:34:43.53365+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '262365e2-093b-493c-abff-d760344338e3', '{"action":"logout","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account"}', '2024-05-27 15:32:39.855999+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'b3b7c848-8d46-468f-8a9f-be56f842e8f8', '{"action":"login","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-05-27 15:32:48.609554+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '96af268f-e323-43ec-ac10-d33b94c47321', '{"action":"user_invited","actor_id":"00000000-0000-0000-0000-000000000000","actor_username":"service_role","actor_via_sso":false,"log_type":"team","traits":{"user_email":"damienostler1@gmail.com","user_id":"e11e6fda-d1fc-4b0a-bd61-80233fcb5cdd"}}', '2024-05-27 15:44:27.171353+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '98b879f8-3ec0-4b14-9114-e9702693edd7', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-05-27 16:33:16.635885+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '05788b7b-5d97-4449-b036-0d94c021f149', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-05-27 16:33:16.636596+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'ec47cc2d-ee91-4bda-93cc-80966a366550', '{"action":"logout","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account"}', '2024-05-27 17:16:40.455383+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'dee2b80d-2cb6-49b0-9391-d52318eba3c6', '{"action":"login","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-05-27 17:18:49.038768+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '50134af5-eeca-4e0a-93c9-30c93395843d', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-05-27 18:17:16.199899+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'e1b7a78c-c40e-4348-bd41-eadc94a93ebb', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-05-27 18:17:16.200645+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '0fffa887-134b-4d3b-bf70-24246ec38013', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-05-27 19:15:16.230466+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '83236dbe-037b-4a7a-a326-7ff3c9759bd7', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-05-27 19:15:16.231644+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '6f4bb32b-4690-4640-98ac-feb06384ef62', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-05-27 20:13:20.140291+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'e6e8d515-e14c-48ff-8c4d-27cea84d33f3', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-05-27 20:13:20.140793+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'e878d51d-2524-4796-9288-88bcf8d1982b', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-05-27 21:11:27.314657+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '0d3f4871-8215-4ae7-920b-c261ba7eaf11', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-05-27 21:11:27.315598+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'f70081c9-673b-4e8e-84c6-574d4a6fc095', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-05-28 00:06:54.425581+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'ff4e9892-902a-4e6f-9493-976acd87e5ad', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-05-28 00:06:54.426626+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '13891f74-fb79-45bd-a202-3c3846723eb3', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-05-28 01:11:09.34946+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '6125acd2-6bd2-4ae1-8b41-4b54b8097a64', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-05-28 01:11:09.350568+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '904b1ae0-83cb-4bce-a1b9-65f4215e0095', '{"action":"logout","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account"}', '2024-05-28 01:45:53.937368+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '16bba433-9af2-4328-b0d2-d59a9d072edb', '{"action":"user_signedup","actor_id":"e11e6fda-d1fc-4b0a-bd61-80233fcb5cdd","actor_username":"damienostler1@gmail.com","actor_via_sso":false,"log_type":"team","traits":{"provider":"email"}}', '2024-05-28 02:01:35.369669+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'a80de210-524f-41a2-b437-a0a68a5b0dc5', '{"action":"login","actor_id":"e11e6fda-d1fc-4b0a-bd61-80233fcb5cdd","actor_username":"damienostler1@gmail.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-05-28 02:01:35.372417+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '56e9bcfc-28ea-4fbf-aae2-a6c611da2536', '{"action":"token_refreshed","actor_id":"e11e6fda-d1fc-4b0a-bd61-80233fcb5cdd","actor_username":"damienostler1@gmail.com","actor_via_sso":false,"log_type":"token"}', '2024-05-28 03:03:11.47339+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'f661df3e-4600-4254-a606-dab87b0bf241', '{"action":"token_revoked","actor_id":"e11e6fda-d1fc-4b0a-bd61-80233fcb5cdd","actor_username":"damienostler1@gmail.com","actor_via_sso":false,"log_type":"token"}', '2024-05-28 03:03:11.474173+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'eccb045f-3fa3-4cc4-92b5-2181ae4c684e', '{"action":"token_refreshed","actor_id":"e11e6fda-d1fc-4b0a-bd61-80233fcb5cdd","actor_username":"damienostler1@gmail.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 01:54:12.341648+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'bdca3f89-401a-40b5-b1bd-7b053f72f15a', '{"action":"token_revoked","actor_id":"e11e6fda-d1fc-4b0a-bd61-80233fcb5cdd","actor_username":"damienostler1@gmail.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 01:54:12.342909+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'a76ea115-0732-45e4-a05f-cbf9aec04dab', '{"action":"logout","actor_id":"e11e6fda-d1fc-4b0a-bd61-80233fcb5cdd","actor_username":"damienostler1@gmail.com","actor_via_sso":false,"log_type":"account"}', '2024-06-01 01:54:44.965028+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '73e58d43-80dc-4c40-93b8-66debb2d79f2', '{"action":"login","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-06-01 01:54:50.928035+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'a7b0b5b0-42d0-4970-a799-f918e320a460', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 02:52:51.499031+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'dd70c686-fc1b-42da-8aa1-91a6d7fbcc14', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 02:52:51.50256+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '09161c6c-3f38-4405-b26e-67fe90bc0005', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 03:51:46.507091+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '7fd17052-1b4a-4178-98b8-3b16b9de930a', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 03:51:46.5081+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '727021f7-1385-43eb-9139-5c8d0984fb07', '{"action":"logout","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account"}', '2024-06-01 04:28:20.313782+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '7df2cdbc-1c84-4847-8142-90477524ee7a', '{"action":"login","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-06-01 04:32:18.045015+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'abb0a2d8-d525-4612-a364-9ba3ea22eabf', '{"action":"logout","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account"}', '2024-06-01 04:32:21.789565+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '21e30d5b-7f03-459f-814d-43757cf3f8bf', '{"action":"login","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-06-01 04:33:07.034577+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '1d8fca22-6ef6-42eb-a1e9-659e702e0568', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 05:31:30.614051+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '3a9c811c-fad9-4739-9e2f-807a65f92ebc', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 05:31:30.614956+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '7620c8d4-9662-4c6b-b04f-8bcf5fc37cd2', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 07:21:44.28552+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '4cfcd7b6-8a95-4713-9409-317734ae7b38', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 07:21:44.286437+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '41cd74f2-8882-4e30-ae82-b743901cae3a', '{"action":"logout","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account"}', '2024-06-01 07:37:28.737433+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'a490a17d-b47e-4820-923d-e7c8bc88efb5', '{"action":"login","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-06-01 07:37:35.302764+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '3c44829d-3ec7-4698-95c3-b53597422759', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 08:36:15.774+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '5b2c215f-bfd1-4b59-a782-eaac62d1c458', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 08:36:15.775505+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '0a5a278a-9fd1-4bcc-a041-66f1302ac7e6', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 09:34:29.572756+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '89b87acd-362b-4c51-8c3a-5a5e356ed8e2', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 09:34:29.573904+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '8c413fec-a827-4ede-a533-2409f855d2e0', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 10:35:29.39825+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '786f5ba3-670c-4799-8b5d-9e2536b75ca0', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 10:35:29.399482+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'da188f51-e5c3-467c-b9c4-7e2ba8430981', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 20:10:45.655684+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'c415ee23-3497-4445-9b18-b3698dd35e16', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 20:10:45.656475+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '4c5c4c36-a506-4c80-b467-68618dbf10db', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 22:05:34.985137+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '52eb3774-6624-4987-b357-fb07ff22e368', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-01 22:05:34.986175+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '4c493923-b97a-4ca7-ad59-801212c59692', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 03:42:48.403833+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '04114bf3-53c5-447b-bb9d-0cf0e97411ce', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 03:42:48.405516+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '59785eb8-3a22-4596-b534-c76d0aaadf9b', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 04:41:14.398806+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '1da856fa-1582-447b-a033-6dfd6e91ee5b', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 04:41:14.399986+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '3790f005-05d8-439d-a828-fb8e6a22356f', '{"action":"logout","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account"}', '2024-06-02 05:20:51.896435+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '903ece4b-635c-4fd0-9a6d-c60103328e11', '{"action":"login","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-06-02 05:21:03.760977+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'ab8d42bd-c9df-4782-8cbd-14279592fe94', '{"action":"logout","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account"}', '2024-06-02 06:18:43.051255+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '008ae3d1-61c4-4456-8e70-8a2030acbbc4', '{"action":"login","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-06-02 07:19:23.344522+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'bf042910-d447-4f27-bb63-fbd6b80c266f', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 08:17:36.070061+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '55f64c6a-d6bd-4dd4-8627-3c35caa6dc7e', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 08:17:36.071183+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '578dc04e-5665-410c-8c0e-bbf40b397b18', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 09:23:17.276185+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '4ccf2be5-8ecd-48ee-9400-7fef1004dc56', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 09:23:17.277357+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '824ccdf1-4dc0-4cee-8c01-ac66cdea101f', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 10:21:37.85499+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '98aa3855-f2ff-4118-9618-041c82318963', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 10:21:37.856028+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'f1599f7e-e1c1-4861-87e5-9b8e5e9fa8f7', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 11:20:00.113655+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '84f7562d-151d-4e30-b810-70891f3a8a2b', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 11:20:00.115274+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '7451f114-d011-4552-9b21-bcf6d6df6243', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 20:49:23.877784+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '24b82857-e2fd-4732-a2e8-ac99f67fffa9', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 20:49:23.878598+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'bf2935a0-244a-449d-925c-ca7ad6bf91d6', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 21:49:06.535623+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '88b130fb-5418-49ec-9e54-7db1df9b9353', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 21:49:06.536554+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '2aafc337-642d-4f4c-b550-b1c88b0f698a', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 22:47:33.949246+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '7b7bc3c1-3751-4e00-a08c-14b5bb3cf892', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-02 22:47:33.950537+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '7b3b5a37-ed60-4b75-84ae-0caba9254581', '{"action":"login","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-06-03 00:10:51.713229+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'd984ff2d-6d96-43d9-9a39-703de7400fd1', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 01:10:47.663131+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'e996a172-f818-489a-84b3-8dc8b8a1068b', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 01:10:47.663668+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '0f07359e-4c78-40a7-8711-4127dc74c0fb', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 02:08:53.524332+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'b8f1d6e8-4e3f-473c-b0be-98f4540da6f3', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 02:08:53.525533+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '1043d8ee-0301-46e0-a451-2bb043fe6634', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 03:07:09.462821+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '6924eb3a-0588-46ff-94dc-b45f29a06e74', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 03:07:09.463674+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '3995cc04-3976-47bd-aafb-04fcf8a533db', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 04:05:10.557103+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'd5cb3c9b-aa2d-4ca6-9067-4c31ecbb7827', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 04:05:10.558474+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '8c7ca4b6-0b87-4704-9508-8cdfaac13c65', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 05:04:07.678559+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '7a1eb770-9f3c-4ac2-a13a-fafe80704bef', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 05:04:07.679535+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'c4c2ae8b-62eb-4dde-8023-bb4a52fd8402', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 06:02:18.158106+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'f3deb712-a27b-4652-b3dc-bb782188943c', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-03 06:02:18.159666+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'db502a30-3a84-4151-8c02-7be7eba0f8d1', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-04 00:29:24.732764+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'a24f4f60-00aa-48eb-8318-ed131fd44b2e', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-04 00:29:24.734165+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'f1d4e360-3355-4850-9f9e-64961bb1cadf', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-04 01:27:58.415574+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '45e4135f-e65c-4011-bd07-c6a5bcb33860', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-04 01:27:58.416715+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '95c4b03d-1f15-4ad9-83c1-79f079407908', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-04 02:26:28.440011+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '9b5db737-976a-459f-8f12-eed61184218d', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-04 02:26:28.441438+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '2bbe5699-d14f-4c3f-9c87-52b7f01ed087', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-05 00:52:31.052995+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'b54ff1b9-6254-43d2-a210-b5d9d2701974', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-05 00:52:31.055077+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'b0611a51-8bb8-4fab-937e-68a413e02b5e', '{"action":"logout","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account"}', '2024-06-05 01:03:30.844197+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '57f72aa6-2609-4efe-bf06-950681c975f9', '{"action":"login","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-06-05 01:03:39.551264+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '3e6b6d3e-c8bd-4cd6-a7ac-b55c59269df1', '{"action":"login","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"account","traits":{"provider":"email"}}', '2024-06-05 01:06:08.194567+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '59805a05-bfba-4dbe-8021-8db6d6b71a4e', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-05 02:02:22.65237+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'eaf050ba-9bdc-4771-8dcb-1534c38d68b9', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-05 02:02:22.653268+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'a326a1f9-92f7-472c-bbb7-f10c6f3c1dff', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-05 03:00:26.781265+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '473362fc-dc06-43d5-99df-065c9e671347', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-05 03:00:26.782565+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '3a82cdde-76bf-4cc4-a5e2-b818601100a1', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-07 23:35:28.284863+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'c3ecf585-5984-4b7e-8115-f57523a31e23', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-07 23:35:28.285858+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'cc3425df-b1e8-4e7b-8729-80e66eae2b27', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-08 00:33:56.442635+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'd991bd91-d600-457c-a887-67a3be188c83', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-08 00:33:56.44418+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'a8bd8737-8115-4643-b9a7-f288be170b28', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-08 02:07:59.069381+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '495056f7-149e-43b3-bc58-1712e3787215', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-08 02:07:59.070256+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '27ca0341-280d-474a-a3da-39fa4c69748e', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-08 03:06:06.149018+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'aa06c3b0-cd66-440a-a184-d44795552f11', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-08 03:06:06.15067+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '398046e7-2dc1-49e0-92ad-4823c0001271', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-08 04:04:06.664163+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', 'eb481c2d-2f96-4efa-84cb-e715ee547913', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-08 04:04:06.665465+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '088f4537-0025-44e9-a499-dc85d7034ed3', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-08 22:08:31.582227+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '7f476998-602e-4d2e-9129-92ea021b1d50', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-08 22:08:31.583859+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '1c9bf13b-7ecf-4432-a83e-8dcd95eeb6c9', '{"action":"token_refreshed","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-08 23:06:38.987497+00', ''),
|
||||
('00000000-0000-0000-0000-000000000000', '07c85a08-4a4b-4238-ac4c-047350db4b7f', '{"action":"token_revoked","actor_id":"893c7701-d5df-4415-80bd-1ec089764400","actor_username":"damienostler1@outlook.com","actor_via_sso":false,"log_type":"token"}', '2024-06-08 23:06:38.988275+00', '');
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: flow_state; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: users; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
INSERT INTO "auth"."users" ("instance_id", "id", "aud", "role", "email", "encrypted_password", "email_confirmed_at", "invited_at", "confirmation_token", "confirmation_sent_at", "recovery_token", "recovery_sent_at", "email_change_token_new", "email_change", "email_change_sent_at", "last_sign_in_at", "raw_app_meta_data", "raw_user_meta_data", "is_super_admin", "created_at", "updated_at", "phone", "phone_confirmed_at", "phone_change", "phone_change_token", "phone_change_sent_at", "email_change_token_current", "email_change_confirm_status", "banned_until", "reauthentication_token", "reauthentication_sent_at", "is_sso_user", "deleted_at", "is_anonymous") VALUES
|
||||
('00000000-0000-0000-0000-000000000000', 'e11e6fda-d1fc-4b0a-bd61-80233fcb5cdd', 'authenticated', 'authenticated', 'damienostler1@gmail.com', '', '2024-05-28 02:01:35.370491+00', '2024-05-27 15:44:27.171961+00', '', '2024-05-27 15:44:27.171961+00', '', NULL, '', '', NULL, '2024-05-28 02:01:35.372861+00', '{"provider": "email", "providers": ["email"]}', '{}', NULL, '2024-05-27 15:44:27.167772+00', '2024-06-01 01:54:12.344577+00', NULL, NULL, '', '', NULL, '', 0, NULL, '', NULL, false, NULL, false),
|
||||
('00000000-0000-0000-0000-000000000000', '893c7701-d5df-4415-80bd-1ec089764400', 'authenticated', 'authenticated', 'damienostler1@outlook.com', '$2a$10$ISYdoWsKL7gxfRz7c5IKDOTsmcjNpGgg9OOApYLMOvtOoNTo4HGM6', '2024-05-27 14:10:29.639017+00', NULL, '', NULL, '', NULL, '', '', NULL, '2024-06-05 01:06:08.194961+00', '{"provider": "email", "providers": ["email"]}', '{"sub": "893c7701-d5df-4415-80bd-1ec089764400", "email": "damienostler1@outlook.com", "email_verified": false, "phone_verified": false}', NULL, '2024-05-27 14:10:29.634157+00', '2024-06-08 23:06:38.990134+00', NULL, NULL, '', '', NULL, '', 0, NULL, '', NULL, false, NULL, false);
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: identities; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
INSERT INTO "auth"."identities" ("provider_id", "user_id", "identity_data", "provider", "last_sign_in_at", "created_at", "updated_at", "id") VALUES
|
||||
('893c7701-d5df-4415-80bd-1ec089764400', '893c7701-d5df-4415-80bd-1ec089764400', '{"sub": "893c7701-d5df-4415-80bd-1ec089764400", "email": "damienostler1@outlook.com", "email_verified": false, "phone_verified": false}', 'email', '2024-05-27 14:10:29.636992+00', '2024-05-27 14:10:29.637013+00', '2024-05-27 14:10:29.637013+00', 'b823bde7-9eae-4e1f-8253-75f12f0f06f2'),
|
||||
('e11e6fda-d1fc-4b0a-bd61-80233fcb5cdd', 'e11e6fda-d1fc-4b0a-bd61-80233fcb5cdd', '{"sub": "e11e6fda-d1fc-4b0a-bd61-80233fcb5cdd", "email": "damienostler1@gmail.com", "email_verified": false, "phone_verified": false}', 'email', '2024-05-27 15:44:27.170495+00', '2024-05-27 15:44:27.170543+00', '2024-05-27 15:44:27.170543+00', 'f88a9c9a-1566-4c04-8340-3d233dcca864');
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: instances; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: sessions; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
INSERT INTO "auth"."sessions" ("id", "user_id", "created_at", "updated_at", "factor_id", "aal", "not_after", "refreshed_at", "user_agent", "ip", "tag") VALUES
|
||||
('88176780-1709-4810-92de-36f909e3fafb', '893c7701-d5df-4415-80bd-1ec089764400', '2024-06-05 01:06:08.19499+00', '2024-06-05 01:06:08.19499+00', NULL, 'aal1', NULL, NULL, 'node', '192.168.65.1', NULL),
|
||||
('8de4dae9-a9f9-44ad-bf2a-c42356feb0e2', '893c7701-d5df-4415-80bd-1ec089764400', '2024-06-05 01:03:39.551694+00', '2024-06-08 23:06:38.991049+00', NULL, 'aal1', NULL, '2024-06-08 23:06:38.990997', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36', '192.168.65.1', NULL);
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: mfa_amr_claims; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
INSERT INTO "auth"."mfa_amr_claims" ("session_id", "created_at", "updated_at", "authentication_method", "id") VALUES
|
||||
('8de4dae9-a9f9-44ad-bf2a-c42356feb0e2', '2024-06-05 01:03:39.553156+00', '2024-06-05 01:03:39.553156+00', 'password', '70b28b1d-9c1c-42ed-b9b6-4629b4dc6610'),
|
||||
('88176780-1709-4810-92de-36f909e3fafb', '2024-06-05 01:06:08.195749+00', '2024-06-05 01:06:08.195749+00', 'password', '2d748036-15f9-49a1-ba18-a9636803f795');
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: mfa_factors; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: mfa_challenges; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: one_time_tokens; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: refresh_tokens; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
INSERT INTO "auth"."refresh_tokens" ("instance_id", "id", "token", "user_id", "revoked", "created_at", "updated_at", "parent", "session_id") VALUES
|
||||
('00000000-0000-0000-0000-000000000000', 83, 'c6bYIcVnSBosWtn4QX8F6w', '893c7701-d5df-4415-80bd-1ec089764400', false, '2024-06-05 01:06:08.195296+00', '2024-06-05 01:06:08.195296+00', NULL, '88176780-1709-4810-92de-36f909e3fafb'),
|
||||
('00000000-0000-0000-0000-000000000000', 82, 'vgibpWzclaC1SiIWnkWFTw', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-05 01:03:39.55241+00', '2024-06-05 02:02:22.653721+00', NULL, '8de4dae9-a9f9-44ad-bf2a-c42356feb0e2'),
|
||||
('00000000-0000-0000-0000-000000000000', 84, 'kcsINvcmhD18guzedNei0Q', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-05 02:02:22.654159+00', '2024-06-05 03:00:26.783216+00', 'vgibpWzclaC1SiIWnkWFTw', '8de4dae9-a9f9-44ad-bf2a-c42356feb0e2'),
|
||||
('00000000-0000-0000-0000-000000000000', 85, '4eJVeDMlvmAUk20ZqwdGQA', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-05 03:00:26.784329+00', '2024-06-07 23:35:28.286039+00', 'kcsINvcmhD18guzedNei0Q', '8de4dae9-a9f9-44ad-bf2a-c42356feb0e2'),
|
||||
('00000000-0000-0000-0000-000000000000', 86, 'Nb0zuvJjDL8keK1lF1xX9Q', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-07 23:35:28.28691+00', '2024-06-08 00:33:56.445064+00', '4eJVeDMlvmAUk20ZqwdGQA', '8de4dae9-a9f9-44ad-bf2a-c42356feb0e2'),
|
||||
('00000000-0000-0000-0000-000000000000', 119, 'y9oA8pEThLtPyEJW2IK3eA', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-08 00:33:56.446127+00', '2024-06-08 02:07:59.070607+00', 'Nb0zuvJjDL8keK1lF1xX9Q', '8de4dae9-a9f9-44ad-bf2a-c42356feb0e2'),
|
||||
('00000000-0000-0000-0000-000000000000', 120, 'TwWGx47OPQs1BNtkLs9JSA', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-08 02:07:59.07107+00', '2024-06-08 03:06:06.151386+00', 'y9oA8pEThLtPyEJW2IK3eA', '8de4dae9-a9f9-44ad-bf2a-c42356feb0e2'),
|
||||
('00000000-0000-0000-0000-000000000000', 121, 'mL_eZQCxVdYq7SR-UjEJgQ', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-08 03:06:06.154686+00', '2024-06-08 04:04:06.666124+00', 'TwWGx47OPQs1BNtkLs9JSA', '8de4dae9-a9f9-44ad-bf2a-c42356feb0e2'),
|
||||
('00000000-0000-0000-0000-000000000000', 122, 'cFLCDOB1QfKd_ydDNLRmoQ', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-08 04:04:06.667264+00', '2024-06-08 22:08:31.584256+00', 'mL_eZQCxVdYq7SR-UjEJgQ', '8de4dae9-a9f9-44ad-bf2a-c42356feb0e2'),
|
||||
('00000000-0000-0000-0000-000000000000', 123, 'G5KZsQQhC6kFqd0Xht2ypg', '893c7701-d5df-4415-80bd-1ec089764400', true, '2024-06-08 22:08:31.584969+00', '2024-06-08 23:06:38.988706+00', 'cFLCDOB1QfKd_ydDNLRmoQ', '8de4dae9-a9f9-44ad-bf2a-c42356feb0e2'),
|
||||
('00000000-0000-0000-0000-000000000000', 124, '4p4Q-c4t1ZH2PUvl_mcYtQ', '893c7701-d5df-4415-80bd-1ec089764400', false, '2024-06-08 23:06:38.989251+00', '2024-06-08 23:06:38.989251+00', 'G5KZsQQhC6kFqd0Xht2ypg', '8de4dae9-a9f9-44ad-bf2a-c42356feb0e2');
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: sso_providers; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: saml_providers; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: saml_relay_states; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: sso_domains; Type: TABLE DATA; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: key; Type: TABLE DATA; Schema: pgsodium; Owner: supabase_admin
|
||||
--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: admins; Type: TABLE DATA; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
INSERT INTO "public"."admins" ("user_id", "created_at", "assigner") VALUES
|
||||
('893c7701-d5df-4415-80bd-1ec089764400', '2024-06-02 21:12:58.507093+00', NULL);
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: galleries; Type: TABLE DATA; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
INSERT INTO "public"."galleries" ("name", "column_number", "tier", "nsfw", "tags", "thumbnail_file") VALUES
|
||||
('Test', 3, 'Free', false, '{twatwat}', ''),
|
||||
('Testsdadas', 3, 'Free', false, '{}', '');
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: interface_configurations; Type: TABLE DATA; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
INSERT INTO "public"."interface_configurations" ("name", "value", "type") VALUES
|
||||
('primary-dark', '#100120', 'color'),
|
||||
('secondary-light', '#6F5D90', 'color'),
|
||||
('secondary-dark', '#2F1D50', 'color'),
|
||||
('primary', '#18161d', 'color'),
|
||||
('secondary', '#4F3D70', 'color'),
|
||||
('primary-light', '#403260', 'color'),
|
||||
('error-dark', '#5C0D0D', 'color'),
|
||||
('error', '#862117', 'color'),
|
||||
('success-dark', '#00A986', 'color'),
|
||||
('error-light', '#C44C4C', 'color'),
|
||||
('success-light', '#20E9C6', 'color'),
|
||||
('success', '#00C9A6', 'color'),
|
||||
('warning', '#E17558', 'color'),
|
||||
('warning-light', '#E39578', 'color'),
|
||||
('info-light', '#424260', 'color'),
|
||||
('warning-dark', '#C15538', 'color'),
|
||||
('info-dark', '#020120', 'color'),
|
||||
('info', '#222140', 'color');
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: tags; Type: TABLE DATA; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
INSERT INTO "public"."tags" ("name", "gallery_name") VALUES
|
||||
('twatwat', NULL),
|
||||
('', NULL);
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: tiers; Type: TABLE DATA; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
INSERT INTO "public"."tiers" ("name", "price", "color", "description") VALUES
|
||||
('Free', 0, '#8f6eaa', 'This is a test tier.dasdasd');
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: user_subscriptions; Type: TABLE DATA; Schema: public; Owner: postgres
|
||||
--
|
||||
|
||||
INSERT INTO "public"."user_subscriptions" ("user_id", "tier") VALUES
|
||||
('893c7701-d5df-4415-80bd-1ec089764400', 'Tier 2');
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: objects; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin
|
||||
--
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: s3_multipart_uploads; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin
|
||||
--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: s3_multipart_uploads_parts; Type: TABLE DATA; Schema: storage; Owner: supabase_storage_admin
|
||||
--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: hooks; Type: TABLE DATA; Schema: supabase_functions; Owner: supabase_functions_admin
|
||||
--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Data for Name: secrets; Type: TABLE DATA; Schema: vault; Owner: supabase_admin
|
||||
--
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Name: refresh_tokens_id_seq; Type: SEQUENCE SET; Schema: auth; Owner: supabase_auth_admin
|
||||
--
|
||||
|
||||
SELECT pg_catalog.setval('"auth"."refresh_tokens_id_seq"', 124, true);
|
||||
|
||||
|
||||
--
|
||||
-- Name: key_key_id_seq; Type: SEQUENCE SET; Schema: pgsodium; Owner: supabase_admin
|
||||
--
|
||||
|
||||
SELECT pg_catalog.setval('"pgsodium"."key_key_id_seq"', 1, false);
|
||||
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
|
||||
RESET ALL;
|
48
tailwind.config.js
Normal file
48
tailwind.config.js
Normal file
@ -0,0 +1,48 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
content: [
|
||||
"./app/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./components/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"./src/**/*.{js,jsx,ts,tsx}",
|
||||
"./node_modules/react-tailwindcss-select/dist/index.esm.js"
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
textStrokeColor: {
|
||||
'black': '#000',
|
||||
},
|
||||
textStrokeWidth: {
|
||||
'1': '1px',
|
||||
},
|
||||
aspectRatio: {}, // enable aspect-ratio plugin
|
||||
textShadow: {
|
||||
// 'pink-glow': '0 0 4px #524FFD, 0 0 4px #524FFD, 0 0 4px #524FFD, 0 0 4px #524FFD',
|
||||
},
|
||||
colors: {
|
||||
'primary': 'var(--color-primary)',
|
||||
'primary-light': 'var(--color-primary-light)',
|
||||
'primary-dark': 'var(--color-primary-dark)',
|
||||
'secondary': 'var(--color-secondary)',
|
||||
'secondary-light': 'var(--color-secondary-light)',
|
||||
'secondary-dark': 'var(--color-secondary-dark)',
|
||||
'error': 'var(--color-error)',
|
||||
'error-light': 'var(--color-error-light)',
|
||||
'error-dark': 'var(--color-error-dark)',
|
||||
'success': 'var(--color-success)',
|
||||
'success-light': 'var(--color-success-light)',
|
||||
'success-dark': 'var(--color-success-dark)',
|
||||
'warning': 'var(--color-warning)',
|
||||
'warning-light': 'var(--color-warning-light)',
|
||||
'warning-dark': 'var(--color-warning-dark)',
|
||||
'info': 'var(--color-info)',
|
||||
'info-light': 'var(--color-info-light)',
|
||||
'info-dark': 'var(--color-info-dark)',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
require('tailwindcss-animated'),
|
||||
require('tailwindcss-textshadow'),
|
||||
require('@tailwindcss/aspect-ratio')
|
||||
],
|
||||
};
|
@ -1,14 +0,0 @@
|
||||
import { config } from '@tamagui/config/v3'
|
||||
|
||||
import { createTamagui } from 'tamagui'
|
||||
const tamaguiConfig = createTamagui(config)
|
||||
// this makes typescript properly type everything based on the config
|
||||
|
||||
type Conf = typeof tamaguiConfig
|
||||
|
||||
declare module 'tamagui' {
|
||||
|
||||
interface TamaguiCustomConfig extends Conf {}
|
||||
|
||||
}
|
||||
export default tamaguiConfig
|
@ -1,28 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"target": "es5",
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"allowJs": true,
|
||||
"skipLibCheck": true,
|
||||
"strict": false,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noEmit": true,
|
||||
"incremental": true,
|
||||
"module": "esnext",
|
||||
"esModuleInterop": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"jsx": "preserve"
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
||||
"exclude": ["node_modules","supabase/volumes/functions/**/*"]
|
||||
}
|
||||
|
3
types/react-easy-panzoom.d.ts
vendored
Normal file
3
types/react-easy-panzoom.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
// types/react-easy-panzoom.d.ts
|
||||
|
||||
declare module 'react-easy-panzoom';
|
6
utils/cn.ts
Normal file
6
utils/cn.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { ClassValue, clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
7
utils/supabase/client.ts
Normal file
7
utils/supabase/client.ts
Normal file
@ -0,0 +1,7 @@
|
||||
import { createBrowserClient } from "@supabase/ssr";
|
||||
|
||||
export const createClient = () =>
|
||||
createBrowserClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
);
|
78
utils/supabase/middleware.ts
Normal file
78
utils/supabase/middleware.ts
Normal file
@ -0,0 +1,78 @@
|
||||
import { createServerClient, type CookieOptions } from "@supabase/ssr";
|
||||
import { type NextRequest, NextResponse } from "next/server";
|
||||
|
||||
export const updateSession = async (request: NextRequest) => {
|
||||
// This `try/catch` block is only here for the interactive tutorial.
|
||||
// Feel free to remove once you have Supabase connected.
|
||||
try {
|
||||
// Create an unmodified response
|
||||
let response = NextResponse.next({
|
||||
request: {
|
||||
headers: request.headers,
|
||||
},
|
||||
});
|
||||
|
||||
const supabase = createServerClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
{
|
||||
cookies: {
|
||||
get(name: string) {
|
||||
return request.cookies.get(name)?.value;
|
||||
},
|
||||
set(name: string, value: string, options: CookieOptions) {
|
||||
// If the cookie is updated, update the cookies for the request and response
|
||||
request.cookies.set({
|
||||
name,
|
||||
value,
|
||||
...options,
|
||||
});
|
||||
response = NextResponse.next({
|
||||
request: {
|
||||
headers: request.headers,
|
||||
},
|
||||
});
|
||||
response.cookies.set({
|
||||
name,
|
||||
value,
|
||||
...options,
|
||||
});
|
||||
},
|
||||
remove(name: string, options: CookieOptions) {
|
||||
// If the cookie is removed, update the cookies for the request and response
|
||||
request.cookies.set({
|
||||
name,
|
||||
value: "",
|
||||
...options,
|
||||
});
|
||||
response = NextResponse.next({
|
||||
request: {
|
||||
headers: request.headers,
|
||||
},
|
||||
});
|
||||
response.cookies.set({
|
||||
name,
|
||||
value: "",
|
||||
...options,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// This will refresh session if expired - required for Server Components
|
||||
// https://supabase.com/docs/guides/auth/server-side/nextjs
|
||||
await supabase.auth.getUser();
|
||||
|
||||
return response;
|
||||
} catch (e) {
|
||||
// If you are here, a Supabase client could not be created!
|
||||
// This is likely because you have not set up environment variables.
|
||||
// Check out http://localhost:3000 for Next Steps.
|
||||
return NextResponse.next({
|
||||
request: {
|
||||
headers: request.headers,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
36
utils/supabase/server.ts
Normal file
36
utils/supabase/server.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { createServerClient, type CookieOptions } from "@supabase/ssr";
|
||||
import { cookies } from "next/headers";
|
||||
|
||||
export const createClient = () => {
|
||||
const cookieStore = cookies();
|
||||
|
||||
return createServerClient(
|
||||
process.env.NEXT_PUBLIC_SUPABASE_URL!,
|
||||
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
|
||||
{
|
||||
cookies: {
|
||||
get(name: string) {
|
||||
return cookieStore.get(name)?.value;
|
||||
},
|
||||
set(name: string, value: string, options: CookieOptions) {
|
||||
try {
|
||||
cookieStore.set({ name, value, ...options });
|
||||
} catch (error) {
|
||||
// The `set` method was called from a Server Component.
|
||||
// This can be ignored if you have middleware refreshing
|
||||
// user sessions.
|
||||
}
|
||||
},
|
||||
remove(name: string, options: CookieOptions) {
|
||||
try {
|
||||
cookieStore.set({ name, value: "", ...options });
|
||||
} catch (error) {
|
||||
// The `delete` method was called from a Server Component.
|
||||
// This can be ignored if you have middleware refreshing
|
||||
// user sessions.
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user