mirror of
https://github.com/D4M13N-D3V/neroshitron.git
synced 2025-06-16 13:19:17 +00:00
Compare commits
227 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 |
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"
|
||||
}
|
||||
}
|
57
README.md
57
README.md
@ -1,29 +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
|
||||
|
||||
### Running With Docker
|
||||
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, AppWrite, and the UI.
|
||||
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/
|
||||
|
||||
#### OwnCast
|
||||
|
||||
|
||||
### 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
|
||||

|
||||
|
||||
#### AppWrite
|
||||
http://localhost:80/
|
||||
You will need to register and sign up, the first account on the appwrite instance will be the admin account.ç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.
|
||||
# Database Diagram
|
||||

|
||||
|
||||
#### UI
|
||||
http://localhost:3000
|
||||
|
||||
### Running Without Docker
|
||||
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;
|
||||
|
15053
package-lock.json
generated
15053
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"
|
||||
},
|
||||
"include": [
|
||||
"next-env.d.ts",
|
||||
"**/*.ts",
|
||||
"**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
"jsx": "preserve",
|
||||
"incremental": true,
|
||||
"plugins": [
|
||||
{
|
||||
"name": "next"
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
},
|
||||
"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