mirror of
https://github.com/MercuryWorkshop/adrift.git
synced 2025-05-12 22:00:02 -04:00
a "little" refactoring
This commit is contained in:
parent
95895056ef
commit
a6c8804552
11 changed files with 585 additions and 617 deletions
|
@ -1,32 +1,31 @@
|
|||
import { getDatabase, onValue, ref, set, remove, goOffline } from "firebase/database";
|
||||
import {
|
||||
getDatabase,
|
||||
onValue,
|
||||
ref,
|
||||
set,
|
||||
remove,
|
||||
goOffline,
|
||||
} from "firebase/database";
|
||||
// import "firebase-config";
|
||||
|
||||
import { v4 as uuid } from "uuid";
|
||||
import { Answer } from "./RTCTransport";
|
||||
import { browserLocalPersistence, getAuth, setPersistence, signInWithEmailAndPassword } from "firebase/auth";
|
||||
|
||||
import { getAuth } from "firebase/auth";
|
||||
|
||||
export async function signalSwarm(offer: string): Promise<Answer> {
|
||||
let id = uuid();
|
||||
const db = getDatabase();
|
||||
let reff = ref(db, `/swarm/${id}`);
|
||||
|
||||
|
||||
set(reff, offer);
|
||||
|
||||
|
||||
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
|
||||
onValue(reff, (snapshot) => {
|
||||
const text = snapshot.val();
|
||||
|
||||
if (!text)
|
||||
return;
|
||||
if (!text) return;
|
||||
let data = JSON.parse(text);
|
||||
console.log(data);
|
||||
console.log("<", data);
|
||||
|
||||
if (data.error) {
|
||||
reject(new Error(data.error));
|
||||
|
@ -37,26 +36,18 @@ export async function signalSwarm(offer: string): Promise<Answer> {
|
|||
|
||||
resolve(data);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
export async function signalAccount(offer: string): Promise<Answer> {
|
||||
|
||||
let auth = getAuth();
|
||||
|
||||
if (!auth.currentUser)
|
||||
throw new Error("not signed in");
|
||||
|
||||
if (!auth.currentUser) throw new Error("not signed in");
|
||||
|
||||
const db = getDatabase();
|
||||
let peer = ref(db, `/peers/${auth.currentUser!.uid}`);
|
||||
|
||||
|
||||
|
||||
|
||||
set(peer, offer);
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
onValue(peer, async (snapshot) => {
|
||||
const str = snapshot.val();
|
||||
if (str) {
|
||||
|
@ -65,7 +56,6 @@ export async function signalAccount(offer: string): Promise<Answer> {
|
|||
remove(peer);
|
||||
resolve(data);
|
||||
goOffline(db);
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<title></title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Cabin">
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Cabin:wght@400;500;700&display=swap"
|
||||
/>
|
||||
<script type="module" src="src/entry.ts"></script>
|
||||
<script src="uv/uv.bundle.js"></script>
|
||||
<script src="uv.config.js"></script>
|
||||
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<div id="app" class="m3-font-body-large"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -18,16 +18,17 @@
|
|||
"@iconify-icons/ic": "^1.2.13",
|
||||
"@iconify-icons/maki": "^1.2.18",
|
||||
"@iconify/svelte": "^3.1.4",
|
||||
"@mercuryworkshop/bare-client-custom": "workspace:*",
|
||||
"@rollup/browser": "^3.28.0",
|
||||
"@sveltejs/vite-plugin-svelte": "^2.4.5",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"@mercuryworkshop/bare-client-custom": "workspace:*",
|
||||
"client": "workspace:*",
|
||||
"corium": "file:../corium",
|
||||
"esbuild": "^0.19.1",
|
||||
"esbuild-plugin-inline-import": "^1.0.1",
|
||||
"firebase": "^10.1.0",
|
||||
"m3-svelte": "^2.0.3",
|
||||
"micromatch": "^4.0.5",
|
||||
"postcss": "^8.4.27",
|
||||
"postcss-load-config": "^4.0.1",
|
||||
"protocol": "workspace:*",
|
||||
|
@ -37,7 +38,6 @@
|
|||
"tracker-list": "workspace:*",
|
||||
"typescript": "^5.1.6",
|
||||
"uuid": "^9.0.0",
|
||||
"vite": "^4.4.9",
|
||||
"vite-plugin-svelte": "^3.0.1"
|
||||
"vite": "^4.4.9"
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB |
|
@ -1,9 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { Card } from "m3-svelte";
|
||||
</script>
|
||||
|
||||
<div class="h-full w-full p-5">
|
||||
<Card type="elevated">
|
||||
<h1>Step 1</h1>
|
||||
</Card>
|
||||
</div>
|
|
@ -1,165 +1,61 @@
|
|||
<script lang="ts">
|
||||
import Icon from "@iconify/svelte";
|
||||
import { setBareClientImplementation } from "@mercuryworkshop/bare-client-custom";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CircularProgressIndeterminate,
|
||||
StyleFromScheme,
|
||||
} from "m3-svelte";
|
||||
import {
|
||||
AdriftBareClient,
|
||||
Connection,
|
||||
DevWsTransport,
|
||||
RTCTransport,
|
||||
SignalFirebase,
|
||||
downloadShortcut,
|
||||
} from "client";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CircularProgressIndeterminate,
|
||||
Dialog,
|
||||
RadioAnim3,
|
||||
SnackbarAnim,
|
||||
StyleFromScheme,
|
||||
TextField,
|
||||
} from "m3-svelte";
|
||||
|
||||
import iconDiscord from "@iconify-icons/ic/outline-discord";
|
||||
import iconGithub from "@iconify-icons/bi/github";
|
||||
|
||||
import Icon from "@iconify/svelte";
|
||||
|
||||
import type { Transport } from "protocol";
|
||||
|
||||
import Proxy from "./Proxy.svelte";
|
||||
import { initializeApp } from "firebase/app";
|
||||
import ConnectionCmp from "./Connection.svelte";
|
||||
import { UIState } from "./state";
|
||||
|
||||
import TrackerList from "tracker-list";
|
||||
import {
|
||||
browserLocalPersistence,
|
||||
createUserWithEmailAndPassword,
|
||||
getAuth,
|
||||
setPersistence,
|
||||
signInWithEmailAndPassword,
|
||||
} from "firebase/auth";
|
||||
let state = UIState.Idle;
|
||||
let stateStr = "";
|
||||
|
||||
import { getAnalytics } from "firebase/analytics";
|
||||
let dialogConnection = false;
|
||||
|
||||
import logo from "./logo.png";
|
||||
import AccountCreation from "./AccountCreation.svelte";
|
||||
import { goOffline } from "firebase/database";
|
||||
let devTransport: Transport;
|
||||
async function onOpen() {
|
||||
console.log("[TRANSPORT DEV] opened");
|
||||
|
||||
enum ReadyState {
|
||||
Idle,
|
||||
Connecting,
|
||||
Connected,
|
||||
AccountCreation,
|
||||
}
|
||||
let state = ReadyState.Idle;
|
||||
|
||||
let transport: Transport;
|
||||
|
||||
let rtctransport: RTCTransport | undefined;
|
||||
|
||||
let email = "";
|
||||
let password = "";
|
||||
|
||||
let connectionState = "";
|
||||
|
||||
let showSwarmWarning = false;
|
||||
let showLogin = false;
|
||||
type TrackerID = keyof typeof TrackerList;
|
||||
type Tracker = (typeof TrackerList)[TrackerID];
|
||||
|
||||
let chosenTracker: TrackerID | undefined;
|
||||
|
||||
let showTrackerList = false;
|
||||
|
||||
let createaccount = false;
|
||||
|
||||
let snackbar: (data: any) => void;
|
||||
|
||||
async function onTransportOpen() {
|
||||
console.log("Transport opened");
|
||||
|
||||
let connection = new Connection(transport);
|
||||
// TODO: error handling here
|
||||
const connection = new Connection(devTransport);
|
||||
await connection.initialize();
|
||||
let bare = new AdriftBareClient(connection);
|
||||
const bare = new AdriftBareClient(connection);
|
||||
setBareClientImplementation(bare);
|
||||
state = ReadyState.Connected;
|
||||
state = UIState.Connected;
|
||||
}
|
||||
|
||||
function onTransportClose() {
|
||||
console.warn("Transport closed");
|
||||
}
|
||||
|
||||
function createRTCTransport() {
|
||||
let transport = new RTCTransport(
|
||||
onTransportOpen,
|
||||
onTransportClose,
|
||||
async function connectDevHttp() {
|
||||
state = UIState.Connecting;
|
||||
const transport = new RTCTransport(
|
||||
onOpen,
|
||||
() => console.warn("[TRANSPORT] closed"),
|
||||
() => {
|
||||
connectionState = `Connection ${transport.peer.connectionState}...`;
|
||||
stateStr = `Connection ${transport.peer.connectionState}...`;
|
||||
},
|
||||
() => {
|
||||
connectionState = `Signaling ${transport.peer.connectionState}...`;
|
||||
stateStr = `Signaling ${transport.peer.connectionState}...`;
|
||||
},
|
||||
() => {
|
||||
if (transport.peer.connectionState == "new") {
|
||||
connectionState = `Creating an offer...`;
|
||||
stateStr = `Creating an offer...`;
|
||||
} else {
|
||||
connectionState = `Gathering ${transport.peer.connectionState}...`;
|
||||
stateStr = `Gathering ${transport.peer.connectionState}...`;
|
||||
}
|
||||
}
|
||||
);
|
||||
return transport;
|
||||
}
|
||||
|
||||
async function initFirebase() {
|
||||
if (!chosenTracker) return;
|
||||
let tracker = TrackerList[chosenTracker];
|
||||
let app = initializeApp(tracker.firebase);
|
||||
getAnalytics(app);
|
||||
}
|
||||
|
||||
async function connectAccount() {
|
||||
rtctransport = transport = createRTCTransport();
|
||||
|
||||
state = ReadyState.Connecting;
|
||||
let offer = await rtctransport.createOffer();
|
||||
connectionState = "Finding your node...";
|
||||
let answer = await SignalFirebase.signalAccount(JSON.stringify(offer));
|
||||
connectionState = "Linking to node...";
|
||||
await new Promise((r) => {
|
||||
setTimeout(r, 1000);
|
||||
});
|
||||
rtctransport.answer(answer.answer, answer.candidates);
|
||||
}
|
||||
|
||||
async function connectSwarm() {
|
||||
await initFirebase();
|
||||
|
||||
state = ReadyState.Connecting;
|
||||
|
||||
rtctransport = transport = createRTCTransport();
|
||||
|
||||
let offer = await rtctransport.createOffer();
|
||||
connectionState = "Routing you to an available node...";
|
||||
try {
|
||||
let answer = await SignalFirebase.signalSwarm(JSON.stringify(offer));
|
||||
|
||||
connectionState = "Linking to node...";
|
||||
await new Promise((r) => {
|
||||
setTimeout(r, 500);
|
||||
});
|
||||
|
||||
rtctransport.answer(answer.answer, answer.candidates);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
connectionState = e;
|
||||
}
|
||||
}
|
||||
|
||||
async function connectDevHttp() {
|
||||
rtctransport = transport = createRTCTransport();
|
||||
let offer = await rtctransport.createOffer();
|
||||
console.log("offer created", offer);
|
||||
console.log(JSON.stringify(offer));
|
||||
devTransport = transport;
|
||||
let offer = await transport.createOffer();
|
||||
console.log("offer", offer);
|
||||
|
||||
const r = await fetch("http://localhost:3000/connect", {
|
||||
method: "POST",
|
||||
|
@ -170,394 +66,181 @@
|
|||
throw new Error("connect: " + r.status + " " + r.statusText);
|
||||
}
|
||||
const { answer, candidates } = await r.json();
|
||||
await rtctransport.answer(answer, candidates);
|
||||
await transport.answer(answer, candidates);
|
||||
}
|
||||
|
||||
async function connectDevWS() {
|
||||
transport = new DevWsTransport(onTransportOpen, () =>
|
||||
console.log("onclose")
|
||||
state = UIState.Connecting;
|
||||
devTransport = new DevWsTransport(onOpen, () =>
|
||||
console.log("[TRANSPORT DEV] closed")
|
||||
);
|
||||
}
|
||||
|
||||
let trackerstatuses: Partial<Record<TrackerID, object | null>> = {};
|
||||
for (let id in TrackerList) {
|
||||
let tracker = TrackerList[id as TrackerID];
|
||||
trackerstatuses[id as TrackerID] = null;
|
||||
|
||||
let url = new URL(`${tracker.tracker}/stats`);
|
||||
url.protocol = "https://";
|
||||
fetch(url).then(async (data) => {
|
||||
trackerstatuses[id as TrackerID] = await data.json();
|
||||
console.log(trackerstatuses);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if state == ReadyState.Connected}
|
||||
<svelte:head>
|
||||
<title>Adrift</title>
|
||||
</svelte:head>
|
||||
|
||||
{#if state == UIState.Connected}
|
||||
<Proxy />
|
||||
{:else if state == ReadyState.Connecting}
|
||||
<div class="h-full w-full flex justify-center items-center">
|
||||
{:else if state == UIState.Connecting}
|
||||
<div class="h-full flex justify-center items-center">
|
||||
<Card type="outlined">
|
||||
<div class="flex items-center p-2">
|
||||
<div class="flex items-center mb-4 gap-4">
|
||||
<CircularProgressIndeterminate />
|
||||
<div class="p-5" />
|
||||
<h2 class="text-xl">
|
||||
{connectionState}
|
||||
</h2>
|
||||
<h2 class="text-xl">{stateStr}</h2>
|
||||
</div>
|
||||
<br />
|
||||
<p class="text-sm opacity-70">
|
||||
<p class="text-sm text-on-surface-variant">
|
||||
Adrift is routing you to a server available to take your requests.<br
|
||||
/>The initial connection may take several minutes depending on server
|
||||
load
|
||||
</p>
|
||||
</Card>
|
||||
</div>
|
||||
{:else if !import.meta.env.VITE_ADRIFT_DEV}
|
||||
<div class="flex flex-col h-full">
|
||||
<div id="topbar" class="flex justify-between items-center p-4">
|
||||
<div id="logo">
|
||||
<Card type="">
|
||||
{:else if import.meta.env.VITE_ADRIFT_DEV}
|
||||
<div class="h-full flex justify-center items-center">
|
||||
<Card type="outlined">
|
||||
<h2 class="m3-font-headline-large mb-4">Adrift DEV</h2>
|
||||
<div class="flex gap-4">
|
||||
<Button type="filled" on:click={connectDevHttp}>
|
||||
Connect with localhost WebRTC transport over HTTP signaling
|
||||
</Button>
|
||||
<Button type="filled" on:click={connectDevWS}>
|
||||
Connect with localhost websocket transport
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="h-full flex flex-col p-4 gap-6">
|
||||
<div class="flex items-center text-3xl">
|
||||
<Icon icon="material-symbols:sailing" />
|
||||
<p class="text-2xl ml-3">Adrift</p>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
<div id="nav" />
|
||||
<div id="links">
|
||||
<Card type="elevated">
|
||||
<div class="flex">
|
||||
<a href="https://discord.gg/bAgNyGpXSx">
|
||||
<Icon icon={iconDiscord} class="icon" />
|
||||
</a>
|
||||
<spacer />
|
||||
<a href="https://github.com/MercuryWorkshop/adrift">
|
||||
<Icon icon={iconGithub} class="icon" />
|
||||
</a>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-col flex-1">
|
||||
<div class="flex m-4">
|
||||
<Card
|
||||
type="elevated"
|
||||
extraOptions={{ class: "m3-container type-elevated w-9/12" }}
|
||||
extraOptions={{ class: "m3-container type-elevated lg:w-3/4" }}
|
||||
>
|
||||
<div class="w-full">
|
||||
<h2 class="text-6xl">Surf the web, Adrift</h2>
|
||||
<h2 class="text-2xl">
|
||||
A fast and modern decentralized proxy network
|
||||
</h2>
|
||||
</div>
|
||||
<div class="mt-5 flex justify-between">
|
||||
<Button type="filled" on:click={() => (showTrackerList = true)}
|
||||
>Start Browsing</Button
|
||||
>
|
||||
<h2 class="text-2xl">A fast and modern decentralized proxy network</h2>
|
||||
<div class="mt-6 flex gap-4">
|
||||
<Button type="filled" on:click={() => (dialogConnection = true)}>
|
||||
Start browsing
|
||||
</Button>
|
||||
{#if !import.meta.env.VITE_ADRIFT_SINGLEFILE}
|
||||
<Button
|
||||
type="text"
|
||||
on:click={() => {
|
||||
downloadShortcut("adrift.html", "Homework");
|
||||
}}>Get Shortcut</Button
|
||||
on:click={() => downloadShortcut("adrift.html", "Homework")}
|
||||
>
|
||||
Get shortcut
|
||||
</Button>
|
||||
{/if}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
<div
|
||||
class="flex h-full justify-end m-4 transition-all"
|
||||
class:opacity-0={!showTrackerList}
|
||||
>
|
||||
<Card
|
||||
type="elevated"
|
||||
extraOptions={{
|
||||
class: "m3-container type-elevated w-9/12 flex flex-col",
|
||||
}}
|
||||
extraOptions={{ class: "m3-container type-elevated mt-auto" }}
|
||||
>
|
||||
<h2 class="text-4xl">Select a Tracker</h2>
|
||||
<h2 class="text-1xl">Trackers allow you to connect to Adrift</h2>
|
||||
<div class="mt-5 space-y-3">
|
||||
{#each Object.keys(TrackerList) as tracker}
|
||||
<Card type="outlined">
|
||||
<label>
|
||||
<div class="flex items-center">
|
||||
<svelte:component this={RadioAnim3}>
|
||||
<input
|
||||
type="radio"
|
||||
id={tracker}
|
||||
name="tabs"
|
||||
value={tracker}
|
||||
bind:group={chosenTracker}
|
||||
/>
|
||||
</svelte:component>
|
||||
<p class="ml-3 text-xl">
|
||||
{tracker}
|
||||
</p>
|
||||
<div class="flex gap-8 items-center">
|
||||
<a class="mr-auto" href="https://mercurywork.shop">
|
||||
© 2023 Mercury Workshop
|
||||
</a>
|
||||
|
||||
<a href="https://discord.gg/bAgNyGpXSx" class="text-2xl">
|
||||
<Icon icon="ic:round-discord" />
|
||||
</a>
|
||||
<a href="https://github.com/MercuryWorkshop/adrift" class="text-2xl">
|
||||
<Icon icon="mdi:github" />
|
||||
</a>
|
||||
</div>
|
||||
<p>
|
||||
{TrackerList[tracker].description}
|
||||
</p>
|
||||
<p class="opacity-50">
|
||||
{trackerstatuses[tracker]
|
||||
? trackerstatuses[tracker]?.members?.length
|
||||
: "loading"} swarm members
|
||||
</p>
|
||||
</label>
|
||||
</Card>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="flex-1" />
|
||||
<div class="mt-5 flex">
|
||||
{#if chosenTracker}
|
||||
<Button type="elevated" on:click={() => (showSwarmWarning = true)}
|
||||
>Connect to the swarm</Button
|
||||
>
|
||||
<Button
|
||||
type="filled"
|
||||
on:click={async () => {
|
||||
await initFirebase();
|
||||
|
||||
let auth = getAuth();
|
||||
await setPersistence(auth, browserLocalPersistence);
|
||||
|
||||
if (!auth.currentUser) {
|
||||
showLogin = true;
|
||||
} else {
|
||||
await connectAccount();
|
||||
}
|
||||
}}>Connect with login</Button
|
||||
>
|
||||
<ConnectionCmp bind:dialogConnection bind:state bind:stateStr />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<Dialog headline="WARNING" bind:open={showSwarmWarning}>
|
||||
<h2 class="text-2xl">
|
||||
TLS has not currently been implemented for the Adrift Swarm. It
|
||||
will later, but until then your data will not be private, and you
|
||||
should not enter any sensitive information on any page
|
||||
</h2>
|
||||
<br />
|
||||
<Button type="filled" on:click={() => (showLogin = false)}
|
||||
>Cancel</Button
|
||||
>
|
||||
<Button type="outlined" on:click={connectSwarm}
|
||||
>I understand, Connect</Button
|
||||
>
|
||||
</Dialog>
|
||||
|
||||
<Dialog headline="Log in to connect" bind:open={showLogin}>
|
||||
<button
|
||||
class="text-primary my-3"
|
||||
on:click={() => ((createaccount = true), (showLogin = false))}
|
||||
>New here? Create an account</button
|
||||
>
|
||||
<br />
|
||||
<TextField name="email" bind:value={email} />
|
||||
<TextField
|
||||
name="password"
|
||||
bind:value={password}
|
||||
extraOptions={{ type: "password" }}
|
||||
/>
|
||||
|
||||
<div class="flex mt-5">
|
||||
<Button type="outlined" on:click={() => (showLogin = false)}
|
||||
>Cancel</Button
|
||||
>
|
||||
<Button
|
||||
type="filled"
|
||||
on:click={async () => {
|
||||
try {
|
||||
await signInWithEmailAndPassword(
|
||||
getAuth(),
|
||||
email,
|
||||
password
|
||||
);
|
||||
connectAccount();
|
||||
} catch (e) {
|
||||
snackbar({ message: e, closable: true });
|
||||
}
|
||||
}}>Connect</Button
|
||||
>
|
||||
</div>
|
||||
</Dialog>
|
||||
<Dialog bind:open={createaccount} headline="Create an account">
|
||||
<TextField name="email" bind:value={email} />
|
||||
<TextField
|
||||
name="password"
|
||||
bind:value={password}
|
||||
extraOptions={{ type: "password" }}
|
||||
/>
|
||||
|
||||
<p>
|
||||
Note: to be able to connect, you'll need to download an exit node
|
||||
and run it on a computer with an uncensored internet connection
|
||||
</p>
|
||||
|
||||
<div class="flex mt-5">
|
||||
<Button
|
||||
type="filled"
|
||||
on:click={async () => {
|
||||
try {
|
||||
await createUserWithEmailAndPassword(
|
||||
getAuth(),
|
||||
email,
|
||||
password
|
||||
);
|
||||
createaccount = false;
|
||||
} catch (e) {
|
||||
snackbar({ message: e, closable: true });
|
||||
}
|
||||
}}>Create Account</Button
|
||||
>
|
||||
</div></Dialog
|
||||
>
|
||||
</Card>
|
||||
</div>
|
||||
<div class="flex m-4">
|
||||
<Card
|
||||
type="elevated"
|
||||
extraOptions={{ class: "m3-container type-elevated w-full" }}
|
||||
>
|
||||
<div class="flex space-x-10">
|
||||
<a class="text-1xl" href="https://mercurywork.shop"
|
||||
>© 2023 Mercury Workshop</a
|
||||
>
|
||||
|
||||
<div class="space-x-3">
|
||||
<a class="text-1xl" href="https://discord.gg/bAgNyGpXSx"
|
||||
>discord</a
|
||||
>
|
||||
<a class="text-1xl" href="https://github.com/MercuryWorkshop"
|
||||
>github</a
|
||||
>
|
||||
</div>
|
||||
<div />
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="flex items-center justify-center h-full">
|
||||
<Card type="elevated">
|
||||
<div class="flex flex-col h-full">
|
||||
<h2 class="m3-font-headline-large m-3">Adrift DEV</h2>
|
||||
<div class="flex space-evenly pad-children">
|
||||
<Button type="filled" on:click={connectDevHttp}
|
||||
>Connect with WebRTC transport over localhost HTTP signaling</Button
|
||||
>
|
||||
<Button type="filled" on:click={connectDevWS}
|
||||
>Connect with localhost websocket transport</Button
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
{/if}
|
||||
<svelte:component this={SnackbarAnim} bind:show={snackbar} />
|
||||
|
||||
<StyleFromScheme
|
||||
lightScheme={{
|
||||
primary: 1284831119,
|
||||
primary: 4282411062,
|
||||
onPrimary: 4294967295,
|
||||
primaryContainer: 4293516799,
|
||||
onPrimaryContainer: 4280291399,
|
||||
inversePrimary: 4291804670,
|
||||
secondary: 4284636017,
|
||||
primaryContainer: 4290834352,
|
||||
onPrimaryContainer: 4278198784,
|
||||
inversePrimary: 4289057685,
|
||||
secondary: 4283720525,
|
||||
onSecondary: 4294967295,
|
||||
secondaryContainer: 4293451512,
|
||||
onSecondaryContainer: 4280162603,
|
||||
tertiary: 4286468704,
|
||||
secondaryContainer: 4292339917,
|
||||
onSecondaryContainer: 4279377678,
|
||||
tertiary: 4281886056,
|
||||
onTertiary: 4294967295,
|
||||
tertiaryContainer: 4294957539,
|
||||
onTertiaryContainer: 4281405469,
|
||||
tertiaryContainer: 4290571246,
|
||||
onTertiaryContainer: 4278198306,
|
||||
error: 4290386458,
|
||||
onError: 4294967295,
|
||||
errorContainer: 4294957782,
|
||||
onErrorContainer: 4282449922,
|
||||
background: 4294834175,
|
||||
onBackground: 4280097568,
|
||||
surface: 4294834175,
|
||||
onSurface: 4280097568,
|
||||
surfaceVariant: 4293386475,
|
||||
onSurfaceVariant: 4282991950,
|
||||
inverseSurface: 4281478965,
|
||||
inverseOnSurface: 4294307831,
|
||||
outline: 4286215551,
|
||||
outlineVariant: 4291478735,
|
||||
background: 4294507505,
|
||||
onBackground: 4279835927,
|
||||
surface: 4294507505,
|
||||
onSurface: 4279835927,
|
||||
surfaceVariant: 4292863191,
|
||||
onSurfaceVariant: 4282599487,
|
||||
inverseSurface: 4281217579,
|
||||
inverseOnSurface: 4293915368,
|
||||
outline: 4285757806,
|
||||
outlineVariant: 4291020988,
|
||||
shadow: 4278190080,
|
||||
scrim: 4278190080,
|
||||
surfaceDim: 4292794592,
|
||||
surfaceBright: 4294834175,
|
||||
surfaceDim: 4292402130,
|
||||
surfaceBright: 4294507505,
|
||||
surfaceContainerLowest: 4294967295,
|
||||
surfaceContainerLow: 4294505210,
|
||||
surfaceContainer: 4294110452,
|
||||
surfaceContainerHigh: 4293715694,
|
||||
surfaceContainerHighest: 4293320937,
|
||||
surfaceTint: 4284831119,
|
||||
surfaceContainerLow: 4294112747,
|
||||
surfaceContainer: 4293717989,
|
||||
surfaceContainerHigh: 4293323232,
|
||||
surfaceContainerHighest: 4292994266,
|
||||
surfaceTint: 4282411062,
|
||||
}}
|
||||
darkScheme={{
|
||||
primary: 1291804670,
|
||||
onPrimary: 4281739101,
|
||||
primaryContainer: 4283252085,
|
||||
onPrimaryContainer: 4293516799,
|
||||
inversePrimary: 4284831119,
|
||||
secondary: 4291543771,
|
||||
onSecondary: 4281544001,
|
||||
secondaryContainer: 4283057240,
|
||||
onSecondaryContainer: 4293451512,
|
||||
tertiary: 4293900488,
|
||||
onTertiary: 4283049266,
|
||||
tertiaryContainer: 4284693320,
|
||||
onTertiaryContainer: 4294957539,
|
||||
primary: 4294945779,
|
||||
onPrimary: 4284153947,
|
||||
primaryContainer: 4291690702,
|
||||
onPrimaryContainer: 4294967295,
|
||||
inversePrimary: 4289265833,
|
||||
secondary: 4294945779,
|
||||
onSecondary: 4284153947,
|
||||
secondaryContainer: 4286709890,
|
||||
onSecondaryContainer: 4294956533,
|
||||
tertiary: 4294947764,
|
||||
onTertiary: 4285005846,
|
||||
tertiaryContainer: 4292294218,
|
||||
onTertiaryContainer: 4294967295,
|
||||
error: 4294948011,
|
||||
onError: 4285071365,
|
||||
errorContainer: 4287823882,
|
||||
onErrorContainer: 4294957782,
|
||||
background: 4279505432,
|
||||
onBackground: 4293320937,
|
||||
surface: 4279505432,
|
||||
onSurface: 4293320937,
|
||||
surfaceVariant: 4282991950,
|
||||
onSurfaceVariant: 4291478735,
|
||||
inverseSurface: 4293320937,
|
||||
inverseOnSurface: 4281478965,
|
||||
outline: 4287926169,
|
||||
outlineVariant: 4282991950,
|
||||
background: 4279702038,
|
||||
onBackground: 4293713893,
|
||||
surface: 4279702038,
|
||||
onSurface: 4293713893,
|
||||
surfaceVariant: 4283319371,
|
||||
onSurfaceVariant: 4291936971,
|
||||
inverseSurface: 4293713893,
|
||||
inverseOnSurface: 4281675315,
|
||||
outline: 4288318869,
|
||||
outlineVariant: 4283319371,
|
||||
shadow: 4278190080,
|
||||
scrim: 4278190080,
|
||||
surfaceDim: 4279505432,
|
||||
surfaceBright: 4282071102,
|
||||
surfaceContainerLowest: 4279176467,
|
||||
surfaceContainerLow: 4280097568,
|
||||
surfaceContainer: 4280360740,
|
||||
surfaceContainerHigh: 4281018671,
|
||||
surfaceContainerHighest: 4281742394,
|
||||
surfaceTint: 4291804670,
|
||||
surfaceDim: 4279702038,
|
||||
surfaceBright: 4282267452,
|
||||
surfaceContainerLowest: 4279373073,
|
||||
surfaceContainerLow: 4280293918,
|
||||
surfaceContainer: 4280557090,
|
||||
surfaceContainerHigh: 4281280557,
|
||||
surfaceContainerHighest: 4282004280,
|
||||
surfaceTint: 4294030310,
|
||||
}}
|
||||
/>
|
||||
|
||||
<style>
|
||||
:global(.icon) {
|
||||
font-size: 2em;
|
||||
}
|
||||
:global(.pad-children > *) {
|
||||
margin: 2rem;
|
||||
}
|
||||
:global(#nav > *) {
|
||||
padding: 0.5em;
|
||||
}
|
||||
spacer {
|
||||
margin: 1em;
|
||||
}
|
||||
:global(body, html, #app) {
|
||||
width: 100vw;
|
||||
:global(body, html) {
|
||||
height: 100vh;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-color: rgb(var(--m3-scheme-background));
|
||||
color: rgb(var(--m3-scheme-on-background));
|
||||
}
|
||||
</style>
|
||||
|
|
234
frontend/src/Connection.svelte
Normal file
234
frontend/src/Connection.svelte
Normal file
|
@ -0,0 +1,234 @@
|
|||
<script lang="ts">
|
||||
import { initializeApp } from "firebase/app";
|
||||
import {
|
||||
Auth,
|
||||
browserLocalPersistence,
|
||||
createUserWithEmailAndPassword,
|
||||
getAuth,
|
||||
setPersistence,
|
||||
signInWithEmailAndPassword,
|
||||
} from "firebase/auth";
|
||||
import {
|
||||
Button,
|
||||
Dialog,
|
||||
Divider,
|
||||
ListItemLabel,
|
||||
RadioAnim2,
|
||||
SnackbarAnim,
|
||||
TextField,
|
||||
} from "m3-svelte";
|
||||
|
||||
import { setBareClientImplementation } from "@mercuryworkshop/bare-client-custom";
|
||||
import {
|
||||
AdriftBareClient,
|
||||
Connection,
|
||||
RTCTransport,
|
||||
SignalFirebase,
|
||||
} from "client";
|
||||
import trackerList from "tracker-list";
|
||||
import { UIState } from "./state";
|
||||
|
||||
type valueof<T> = T[keyof T];
|
||||
|
||||
export let dialogConnection: boolean;
|
||||
let tlsWarningShown = false;
|
||||
let selectedTracker = Object.keys(trackerList)[0] as keyof typeof trackerList;
|
||||
|
||||
let trackerStats: Record<string, any> = {};
|
||||
const getStats = async (tracker: valueof<typeof trackerList>) => {
|
||||
const url = new URL(`${tracker.tracker}/stats`);
|
||||
url.protocol = "https://";
|
||||
const resp = await fetch(url);
|
||||
|
||||
return await resp.json();
|
||||
};
|
||||
Object.entries(trackerList).map(async ([trackerId, tracker]) => {
|
||||
const stats = await getStats(tracker);
|
||||
trackerStats[trackerId] = stats;
|
||||
});
|
||||
|
||||
export let state: UIState;
|
||||
export let stateStr: string;
|
||||
let auth: Auth;
|
||||
let transport: RTCTransport;
|
||||
function createRTCTransport() {
|
||||
return new RTCTransport(
|
||||
async () => {
|
||||
stateStr = "Transport opened";
|
||||
console.log("[TRANSPORT] opened");
|
||||
|
||||
const connection = new Connection(transport);
|
||||
await connection.initialize();
|
||||
const bare = new AdriftBareClient(connection);
|
||||
setBareClientImplementation(bare);
|
||||
state = UIState.Connected;
|
||||
},
|
||||
() => console.warn("[TRANSPORT] closed"),
|
||||
() => {
|
||||
stateStr = `Connection ${transport.peer.connectionState}...`;
|
||||
},
|
||||
() => {
|
||||
stateStr = `Signaling ${transport.peer.connectionState}...`;
|
||||
},
|
||||
() => {
|
||||
if (transport.peer.connectionState == "new") {
|
||||
stateStr = `Creating an offer...`;
|
||||
} else {
|
||||
stateStr = `Gathering ${transport.peer.connectionState}...`;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
function connectToApp(tracker: valueof<typeof trackerList>) {
|
||||
initializeApp(tracker.firebase);
|
||||
auth = getAuth();
|
||||
}
|
||||
async function connectSwarm() {
|
||||
connectToApp(trackerList[selectedTracker]);
|
||||
state = UIState.Connecting;
|
||||
|
||||
transport = createRTCTransport();
|
||||
const offer = await transport.createOffer();
|
||||
stateStr = "Finding a node...";
|
||||
|
||||
try {
|
||||
const answer = await SignalFirebase.signalSwarm(JSON.stringify(offer));
|
||||
stateStr = "Linking to the node...";
|
||||
|
||||
transport.answer(answer.answer, answer.candidates);
|
||||
} catch (e) {
|
||||
console.error("While connecting to swarm", e);
|
||||
stateStr = e;
|
||||
}
|
||||
}
|
||||
|
||||
let dialogAccount = false;
|
||||
let email = "";
|
||||
let password = "";
|
||||
let snackbar: (data: any) => void;
|
||||
async function connectNode() {
|
||||
state = UIState.Connecting;
|
||||
|
||||
transport = createRTCTransport();
|
||||
const offer = await transport.createOffer();
|
||||
stateStr = "Finding your node...";
|
||||
|
||||
let answer = await SignalFirebase.signalAccount(JSON.stringify(offer));
|
||||
stateStr = "Linking to the node...";
|
||||
transport.answer(answer.answer, answer.candidates);
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog bind:open={dialogConnection} headline="Connect to a tracker">
|
||||
<div class="flex flex-col -mx-4">
|
||||
{#each Object.entries(trackerList) as [trackerId, tracker], i}
|
||||
{#if i != 0}
|
||||
<Divider />
|
||||
{/if}
|
||||
<ListItemLabel
|
||||
headline={trackerId}
|
||||
supporting={trackerStats[trackerId]
|
||||
? `${tracker.description} - ${
|
||||
trackerStats[trackerId].members.length
|
||||
} ${trackerStats[trackerId].members.length == 1 ? "node" : "nodes"}`
|
||||
: tracker.description}
|
||||
>
|
||||
<RadioAnim2 slot="leading">
|
||||
<input
|
||||
type="radio"
|
||||
name="tracker"
|
||||
bind:group={selectedTracker}
|
||||
value={trackerId}
|
||||
/>
|
||||
</RadioAnim2>
|
||||
</ListItemLabel>
|
||||
{/each}
|
||||
</div>
|
||||
<p class="font-bold mt-4" class:hide-warning={!tlsWarningShown}>
|
||||
Your data is not end-to-end encrypted, and will not be private. While TLS
|
||||
will be implemented later, for now do not enter any private information.
|
||||
Click connect again to continue.
|
||||
</p>
|
||||
<svelte:fragment slot="buttons">
|
||||
<Button type="text" on:click={() => (dialogConnection = false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
type="text"
|
||||
on:click={() => {
|
||||
connectToApp(trackerList[selectedTracker]);
|
||||
setPersistence(auth, browserLocalPersistence);
|
||||
console.log(browserLocalPersistence, auth.currentUser);
|
||||
|
||||
if (auth.currentUser) {
|
||||
connectNode();
|
||||
} else {
|
||||
dialogConnection = false;
|
||||
dialogAccount = true;
|
||||
}
|
||||
}}
|
||||
>
|
||||
Connect to your node
|
||||
</Button>
|
||||
<Button
|
||||
type="tonal"
|
||||
on:click={() => {
|
||||
if (tlsWarningShown) {
|
||||
connectSwarm();
|
||||
dialogConnection = false;
|
||||
}
|
||||
tlsWarningShown = true;
|
||||
}}
|
||||
>
|
||||
Connect
|
||||
</Button>
|
||||
</svelte:fragment>
|
||||
</Dialog>
|
||||
<Dialog bind:open={dialogAccount} headline="Sign in">
|
||||
<div class="flex gap-4 flex-col">
|
||||
<TextField name="Email" bind:value={email} />
|
||||
<TextField
|
||||
name="Password"
|
||||
bind:value={password}
|
||||
extraOptions={{ type: "password" }}
|
||||
/>
|
||||
</div>
|
||||
<svelte:fragment slot="buttons">
|
||||
<Button type="text" on:click={() => (dialogAccount = false)}>Cancel</Button>
|
||||
<Button
|
||||
type="text"
|
||||
on:click={async () => {
|
||||
try {
|
||||
await createUserWithEmailAndPassword(auth, email, password);
|
||||
await connectNode();
|
||||
} catch (e) {
|
||||
snackbar({ message: e.message, closable: true });
|
||||
}
|
||||
}}
|
||||
>
|
||||
Sign up
|
||||
</Button>
|
||||
<Button
|
||||
type="text"
|
||||
on:click={async () => {
|
||||
try {
|
||||
await signInWithEmailAndPassword(auth, email, password);
|
||||
await connectNode();
|
||||
} catch (e) {
|
||||
snackbar({ message: e.message, closable: true });
|
||||
}
|
||||
}}
|
||||
>
|
||||
Log in
|
||||
</Button>
|
||||
</svelte:fragment>
|
||||
</Dialog>
|
||||
<SnackbarAnim bind:show={snackbar} />
|
||||
|
||||
<style>
|
||||
.hide-warning {
|
||||
margin: 0;
|
||||
height: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
</style>
|
|
@ -3,9 +3,6 @@
|
|||
import { Win, openWindow } from "../../corium";
|
||||
import Icon from "@iconify/svelte";
|
||||
|
||||
let selectedProxy = "ultraviolet";
|
||||
|
||||
let url: string = "http://google.com";
|
||||
import { onMount } from "svelte";
|
||||
import {
|
||||
Dialog,
|
||||
|
@ -14,10 +11,14 @@
|
|||
TextField,
|
||||
} from "m3-svelte";
|
||||
|
||||
let url = "http://google.com";
|
||||
|
||||
let proxyIframe: HTMLIFrameElement;
|
||||
|
||||
let settingsenabled: boolean = false;
|
||||
|
||||
let selectedProxy = "ultraviolet";
|
||||
|
||||
let searchengine = "https://google.com/search?q=";
|
||||
|
||||
function frameLoad() {
|
||||
|
@ -59,35 +60,35 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<div class="h-full w-full flex flex-col">
|
||||
<div class="h-full flex flex-col">
|
||||
<div class="flex p-2">
|
||||
<div class="flex text-xl items-center w-full">
|
||||
<button
|
||||
class="text-2xl p-2 hover:text-primary"
|
||||
on:click={() => {
|
||||
proxyIframe.contentWindow?.history.back();
|
||||
}}
|
||||
>
|
||||
<Icon icon="fluent-mdl2:back" />
|
||||
<Icon icon="ic:round-arrow-back" />
|
||||
</button>
|
||||
<div class="p-2" />
|
||||
<button
|
||||
class="text-2xl p-2 hover:text-primary"
|
||||
on:click={() => {
|
||||
proxyIframe.contentWindow?.history.forward();
|
||||
}}
|
||||
>
|
||||
<Icon icon="fluent-mdl2:forward" />
|
||||
<Icon icon="ic:round-arrow-forward" />
|
||||
</button>
|
||||
<button
|
||||
class="text-2xl px-4"
|
||||
class="text-2xl p-2 hover:text-primary"
|
||||
on:click={() => {
|
||||
visitURL(url);
|
||||
}}
|
||||
>
|
||||
<Icon icon="tabler:reload" />
|
||||
<Icon icon="ic:round-refresh" />
|
||||
</button>
|
||||
<div class="urlbar flex items-center flex-1">
|
||||
<div class="flex flex-1 mx-2 border border-outline rounded-xl">
|
||||
<button
|
||||
class="text-2xl px-2"
|
||||
class="text-2xl px-2 hover:text-primary"
|
||||
on:click={() => {
|
||||
visitURL(url);
|
||||
}}
|
||||
|
@ -97,7 +98,7 @@
|
|||
<input
|
||||
bind:value={url}
|
||||
type="text"
|
||||
class="flex-1"
|
||||
class="flex-1 w-0 pr-2 text-xl"
|
||||
on:keydown={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
visitURL(url);
|
||||
|
@ -105,11 +106,15 @@
|
|||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button class="text-2xl pl-3" on:click={() => (settingsenabled = true)}>
|
||||
<button
|
||||
class="text-2xl p-2 hover:text-primary"
|
||||
on:click={() => (settingsenabled = true)}
|
||||
>
|
||||
<Icon icon="ic:round-settings" />
|
||||
</button>
|
||||
</div>
|
||||
<iframe class="flex-1" bind:this={proxyIframe} on:load={frameLoad} />
|
||||
</div>
|
||||
<Dialog bind:open={settingsenabled} headline="Proxy Settings">
|
||||
{#if !import.meta.env.VITE_ADRIFT_SINGLEFILE}
|
||||
<div>
|
||||
|
@ -121,9 +126,9 @@
|
|||
value="ultraviolet"
|
||||
id="ultraviolet"
|
||||
/>
|
||||
<SegmentedButtonItem input="ultraviolet"
|
||||
>Ultraviolet</SegmentedButtonItem
|
||||
>
|
||||
<SegmentedButtonItem input="ultraviolet">
|
||||
Ultraviolet
|
||||
</SegmentedButtonItem>
|
||||
<input
|
||||
type="radio"
|
||||
name="selectedProxy"
|
||||
|
@ -139,16 +144,8 @@
|
|||
<TextField name="Default Search Engine" bind:value={searchengine} />
|
||||
{/if}
|
||||
</Dialog>
|
||||
</div>
|
||||
<iframe class="flex-1" bind:this={proxyIframe} on:load={frameLoad} />
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.urlbar {
|
||||
border: solid 0.0625rem rgb(var(--m3-scheme-outline));
|
||||
padding: 0.25rem;
|
||||
border-radius: 0.75rem;
|
||||
}
|
||||
input {
|
||||
background-color: transparent;
|
||||
outline: none;
|
||||
|
|
|
@ -1,6 +1,18 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
*{
|
||||
font-family: "Cabin";
|
||||
html {
|
||||
background-color: rgb(var(--m3-scheme-background));
|
||||
color: rgb(var(--m3-scheme-on-background));
|
||||
--m3-font-display: Cabin, system-ui, sans-serif;
|
||||
--m3-font-headline: Cabin, system-ui, sans-serif;
|
||||
--m3-font-title: Cabin, system-ui, sans-serif;
|
||||
--m3-font-label: Cabin, system-ui, sans-serif;
|
||||
--m3-font-label-large-tracking: 0.25px;
|
||||
--m3-font-label-medium-tracking: 1px;
|
||||
--m3-font-label-small-tracking: 1px;
|
||||
--m3-font-body: Cabin, system-ui, sans-serif;
|
||||
}
|
||||
#app {
|
||||
display: contents;
|
||||
}
|
5
frontend/src/state.ts
Normal file
5
frontend/src/state.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export enum UIState {
|
||||
Idle,
|
||||
Connecting,
|
||||
Connected,
|
||||
}
|
|
@ -1,11 +1,68 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{js,ts,jsx,tsx,svelte,html}",
|
||||
],
|
||||
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx,svelte,html}"],
|
||||
theme: {
|
||||
extend: {},
|
||||
extend: {
|
||||
colors: {
|
||||
primary: "rgb(var(--m3-scheme-primary) / <alpha-value>)",
|
||||
"on-primary": "rgb(var(--m3-scheme-on-primary) / <alpha-value>)",
|
||||
"primary-container":
|
||||
"rgb(var(--m3-scheme-primary-container) / <alpha-value>)",
|
||||
"on-primary-container":
|
||||
"rgb(var(--m3-scheme-on-primary-container) / <alpha-value>)",
|
||||
secondary: "rgb(var(--m3-scheme-secondary) / <alpha-value>)",
|
||||
"on-secondary": "rgb(var(--m3-scheme-on-secondary) / <alpha-value>)",
|
||||
"secondary-container":
|
||||
"rgb(var(--m3-scheme-secondary-container) / <alpha-value>)",
|
||||
"on-secondary-container":
|
||||
"rgb(var(--m3-scheme-on-secondary-container) / <alpha-value>)",
|
||||
tertiary: "rgb(var(--m3-scheme-tertiary) / <alpha-value>)",
|
||||
"on-tertiary": "rgb(var(--m3-scheme-on-tertiary) / <alpha-value>)",
|
||||
"tertiary-container":
|
||||
"rgb(var(--m3-scheme-tertiary-container) / <alpha-value>)",
|
||||
"on-tertiary-container":
|
||||
"rgb(var(--m3-scheme-on-tertiary-container) / <alpha-value>)",
|
||||
error: "rgb(var(--m3-scheme-error) / <alpha-value>)",
|
||||
"on-error": "rgb(var(--m3-scheme-on-error) / <alpha-value>)",
|
||||
"error-container":
|
||||
"rgb(var(--m3-scheme-error-container) / <alpha-value>)",
|
||||
"on-error-container":
|
||||
"rgb(var(--m3-scheme-on-error-container) / <alpha-value>)",
|
||||
background: "rgb(var(--m3-scheme-background) / <alpha-value>)",
|
||||
"on-background": "rgb(var(--m3-scheme-on-background) / <alpha-value>)",
|
||||
surface: "rgb(var(--m3-scheme-surface) / <alpha-value>)",
|
||||
"on-surface": "rgb(var(--m3-scheme-on-surface) / <alpha-value>)",
|
||||
"surface-variant":
|
||||
"rgb(var(--m3-scheme-surface-variant) / <alpha-value>)",
|
||||
"on-surface-variant":
|
||||
"rgb(var(--m3-scheme-on-surface-variant) / <alpha-value>)",
|
||||
outline: "rgb(var(--m3-scheme-outline) / <alpha-value>)",
|
||||
"outline-variant":
|
||||
"rgb(var(--m3-scheme-outline-variant) / <alpha-value>)",
|
||||
shadow: "rgb(var(--m3-scheme-shadow) / <alpha-value>)",
|
||||
scrim: "rgb(var(--m3-scheme-scrim) / <alpha-value>)",
|
||||
"inverse-surface":
|
||||
"rgb(var(--m3-scheme-inverse-surface) / <alpha-value>)",
|
||||
"inverse-on-surface":
|
||||
"rgb(var(--m3-scheme-inverse-on-surface) / <alpha-value>)",
|
||||
"inverse-primary":
|
||||
"rgb(var(--m3-scheme-inverse-primary) / <alpha-value>)",
|
||||
"surface-bright":
|
||||
"rgb(var(--m3-scheme-surface-bright) / <alpha-value>)",
|
||||
"surface-container":
|
||||
"rgb(var(--m3-scheme-surface-container) / <alpha-value>)",
|
||||
"surface-container-high":
|
||||
"rgb(var(--m3-scheme-surface-container-high) / <alpha-value>)",
|
||||
"surface-container-highest":
|
||||
"rgb(var(--m3-scheme-surface-container-highest) / <alpha-value>)",
|
||||
"surface-container-low":
|
||||
"rgb(var(--m3-scheme-surface-container-low) / <alpha-value>)",
|
||||
"surface-container-lowest":
|
||||
"rgb(var(--m3-scheme-surface-container-lowest) / <alpha-value>)",
|
||||
"surface-dim": "rgb(var(--m3-scheme-surface-dim) / <alpha-value>)",
|
||||
"surface-tint": "rgb(var(--m3-scheme-surface-tint) / <alpha-value>)",
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue