update
This commit is contained in:
parent
6f3a08867f
commit
36d554c16b
30 changed files with 5790 additions and 650 deletions
|
@ -7,14 +7,21 @@ SERVER_DOMAIN="https://example.org"
|
|||
# Default Instances and Options
|
||||
## Set the instances you want to use.
|
||||
## Can be overriden by the user in their preferences.
|
||||
### Supabase Server
|
||||
SUPABASE_URL="http://supa.example.com"
|
||||
SUPABASE_ANON_KEY="anon_key"
|
||||
### Invidious
|
||||
DEFAULT_MEDIA_PROXY="https://yt.sudovanilla.org" # Invidious (YouTube)
|
||||
DEFAULT_MEDIA_DATA_PROXY="https://yt.sudovanilla.org" # Invidious (YouTube)
|
||||
### SafeTwitch
|
||||
DEFAULT_STREAM_PROXY="https://twitch-backend.sudovanilla.org" # SafeTwitch (Twitch)
|
||||
DEFAULT_STREAM_DATA_PROXY="https://twitch-backend.sudovanilla.org" # SafeTwitch (Twitch)
|
||||
### Image Proxy
|
||||
DEFAULT_IMAGE_PROXY="https://ipx.sudovanilla.org"
|
||||
### Options
|
||||
DEFAULT_PLAYER="Zorn"
|
||||
|
||||
# Important Information
|
||||
# Source Code Information
|
||||
## If you've modified the source code, please publish
|
||||
## your changes and list the repo here.
|
||||
MODIFIED="false"
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -25,3 +25,6 @@ pnpm-debug.log*
|
|||
/src/pages/en/
|
||||
/src/pages/jp/
|
||||
/src/pages/ru/
|
||||
|
||||
# other
|
||||
supabase/
|
24
README.md
24
README.md
|
@ -24,27 +24,25 @@ ___
|
|||
- [ ] Allow 4K
|
||||
- [ ] Allow 8K
|
||||
- [ ] Account System (Based on [Account System Demo](https://ark.sudovanilla.org/MinPluto/Account-System-Demo))
|
||||
- [ ] Use Supabase Library
|
||||
- [x] Use Supabase Library
|
||||
- [ ] Create Pages:
|
||||
- [ ] Subscription Feed
|
||||
- [ ] History (Maybe, maybe not)
|
||||
- [ ] Login
|
||||
- [ ] Register
|
||||
- [ ] Account
|
||||
- [x] Login
|
||||
- [x] Register
|
||||
- [x] Account
|
||||
- [ ] Preferences
|
||||
- [ ] Delete
|
||||
- [ ] Anomymous Account Creation
|
||||
- [ ] Email Confirmation Code
|
||||
- [x] Email Confirmation Code
|
||||
- [ ] Ability to:
|
||||
- [ ] Update Data
|
||||
- [ ] Avatar (Reminder: Proxy avatar URL)
|
||||
- [ ] Username
|
||||
- [x] Username
|
||||
- [ ] Email
|
||||
- [ ] Pasword
|
||||
- [ ] Delete Account
|
||||
- [ ] API
|
||||
- [ ] `/api/update/avatar` (Reminder: Proxy avatar URL)
|
||||
- [ ] `/api/update/name`
|
||||
- [x] `/api/update/name`
|
||||
- [ ] `/api/update/email`
|
||||
- [ ] `/api/update/password`
|
||||
- [ ] `/api/update/preference/ui/theme`
|
||||
|
@ -57,11 +55,11 @@ ___
|
|||
- [ ] `/api/update/preference/instance/invidious/data`
|
||||
- [ ] `/api/update/preference/instance/safetwitch/media`
|
||||
- [ ] `/api/update/preference/instance/safetwitch/data`
|
||||
- [ ] `/api/auth/login`
|
||||
- [ ] `/api/auth/register`
|
||||
- [x] `/api/auth/login`
|
||||
- [x] `/api/auth/register`
|
||||
- [ ] `/api/auth/delete`
|
||||
- [ ] `/api/auth/confirm`
|
||||
- [ ] `/api/auth/logout`
|
||||
- [x] `/api/auth/confirm`
|
||||
- [x] `/api/auth/logout`
|
||||
- [ ] `/api/anon/create`
|
||||
- [ ] `/api/anon/delete`
|
||||
- [ ] `/api/anon/signout`
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { defineConfig } from 'astro/config'
|
||||
import node from '@astrojs/node'
|
||||
import vue from '@astrojs/vue'
|
||||
import astroI18next from "astro-i18next"
|
||||
import { defineConfig } from 'astro/config';
|
||||
import node from '@astrojs/node';
|
||||
import vue from '@astrojs/vue';
|
||||
import astroI18next from "astro-i18next";
|
||||
import mdx from '@astrojs/mdx';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Project Structure
|
||||
publicDir: './src/public/',
|
||||
|
@ -21,8 +22,16 @@ export default defineConfig({
|
|||
// Use Server-Side Rendering
|
||||
output: 'server',
|
||||
adapter: node({
|
||||
mode: 'standalone',
|
||||
mode: 'standalone'
|
||||
}),
|
||||
// Vite
|
||||
vite: {
|
||||
server: {
|
||||
hmr: false // Auto Reload
|
||||
}
|
||||
},
|
||||
// Others
|
||||
devToolbar: {enabled: false},
|
||||
})
|
||||
devToolbar: {
|
||||
enabled: false
|
||||
}
|
||||
});
|
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
5746
package-lock.json
generated
5746
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -33,11 +33,11 @@
|
|||
"@astrojs/vue": "^4.5.0",
|
||||
"@iconoir/vue": "^7.7.0",
|
||||
"@openpanel/sdk": "^0.0.9-beta",
|
||||
"astro": "^4.11.5",
|
||||
"@supabase/supabase-js": "^2.44.4",
|
||||
"astro": "^4.12.1",
|
||||
"astro-analytics": "^2.7.0",
|
||||
"astro-i18next": "^1.0.0-beta.21",
|
||||
"astro-useragent": "^4.0.2",
|
||||
"express": "^4.19.2",
|
||||
"rss-to-json": "^2.1.1",
|
||||
"undici": "^6.19.2"
|
||||
},
|
||||
|
|
|
@ -19,9 +19,6 @@ if (Astro.cookies.get("Telemtry") === undefined) {
|
|||
Astro.cookies.set("Telemtry", "Disabled", {path: "/",sameSite: 'strict'})
|
||||
}
|
||||
|
||||
//// Check what language the user has set it to and switch to it
|
||||
|
||||
|
||||
// Properties
|
||||
const {
|
||||
Title,
|
||||
|
@ -99,5 +96,4 @@ if (Astro.url.href.match('watch')) {
|
|||
</head>
|
||||
<Analytics/>
|
||||
|
||||
<script type="module" is:inline>
|
||||
</script>
|
||||
<script is:inline src="./assets/vendor/preline/preline.js"></script>
|
5
src/env.d.ts
vendored
5
src/env.d.ts
vendored
|
@ -1 +1,6 @@
|
|||
/// <reference types="astro/client" />
|
||||
declare namespace App {
|
||||
interface Locals {
|
||||
email: string;
|
||||
}
|
||||
}
|
115
src/layouts/Settings.astro
Normal file
115
src/layouts/Settings.astro
Normal file
|
@ -0,0 +1,115 @@
|
|||
---
|
||||
// Properties
|
||||
const { Title, Description } = Astro.props
|
||||
|
||||
// Components
|
||||
import Head from '@components/global/Head.astro'
|
||||
import MobileNav from '@components/global/MobileNav.astro'
|
||||
import Sidebar from '@components/global/Sidebar.astro'
|
||||
import Footer from '@components/global/Footer.astro'
|
||||
|
||||
// Styles
|
||||
import '@styles/index.scss'
|
||||
import '@styles/mobile.scss'
|
||||
import { CodeBrackets, EditPencil, EvPlugXmark, FloppyDisk, HelpCircle, InfoCircle, LogOut, Play, PrivacyPolicy, ProfileCircle, Server, UnionAlt, XmarkCircle } from '@iconoir/vue'
|
||||
---
|
||||
|
||||
<Head Title={Title} Description={Description}/>
|
||||
<MobileNav/>
|
||||
<Sidebar/>
|
||||
<div class="content settings-area">
|
||||
<div class="settings-sidebar">
|
||||
<div>
|
||||
<h2>General</h2>
|
||||
<a id="sidebar-disable" href="#"><EditPencil/> Customization</a>
|
||||
<a id="sidebar-disable" href="#"><Play/> Video Player</a>
|
||||
<a id="sidebar-disable" href="#"><CodeBrackets/> CSS/JS</a>
|
||||
<h2>You</h2>
|
||||
<a href="#"><ProfileCircle/> Account</a>
|
||||
<h2>Advanced</h2>
|
||||
<a id="sidebar-disable" href="#"><EvPlugXmark/> Reset</a>
|
||||
<a id="sidebar-disable" href="#"><FloppyDisk/> Backup & Restore</a>
|
||||
<a id="sidebar-disable" href="#"><XmarkCircle/> Delete Account</a>
|
||||
</div>
|
||||
<div>
|
||||
<a id="sidebar-disable" href="#"><HelpCircle/> Help</a>
|
||||
<a href="#"><UnionAlt/> Telemtry</a>
|
||||
<a href="#"><Server/> Instance</a>
|
||||
<a href="#"><PrivacyPolicy/> Privacy Policy</a>
|
||||
<hr/>
|
||||
<a href="#"><LogOut/> Log Out</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settings-content">
|
||||
<slot/>
|
||||
</div>
|
||||
</div>
|
||||
<Footer/>
|
||||
|
||||
<style is:inline>a[href="/settings"] {background: rgb(255 255 255 / 25%) !important;border: 2px rgba(255, 255, 255, 0.25) solid !important;}</style>
|
||||
<style lang="scss">
|
||||
.settings-area {
|
||||
display: flex;
|
||||
gap: 24px;
|
||||
position: relative;
|
||||
flex-wrap: wrap;
|
||||
align-items: stretch;
|
||||
min-height: 100vh;
|
||||
.settings-content {
|
||||
max-width: 750px;
|
||||
margin: 0px auto;
|
||||
}
|
||||
.settings-sidebar {
|
||||
background: #161616;
|
||||
width: 180px;
|
||||
color: white;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
padding: 0px 12px;
|
||||
div {
|
||||
position: sticky;
|
||||
}
|
||||
div:nth-child(1) {
|
||||
position: sticky;
|
||||
top: 0px;
|
||||
}
|
||||
div:nth-child(2) {
|
||||
position: sticky;
|
||||
bottom: 0px;
|
||||
}
|
||||
h2 {
|
||||
font-size: 16px;
|
||||
padding-left: 12px;
|
||||
}
|
||||
a {
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
margin-bottom: 6px;
|
||||
border-radius: 6px;
|
||||
padding: 4px 12px;
|
||||
background: transparent;
|
||||
border: 2px transparent solid;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
font-size: 14px;
|
||||
&:hover {
|
||||
background: rgb(255 255 255 / 05%);
|
||||
border: 2px rgba(255, 255, 255, 0.05) solid;
|
||||
}
|
||||
svg {
|
||||
width: 18px;
|
||||
}
|
||||
&#sidebar-disable {
|
||||
filter: brightness(0.4);
|
||||
cursor: not-allowed;
|
||||
&:hover {
|
||||
background: transparent;
|
||||
border: 2px transparent solid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
14
src/library/supabase.ts
Normal file
14
src/library/supabase.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { createClient } from "@supabase/supabase-js";
|
||||
|
||||
export const supabase = createClient(
|
||||
import.meta.env.SUPABASE_URL,
|
||||
import.meta.env.SUPABASE_ANON_KEY,
|
||||
{
|
||||
auth: {
|
||||
flowType: "pkce",
|
||||
autoRefreshToken: false,
|
||||
detectSessionInUrl: false,
|
||||
persistSession: true,
|
||||
},
|
||||
},
|
||||
);
|
53
src/pages/account/confirm-your-email.astro
Normal file
53
src/pages/account/confirm-your-email.astro
Normal file
|
@ -0,0 +1,53 @@
|
|||
---
|
||||
import i18next,{ t, changeLanguage } from "i18next";
|
||||
import Base from "@layouts/Default.astro";
|
||||
|
||||
import '@styles/form.scss'
|
||||
---
|
||||
|
||||
<Base Title="MinPluto" Description="">
|
||||
<div class="force-center">
|
||||
<img src="/images/logo/MinPluto - Image Logo Full with Shadow.png"/>
|
||||
<hr/>
|
||||
<img src="/images/backgrounds/1.webp"/>
|
||||
</div>
|
||||
<form action="/api/auth/confirm" method="post">
|
||||
<div class="form-field">
|
||||
<label>Email</label>
|
||||
<input name="email" type="email" autocomplete="off" required/>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label>Code</label>
|
||||
<input name="code" type="text" autocomplete="off" required/>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<div></div>
|
||||
<div>
|
||||
<span></span>
|
||||
<button type="submit">Confirm</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Base>
|
||||
|
||||
<style is:global>
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
left: 50%;
|
||||
transform: translate(-57%);
|
||||
-webkit-mask-image: linear-gradient(180deg, transparent 5%, rgb(0 0 0) 52%, rgb(0 0 0) 44%, transparent 95%);
|
||||
}
|
||||
@media only screen and (min-width: 875px) {
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.force-center {
|
||||
text-align: center;
|
||||
padding-top: 10%;
|
||||
}
|
||||
.search-bar {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
59
src/pages/account/index.astro
Normal file
59
src/pages/account/index.astro
Normal file
|
@ -0,0 +1,59 @@
|
|||
---
|
||||
// i18n
|
||||
import i18next,{ t, changeLanguage } from "i18next";
|
||||
import Settings from "@layouts/Settings.astro";
|
||||
|
||||
// Supabase Data
|
||||
import { supabase } from "@library/supabase"
|
||||
const { data: { user } } = await supabase.auth.getUser()
|
||||
const ID = user?.id
|
||||
const Name = user?.user_metadata.name
|
||||
const Email = user?.email
|
||||
|
||||
// Styles
|
||||
import '@styles/form.scss'
|
||||
---
|
||||
|
||||
<Settings Title="Account" Description="Manage your account">
|
||||
<p>Account ID: {ID}</p>
|
||||
<form action="/api/update/name" method="post">
|
||||
<div class="form-field">
|
||||
<label>Username</label>
|
||||
<input name="name" type="text" autocomplete="off" value={Name} required/>
|
||||
</div>
|
||||
<div class="form-actions"><div></div><div><span></span><button type="submit">Update</button></div></div>
|
||||
</form>
|
||||
<form>
|
||||
<div class="form-field">
|
||||
<label>Email</label>
|
||||
<input name="email" type="email" autocomplete="off" value={Email} readonly/>
|
||||
</div>
|
||||
<div class="form-actions"><div></div><div><span></span><button type="submit">Update</button></div></div>
|
||||
</form>
|
||||
<form onkeypress="CheckPasswordConfirmation()">
|
||||
<div class="form-field">
|
||||
<label>Password</label>
|
||||
<input id="password" name="password" type="password" autocomplete="off" required/>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label>Confirm Password</label>
|
||||
<input id="confirm_password" name="password" type="password" autocomplete="off" required/>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<div>
|
||||
<a href="#">Forgot Password</a>
|
||||
</div>
|
||||
<div><span></span><button type="submit">Update</button></div>
|
||||
</div>
|
||||
</form>
|
||||
</Settings>
|
||||
|
||||
<script is:inline>
|
||||
function CheckPasswordConfirmation() {
|
||||
if (document.getElementById('confirm_password').value !== document.getElementById('password').value) {
|
||||
document.getElementById('confirm_password').setCustomValidity('Password Must be Matching.');
|
||||
} else {
|
||||
document.getElementById('confirm_password').setCustomValidity('');
|
||||
}
|
||||
}
|
||||
</script>
|
20
src/pages/api/auth/confirm.ts
Normal file
20
src/pages/api/auth/confirm.ts
Normal file
|
@ -0,0 +1,20 @@
|
|||
import type { APIRoute } from "astro"
|
||||
import { supabase } from "@library/supabase"
|
||||
|
||||
export const POST: APIRoute = async ({ request, redirect }) => {
|
||||
const formData = await request.formData()
|
||||
const EMAIL = formData.get("email")?.toString()
|
||||
const OTP = formData.get("code")?.toString()
|
||||
|
||||
if (!OTP) {
|
||||
return new Response("Code required", { status: 400 })
|
||||
}
|
||||
|
||||
const { error } = await supabase.auth.verifyOtp({type: 'email', token: OTP, email: EMAIL})
|
||||
|
||||
if (error) {
|
||||
return new Response(error.message, { status: 500 })
|
||||
}
|
||||
|
||||
return redirect("/login?=confirmed")
|
||||
}
|
35
src/pages/api/auth/login.ts
Normal file
35
src/pages/api/auth/login.ts
Normal file
|
@ -0,0 +1,35 @@
|
|||
import type { APIRoute } from "astro"
|
||||
import { supabase } from "@library/supabase"
|
||||
|
||||
export const POST: APIRoute = async ({ request, cookies, redirect }) => {
|
||||
const formData = await request.formData()
|
||||
const email = formData.get("email")?.toString()
|
||||
const password = formData.get("password")?.toString()
|
||||
|
||||
if (!email || !password) {
|
||||
return new Response("Email and password are required", { status: 400 })
|
||||
}
|
||||
|
||||
const { data, error } = await supabase.auth.signInWithPassword({
|
||||
email,
|
||||
password,
|
||||
})
|
||||
|
||||
if (error) {
|
||||
return new Response(error.message, { status: 500 })
|
||||
}
|
||||
|
||||
const { access_token, refresh_token } = data.session
|
||||
cookies.set("sb-access-token", access_token, {
|
||||
sameSite: "strict",
|
||||
path: "/",
|
||||
secure: true,
|
||||
})
|
||||
cookies.set("sb-refresh-token", refresh_token, {
|
||||
sameSite: "strict",
|
||||
path: "/",
|
||||
secure: true,
|
||||
})
|
||||
|
||||
return redirect("/")
|
||||
}
|
15
src/pages/api/auth/logout.ts
Normal file
15
src/pages/api/auth/logout.ts
Normal file
|
@ -0,0 +1,15 @@
|
|||
import type { APIRoute } from "astro"
|
||||
import { supabase } from "@library/supabase"
|
||||
import type { Provider } from "@supabase/supabase-js"
|
||||
|
||||
export const GET: APIRoute = async ({ cookies, redirect }) => {
|
||||
|
||||
if(cookies.get('anonymous-session')) {
|
||||
return redirect('/account/anon/end')
|
||||
} else {
|
||||
cookies.delete("sb-access-token", { path: "/" })
|
||||
cookies.delete("sb-refresh-token", { path: "/" })
|
||||
const { error } = await supabase.auth.signOut()
|
||||
}
|
||||
return redirect("/")
|
||||
}
|
40
src/pages/api/auth/register.ts
Normal file
40
src/pages/api/auth/register.ts
Normal file
|
@ -0,0 +1,40 @@
|
|||
import type { APIRoute } from "astro"
|
||||
import { supabase } from "@library/supabase"
|
||||
|
||||
export const POST: APIRoute = async ({ request, redirect }) => {
|
||||
const formData = await request.formData()
|
||||
const name = formData.get("username")?.toString()
|
||||
const email = formData.get("email")?.toString()
|
||||
const password = formData.get("password")?.toString()
|
||||
|
||||
if (!email || !password || !name) {
|
||||
return new Response("Email and password are required", { status: 400 })
|
||||
}
|
||||
|
||||
const { error } = await supabase.auth.signUp({
|
||||
options: {
|
||||
emailRedirectTo: "http://localhost:1930/?=welcome",
|
||||
data: {
|
||||
name: name,
|
||||
ui_theme: "Default",
|
||||
ui_color: "Default",
|
||||
ui_zen: "false",
|
||||
ui_sidebar_size: "Normal",
|
||||
invidous_data: "https://yt.sudovanilla.org",
|
||||
invidous_media: "https://yt.sudovanilla.org",
|
||||
safetwitch_data: "https://twitch.sudovanilla.org",
|
||||
safetwitch_media: "https://twitch.sudovanilla.org",
|
||||
image_proxy: "https://ipx.sudovanilla.org",
|
||||
player_type: "Zorn"
|
||||
}
|
||||
},
|
||||
email,
|
||||
password,
|
||||
})
|
||||
|
||||
if (error) {
|
||||
return new Response(error.message, { status: 500 })
|
||||
}
|
||||
|
||||
return redirect("/account/confirm-your-email")
|
||||
}
|
22
src/pages/api/update/email.ts
Normal file
22
src/pages/api/update/email.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import type { APIRoute } from "astro"
|
||||
import { supabase } from "@library/supabase"
|
||||
|
||||
export const POST: APIRoute = async ({ request, redirect }) => {
|
||||
const formData = await request.formData()
|
||||
const NewEmail = formData.get("email")?.toString()
|
||||
|
||||
if (!NewEmail) {
|
||||
return new Response("Error.", { status: 400 })
|
||||
}
|
||||
|
||||
const { error } = await supabase.auth.resend({
|
||||
type: 'email_change',
|
||||
email: NewEmail
|
||||
})
|
||||
|
||||
if (error) {
|
||||
return new Response(error.message, { status: 500 })
|
||||
}
|
||||
|
||||
return redirect("/account?=CheckEmail")
|
||||
}
|
21
src/pages/api/update/name.ts
Normal file
21
src/pages/api/update/name.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import type { APIRoute } from "astro"
|
||||
import { supabase } from "@library/supabase"
|
||||
|
||||
export const POST: APIRoute = async ({ request, redirect }) => {
|
||||
const formData = await request.formData()
|
||||
const name = formData.get("name")?.toString()
|
||||
|
||||
if (!name) {
|
||||
return new Response("Error.", { status: 400 })
|
||||
}
|
||||
|
||||
const { error } = await supabase.auth.updateUser({
|
||||
data: {name: name}
|
||||
})
|
||||
|
||||
if (error) {
|
||||
return new Response(error.message, { status: 500 })
|
||||
}
|
||||
|
||||
return redirect("/account?=NameUpdated")
|
||||
}
|
|
@ -3,7 +3,7 @@ import { t, changeLanguage } from "i18next";
|
|||
import Embed from "@layouts/Embed.astro";
|
||||
import "@styles/video.scss";
|
||||
// Configuration
|
||||
import { DEFAULT_MEDIA_DATA_PROXY, DEFAULT_MEDIA_DATA_PROXY, DEFAULT_IMAGE_PROXY, SERVER_DOMAIN } from '@utils/GetConfig'
|
||||
import { DEFAULT_MEDIA_DATA_PROXY, DEFAULT_IMAGE_PROXY, SERVER_DOMAIN } from '@utils/GetConfig'
|
||||
|
||||
// Fetch
|
||||
const SWV = Astro.url.href.split("embed/").pop();
|
||||
|
|
|
@ -78,6 +78,8 @@ const GamingSplit = GamingData.slice(0, 1)
|
|||
</div>
|
||||
</Base>
|
||||
|
||||
|
||||
<style is:inline>.sidebar-top-end a[href="/"] {background: rgb(255 255 255 / 25%) !important;border: 2px rgba(255, 255, 255, 0.25) solid !important;}</style>
|
||||
<style>
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
position: fixed;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
layout: '@layouts/Markdown.astro'
|
||||
layout: '@layouts/Settings.astro'
|
||||
---
|
||||
|
||||
import {
|
||||
|
|
58
src/pages/login.astro
Normal file
58
src/pages/login.astro
Normal file
|
@ -0,0 +1,58 @@
|
|||
---
|
||||
import i18next,{ t, changeLanguage } from "i18next";
|
||||
import Base from "@layouts/Default.astro";
|
||||
|
||||
import '@styles/form.scss'
|
||||
---
|
||||
|
||||
<Base Title="MinPluto" Description="">
|
||||
<div class="force-center">
|
||||
<img src="/images/logo/MinPluto - Image Logo Full with Shadow.png"/>
|
||||
<hr/>
|
||||
<img src="/images/backgrounds/1.webp"/>
|
||||
</div>
|
||||
<form action="/api/auth/login" method="post">
|
||||
<div class="form-field">
|
||||
<label>Email</label>
|
||||
<input name="email" type="email" autocomplete="off" required/>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label>Password</label>
|
||||
<input name="password" type="password" autocomplete="off" required/>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<div>
|
||||
<a aria-disabled="true" href="#">Forgot Password</a>
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="location.href = '/register/'">Create Account</button>
|
||||
<button type="submit">Login</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Base>
|
||||
<style is:inline>a[href="/login"] {background: rgb(255 255 255 / 25%) !important;border: 2px rgba(255, 255, 255, 0.25) solid !important;}</style>
|
||||
<style is:global>
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
left: 50%;
|
||||
transform: translate(-57%);
|
||||
-webkit-mask-image: linear-gradient(180deg, transparent 5%, rgb(0 0 0) 52%, rgb(0 0 0) 44%, transparent 95%);
|
||||
}
|
||||
@media only screen and (min-width: 875px) {
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.force-center {
|
||||
text-align: center;
|
||||
padding-top: 10%;
|
||||
}
|
||||
.search-bar {
|
||||
display: none !important;
|
||||
}
|
||||
form {
|
||||
max-width: 500px !important;
|
||||
}
|
||||
</style>
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
layout: "@layouts/Markdown.astro"
|
||||
layout: "@layouts/Settings.astro"
|
||||
---
|
||||
|
||||
import {
|
||||
|
|
66
src/pages/register.astro
Normal file
66
src/pages/register.astro
Normal file
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
import i18next,{ t, changeLanguage } from "i18next";
|
||||
import Base from "@layouts/Default.astro";
|
||||
|
||||
import '@styles/form.scss'
|
||||
---
|
||||
|
||||
<Base Title="MinPluto" Description="">
|
||||
<div class="force-center">
|
||||
<img src="/images/logo/MinPluto - Image Logo Full with Shadow.png"/>
|
||||
<hr/>
|
||||
<img src="/images/backgrounds/1.webp"/>
|
||||
</div>
|
||||
<form action="/api/auth/register" method="post">
|
||||
<div class="form-field">
|
||||
<label>Username</label>
|
||||
<input name="username" type="text" autocomplete="off" required/>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label>Email</label>
|
||||
<input name="email" type="email" autocomplete="off" required/>
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between; gap: 6px;">
|
||||
<div style="width: 100%;" class="form-field">
|
||||
<label>Password</label>
|
||||
<input name="password" type="password" autocomplete="off" required/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<div>
|
||||
<a href="/privacy">Privacy Policy</a>
|
||||
</div>
|
||||
<div>
|
||||
<button onclick="location.href = '/login'">Login</button>
|
||||
<button type="submit">Register</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</Base>
|
||||
|
||||
<style is:global>
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
left: 50%;
|
||||
transform: translate(-57%);
|
||||
-webkit-mask-image: linear-gradient(180deg, transparent 5%, rgb(0 0 0) 52%, rgb(0 0 0) 44%, transparent 95%);
|
||||
z-index: -1;
|
||||
opacity: 0.5;
|
||||
}
|
||||
@media only screen and (min-width: 875px) {
|
||||
img[src="/images/backgrounds/1.webp"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.force-center {
|
||||
text-align: center;
|
||||
padding-top: 10%;
|
||||
}
|
||||
.search-bar {
|
||||
display: none !important;
|
||||
}
|
||||
form {
|
||||
max-width: 500px !important;
|
||||
}
|
||||
</style>
|
|
@ -28,12 +28,37 @@
|
|||
"STATUS": "Status",
|
||||
"FORUM": "Forum",
|
||||
"SOURCE_CODE": "Source Code"
|
||||
},
|
||||
"ACCOUNT": {
|
||||
"CUSTOMIZATION": "",
|
||||
"VIDEO_PLAYER": "",
|
||||
"CSS/JS": "",
|
||||
"ACCOUNT": "",
|
||||
"RESET": "",
|
||||
"BACKUP_RESTORE": "",
|
||||
"DELETE_ACCOUNT": "",
|
||||
"HEADERS": {
|
||||
"SETTINGS": "Settings",
|
||||
"YOU": "You",
|
||||
"ADVANCE": "Advance"
|
||||
}
|
||||
}
|
||||
},
|
||||
"HEADER": {
|
||||
"SEARCH": "Search",
|
||||
"FEEDBACK": "Feedback"
|
||||
},
|
||||
"FORM": {
|
||||
"EMAIL": "Email",
|
||||
"PASSWORD": "Password",
|
||||
"USERNAME": "Username",
|
||||
"CREATE_ACCOUNT": "Create Account",
|
||||
"FORGOT_PASSWORD": "Forgot Password",
|
||||
"LOGIN": "Login",
|
||||
"REGISTER": "Register",
|
||||
"UPDATE": "Update",
|
||||
"SUBMIT": "Submit"
|
||||
},
|
||||
"TELEMTRY": {
|
||||
"OPTIN": "Opt-In",
|
||||
"OPTOUT": "Opt-Out"
|
||||
|
|
59
src/styles/form.scss
Normal file
59
src/styles/form.scss
Normal file
|
@ -0,0 +1,59 @@
|
|||
form {
|
||||
margin: auto;
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
margin-bottom: 12px;
|
||||
.form-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
background: #161616;
|
||||
color: white;
|
||||
border: 1px #2d2d2d solid;
|
||||
border-radius: 4px;
|
||||
padding: 6px 12px;
|
||||
position: relative;
|
||||
label {
|
||||
font-size: 12px;
|
||||
color: rgb(145, 145, 145);
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
}
|
||||
input {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 32px 12px 12px 12px;
|
||||
margin: -26px -12px -6px -12px;
|
||||
border-radius: 4px;
|
||||
&:hover {
|
||||
background: rgb(32, 32, 32);
|
||||
}
|
||||
&:focus {
|
||||
background: rgb(48, 48, 48);
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
.form-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
button {
|
||||
background: white;
|
||||
color: black;
|
||||
padding: 6px 12px;
|
||||
border-radius: 3rem;
|
||||
border: 1px white solid;
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
filter: brightness(0.8);
|
||||
}
|
||||
&:nth-child(1) {
|
||||
border: 1px white solid;
|
||||
background: transparent;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ body {
|
|||
top: 0px;
|
||||
right: 0px;
|
||||
margin: auto;
|
||||
width: calc(100% - 248px);
|
||||
width: calc(100% - 204px);
|
||||
}
|
||||
|
||||
a {
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
{
|
||||
"extends": "astro/tsconfigs/base",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"paths": {
|
||||
"@components/*": ["src/components/*"],
|
||||
"@layouts/*": ["src/layouts/*"],
|
||||
"@library/*": ["src/library/*"],
|
||||
"@root/*": ["*"],
|
||||
"@styles/*": ["src/styles/*"],
|
||||
"@utils/*": ["src/utilities/*"]
|
||||
|
|
Reference in a new issue