mirror of
https://github.com/CharaChorder/DeviceManager.git
synced 2026-01-23 10:22:41 +00:00
73
src/lib/chat/MatrixRooms.svelte
Normal file
73
src/lib/chat/MatrixRooms.svelte
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { Room } from "matrix-js-sdk";
|
||||||
|
import { matrixClient, currentRoomId } from "./chat";
|
||||||
|
|
||||||
|
let { rooms }: { rooms: Room[] } = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="rooms">
|
||||||
|
{#each $matrixClient.getRooms() as room}
|
||||||
|
{@const avatar = room.getMxcAvatarUrl()}
|
||||||
|
<button
|
||||||
|
class:active={$currentRoomId === room.roomId}
|
||||||
|
class="room"
|
||||||
|
onclick={() => ($currentRoomId = room.roomId)}
|
||||||
|
>
|
||||||
|
{#if avatar}
|
||||||
|
<img
|
||||||
|
alt={room.name}
|
||||||
|
src={$matrixClient.mxcUrlToHttp(avatar, 16, 16)}
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
/>
|
||||||
|
{:else}
|
||||||
|
<div>#</div>
|
||||||
|
{/if}
|
||||||
|
<div>{room.name}</div>
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
|
||||||
|
{#await $matrixClient.publicRooms()}
|
||||||
|
<div>Loading...</div>
|
||||||
|
{:then rooms}
|
||||||
|
{#each rooms.chunk as room}
|
||||||
|
<button class="room" onclick={() => ($currentRoomId = room.roomId)}>
|
||||||
|
<div>#</div>
|
||||||
|
<div>{room.name}</div>
|
||||||
|
</button>
|
||||||
|
{/each}
|
||||||
|
{:catch error}
|
||||||
|
<div>{error.message}</div>
|
||||||
|
{/await}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.rooms {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 8px;
|
||||||
|
padding-left: 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.room {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
gap: 0.5rem;
|
||||||
|
cursor: pointer;
|
||||||
|
padding-block: 2px;
|
||||||
|
min-height: 0;
|
||||||
|
height: unset;
|
||||||
|
padding-inline: 16px;
|
||||||
|
padding-block: 4px;
|
||||||
|
border-radius: 8px;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: var(--md-sys-color-primary-container);
|
||||||
|
color: var(--md-sys-color-on-primary-container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
109
src/lib/chat/chat-rx.ts
Normal file
109
src/lib/chat/chat-rx.ts
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
import { derived, writable, type Writable } from "svelte/store";
|
||||||
|
import type {
|
||||||
|
ClientEvent,
|
||||||
|
LoginResponse,
|
||||||
|
MatrixClient,
|
||||||
|
RoomMember,
|
||||||
|
} from "matrix-js-sdk";
|
||||||
|
import { persistentWritable } from "$lib/storage";
|
||||||
|
import {
|
||||||
|
themeFromSourceColor,
|
||||||
|
argbFromHex,
|
||||||
|
type CustomColorGroup,
|
||||||
|
} from "@material/material-color-utilities";
|
||||||
|
import type { UserTheme } from "$lib/preferences";
|
||||||
|
import { MatrixRx } from "./matrix-rx/client";
|
||||||
|
|
||||||
|
export const matrixClient: Writable<MatrixClient> = writable();
|
||||||
|
|
||||||
|
export const isLoggedIn: Writable<boolean> = writable(false);
|
||||||
|
|
||||||
|
export const matrix = derived(
|
||||||
|
[matrixClient, isLoggedIn],
|
||||||
|
([matrixClient, isLoggedIn]) =>
|
||||||
|
isLoggedIn ? new MatrixRx(matrixClient) : undefined,
|
||||||
|
);
|
||||||
|
|
||||||
|
export const currentRoomId = persistentWritable<string | null>(
|
||||||
|
"currentRoomId",
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
function getStoredLogin(): LoginResponse | undefined {
|
||||||
|
try {
|
||||||
|
return JSON.parse(localStorage.getItem("matrix-login")!);
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function storeLogin(response: LoginResponse) {
|
||||||
|
localStorage.setItem("matrix-login", JSON.stringify(response));
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function initMatrixClient() {
|
||||||
|
const { createClient, IndexedDBStore, IndexedDBCryptoStore } = await import(
|
||||||
|
"matrix-js-sdk"
|
||||||
|
);
|
||||||
|
|
||||||
|
const storedLogin = getStoredLogin();
|
||||||
|
|
||||||
|
const store = new IndexedDBStore({
|
||||||
|
dbName: "matrix",
|
||||||
|
indexedDB: window.indexedDB,
|
||||||
|
});
|
||||||
|
const cryptoStore = new IndexedDBCryptoStore(
|
||||||
|
window.indexedDB,
|
||||||
|
"matrix-crypto",
|
||||||
|
);
|
||||||
|
|
||||||
|
const client = createClient({
|
||||||
|
baseUrl: import.meta.env.VITE_MATRIX_URL,
|
||||||
|
userId: storedLogin?.user_id,
|
||||||
|
accessToken: storedLogin?.access_token,
|
||||||
|
timelineSupport: true,
|
||||||
|
store,
|
||||||
|
cryptoStore,
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("store");
|
||||||
|
await store.startup();
|
||||||
|
console.log("cryptoStore");
|
||||||
|
await cryptoStore.startup();
|
||||||
|
console.log("client");
|
||||||
|
await client.startClient();
|
||||||
|
client.once("sync" as ClientEvent.Sync, () => {
|
||||||
|
isLoggedIn.set(client.isLoggedIn());
|
||||||
|
});
|
||||||
|
|
||||||
|
const loginToken = new URLSearchParams(window.location.search).get(
|
||||||
|
"loginToken",
|
||||||
|
);
|
||||||
|
if (loginToken) {
|
||||||
|
storeLogin(await client.loginWithToken(loginToken));
|
||||||
|
window.history.replaceState({}, document.title, window.location.pathname);
|
||||||
|
isLoggedIn.set(client.isLoggedIn());
|
||||||
|
}
|
||||||
|
|
||||||
|
matrixClient.set(client);
|
||||||
|
console.log("done");
|
||||||
|
}
|
||||||
|
|
||||||
|
export function memberColor(
|
||||||
|
member: RoomMember,
|
||||||
|
theme: UserTheme,
|
||||||
|
): CustomColorGroup {
|
||||||
|
let hash = 0;
|
||||||
|
member.userId.split("").forEach((char) => {
|
||||||
|
hash = char.charCodeAt(0) + ((hash << 5) - hash);
|
||||||
|
});
|
||||||
|
let color = "#";
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
const value = (hash >> (i * 8)) & 0xff;
|
||||||
|
color += value.toString(16).padStart(2, "0");
|
||||||
|
}
|
||||||
|
|
||||||
|
return themeFromSourceColor(argbFromHex(theme.color), [
|
||||||
|
{ value: argbFromHex(color), name: "member", blend: true },
|
||||||
|
]).customColors.find((c) => c.color.name === "member")!;
|
||||||
|
}
|
||||||
@@ -1,10 +1,5 @@
|
|||||||
import { derived, writable, type Writable } from "svelte/store";
|
import { writable, type Writable } from "svelte/store";
|
||||||
import type {
|
import type { MatrixClient, RoomMember } from "matrix-js-sdk";
|
||||||
ClientEvent,
|
|
||||||
LoginResponse,
|
|
||||||
MatrixClient,
|
|
||||||
RoomMember,
|
|
||||||
} from "matrix-js-sdk";
|
|
||||||
import { persistentWritable } from "$lib/storage";
|
import { persistentWritable } from "$lib/storage";
|
||||||
import {
|
import {
|
||||||
themeFromSourceColor,
|
themeFromSourceColor,
|
||||||
@@ -12,83 +7,14 @@ import {
|
|||||||
type CustomColorGroup,
|
type CustomColorGroup,
|
||||||
} from "@material/material-color-utilities";
|
} from "@material/material-color-utilities";
|
||||||
import type { UserTheme } from "$lib/preferences";
|
import type { UserTheme } from "$lib/preferences";
|
||||||
import { MatrixRx } from "./matrix-rx/client";
|
|
||||||
|
|
||||||
export const matrixClient: Writable<MatrixClient> = writable();
|
export const matrixClient: Writable<MatrixClient> = writable();
|
||||||
|
|
||||||
export const isLoggedIn: Writable<boolean> = writable(false);
|
|
||||||
|
|
||||||
export const matrix = derived(
|
|
||||||
[matrixClient, isLoggedIn],
|
|
||||||
([matrixClient, isLoggedIn]) =>
|
|
||||||
isLoggedIn ? new MatrixRx(matrixClient) : undefined,
|
|
||||||
);
|
|
||||||
|
|
||||||
export const currentRoomId = persistentWritable<string | null>(
|
export const currentRoomId = persistentWritable<string | null>(
|
||||||
"currentRoomId",
|
"currentRoomId",
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
|
|
||||||
function getStoredLogin(): LoginResponse | undefined {
|
|
||||||
try {
|
|
||||||
return JSON.parse(localStorage.getItem("matrix-login")!);
|
|
||||||
} catch {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function storeLogin(response: LoginResponse) {
|
|
||||||
localStorage.setItem("matrix-login", JSON.stringify(response));
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function initMatrixClient() {
|
|
||||||
const { createClient, IndexedDBStore, IndexedDBCryptoStore } = await import(
|
|
||||||
"matrix-js-sdk"
|
|
||||||
);
|
|
||||||
|
|
||||||
const storedLogin = getStoredLogin();
|
|
||||||
|
|
||||||
const store = new IndexedDBStore({
|
|
||||||
dbName: "matrix",
|
|
||||||
indexedDB: window.indexedDB,
|
|
||||||
});
|
|
||||||
const cryptoStore = new IndexedDBCryptoStore(
|
|
||||||
window.indexedDB,
|
|
||||||
"matrix-crypto",
|
|
||||||
);
|
|
||||||
|
|
||||||
const client = createClient({
|
|
||||||
baseUrl: import.meta.env.VITE_MATRIX_URL,
|
|
||||||
userId: storedLogin?.user_id,
|
|
||||||
accessToken: storedLogin?.access_token,
|
|
||||||
timelineSupport: true,
|
|
||||||
store,
|
|
||||||
cryptoStore,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("store");
|
|
||||||
await store.startup();
|
|
||||||
console.log("cryptoStore");
|
|
||||||
await cryptoStore.startup();
|
|
||||||
console.log("client");
|
|
||||||
await client.startClient();
|
|
||||||
client.once("sync" as ClientEvent.Sync, () => {
|
|
||||||
isLoggedIn.set(client.isLoggedIn());
|
|
||||||
});
|
|
||||||
|
|
||||||
const loginToken = new URLSearchParams(window.location.search).get(
|
|
||||||
"loginToken",
|
|
||||||
);
|
|
||||||
if (loginToken) {
|
|
||||||
storeLogin(await client.loginWithToken(loginToken));
|
|
||||||
window.history.replaceState({}, document.title, window.location.pathname);
|
|
||||||
isLoggedIn.set(client.isLoggedIn());
|
|
||||||
}
|
|
||||||
|
|
||||||
matrixClient.set(client);
|
|
||||||
console.log("done");
|
|
||||||
}
|
|
||||||
|
|
||||||
export function memberColor(
|
export function memberColor(
|
||||||
member: RoomMember,
|
member: RoomMember,
|
||||||
theme: UserTheme,
|
theme: UserTheme,
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
external: true,
|
external: true,
|
||||||
},
|
},
|
||||||
{ href: "/editor", icon: "edit_document", title: "Editor", wip: true },
|
{ href: "/editor", icon: "edit_document", title: "Editor", wip: true },
|
||||||
{ href: "https://chat.dev.charachorder.io", icon: "chat", title: "Chat", wip: true },
|
{ href: "/chat", icon: "chat", title: "Chat", wip: true },
|
||||||
],
|
],
|
||||||
/*[
|
/*[
|
||||||
{ href: "/plugin", icon: "code", title: "Plugin", wip: true },
|
{ href: "/plugin", icon: "code", title: "Plugin", wip: true },
|
||||||
|
|||||||
92
src/routes/(app)/chat-rx/+page.svelte
Normal file
92
src/routes/(app)/chat-rx/+page.svelte
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { initMatrixClient, isLoggedIn, matrix } from "$lib/chat/chat";
|
||||||
|
import { flip } from "svelte/animate";
|
||||||
|
import { slide } from "svelte/transition";
|
||||||
|
import Login from "./Login.svelte";
|
||||||
|
import { onMount } from "svelte";
|
||||||
|
import { browser } from "$app/environment";
|
||||||
|
|
||||||
|
onMount(async () => {
|
||||||
|
if (browser) {
|
||||||
|
await initMatrixClient();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let { children } = $props();
|
||||||
|
|
||||||
|
let spaces = $derived($matrix?.topLevelSpaces$);
|
||||||
|
|
||||||
|
function spaceShort(name: string) {
|
||||||
|
return name
|
||||||
|
.split(" ")
|
||||||
|
.map((it) => it[0])
|
||||||
|
.join("");
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if $isLoggedIn}
|
||||||
|
<div class="layout">
|
||||||
|
<nav class="spaces">
|
||||||
|
<a href="/chat/chats" class="icon chats">chat</a>
|
||||||
|
<hr />
|
||||||
|
{#if $spaces}
|
||||||
|
<ul>
|
||||||
|
{#each $spaces as space (space.roomId)}
|
||||||
|
<li animate:flip transition:slide>
|
||||||
|
<a class="space" href="/chat/space/{space.roomId}">
|
||||||
|
{spaceShort(space.name)}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{/each}
|
||||||
|
</ul>
|
||||||
|
{/if}
|
||||||
|
<button class="icon">add</button>
|
||||||
|
</nav>
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<Login />
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
nav {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.layout {
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
width: 60%;
|
||||||
|
height: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
button,
|
||||||
|
a {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 56px;
|
||||||
|
height: 56px;
|
||||||
|
background: var(--md-sys-color-surface-variant);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chats {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.space {
|
||||||
|
font-size: 20px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,92 +1,186 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { initMatrixClient, isLoggedIn, matrix } from "$lib/chat/chat";
|
|
||||||
import { flip } from "svelte/animate";
|
|
||||||
import { slide } from "svelte/transition";
|
|
||||||
import Login from "./Login.svelte";
|
|
||||||
import { onMount } from "svelte";
|
|
||||||
import { browser } from "$app/environment";
|
import { browser } from "$app/environment";
|
||||||
|
import { onDestroy, onMount, setContext } from "svelte";
|
||||||
|
import type {
|
||||||
|
IndexedDBStore,
|
||||||
|
IndexedDBCryptoStore,
|
||||||
|
LoginResponse,
|
||||||
|
} from "matrix-js-sdk";
|
||||||
|
import MatrixTimeline from "$lib/chat/MatrixTimeline.svelte";
|
||||||
|
import { matrixClient, currentRoomId } from "$lib/chat/chat";
|
||||||
|
import MatrixRooms from "$lib/chat/MatrixRooms.svelte";
|
||||||
|
import MatrixRoomMembers from "$lib/chat/MatrixRoomMembers.svelte";
|
||||||
|
|
||||||
|
let loggedIn = $state(false);
|
||||||
|
let ready = $state(false);
|
||||||
|
|
||||||
|
let store: IndexedDBStore;
|
||||||
|
let cryptoStore: IndexedDBCryptoStore;
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
if (browser) {
|
if (!browser) return;
|
||||||
await initMatrixClient();
|
const { createClient, IndexedDBStore, IndexedDBCryptoStore } = await import(
|
||||||
|
"matrix-js-sdk"
|
||||||
|
);
|
||||||
|
|
||||||
|
const storedLogin = getStoredLogin();
|
||||||
|
|
||||||
|
store = new IndexedDBStore({
|
||||||
|
dbName: "matrix",
|
||||||
|
indexedDB: window.indexedDB,
|
||||||
|
});
|
||||||
|
cryptoStore = new IndexedDBCryptoStore(window.indexedDB, "matrix-crypto");
|
||||||
|
|
||||||
|
$matrixClient = createClient({
|
||||||
|
baseUrl: import.meta.env.VITE_MATRIX_URL,
|
||||||
|
userId: storedLogin?.user_id,
|
||||||
|
accessToken: storedLogin?.access_token,
|
||||||
|
timelineSupport: true,
|
||||||
|
store,
|
||||||
|
cryptoStore,
|
||||||
|
});
|
||||||
|
|
||||||
|
const loginToken = new URLSearchParams(window.location.search).get(
|
||||||
|
"loginToken",
|
||||||
|
);
|
||||||
|
if (loginToken) {
|
||||||
|
await handleLogin(await $matrixClient.loginWithToken(loginToken));
|
||||||
|
window.history.replaceState({}, document.title, window.location.pathname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await postLogin();
|
||||||
});
|
});
|
||||||
|
|
||||||
let { children } = $props();
|
async function passwordLogin(event: SubmitEvent) {
|
||||||
|
event.preventDefault();
|
||||||
|
const form = event.target as HTMLFormElement;
|
||||||
|
const username = (form.elements.namedItem("username") as HTMLInputElement)
|
||||||
|
.value;
|
||||||
|
const password = (form.elements.namedItem("password") as HTMLInputElement)
|
||||||
|
.value;
|
||||||
|
|
||||||
let spaces = $derived($matrix?.topLevelSpaces$);
|
await handleLogin(
|
||||||
|
await $matrixClient.loginWithPassword(username, password),
|
||||||
function spaceShort(name: string) {
|
);
|
||||||
return name
|
await postLogin();
|
||||||
.split(" ")
|
|
||||||
.map((it) => it[0])
|
|
||||||
.join("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function handleLogin(response: LoginResponse) {
|
||||||
|
localStorage.setItem("matrix-login", JSON.stringify(response));
|
||||||
|
}
|
||||||
|
|
||||||
|
async function postLogin() {
|
||||||
|
loggedIn = $matrixClient.isLoggedIn();
|
||||||
|
|
||||||
|
if (loggedIn) {
|
||||||
|
await store.startup();
|
||||||
|
await cryptoStore.startup();
|
||||||
|
await $matrixClient.startClient();
|
||||||
|
$matrixClient.once("sync", function (state, prevState, res) {
|
||||||
|
ready = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStoredLogin(): LoginResponse | undefined {
|
||||||
|
try {
|
||||||
|
return JSON.parse(localStorage.getItem("matrix-login")!);
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
if ($matrixClient) {
|
||||||
|
$matrixClient.stopClient();
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $isLoggedIn}
|
{#if $matrixClient && loggedIn}
|
||||||
<div class="layout">
|
{#if ready}
|
||||||
<nav class="spaces">
|
<div class="chat">
|
||||||
<a href="/chat/chats" class="icon chats">chat</a>
|
<div class="rooms">
|
||||||
<hr />
|
<button
|
||||||
{#if $spaces}
|
onclick={() => {
|
||||||
<ul>
|
$matrixClient.logout(true);
|
||||||
{#each $spaces as space (space.roomId)}
|
$matrixClient.clearStores();
|
||||||
<li animate:flip transition:slide>
|
localStorage.removeItem("matrix-login");
|
||||||
<a class="space" href="/chat/space/{space.roomId}">
|
window.location.reload();
|
||||||
{spaceShort(space.name)}
|
}}>logout</button
|
||||||
</a>
|
>
|
||||||
</li>
|
<MatrixRooms rooms={$matrixClient.getRooms()} />
|
||||||
{/each}
|
</div>
|
||||||
</ul>
|
{#if $currentRoomId}
|
||||||
|
{@const room = $matrixClient.getRoom($currentRoomId)}
|
||||||
|
{#key room}
|
||||||
|
{#if room}
|
||||||
|
<div class="timeline">
|
||||||
|
<MatrixTimeline timeline={room.getLiveTimeline()} />
|
||||||
|
</div>
|
||||||
|
<div class="members">
|
||||||
|
<MatrixRoomMembers members={room.getJoinedMembers()} />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/key}
|
||||||
{/if}
|
{/if}
|
||||||
<button class="icon">add</button>
|
</div>
|
||||||
</nav>
|
{/if}
|
||||||
</div>
|
{:else if $matrixClient}
|
||||||
{:else}
|
{#await $matrixClient.loginFlows() then flows}
|
||||||
<Login />
|
{#each flows.flows as flow}
|
||||||
|
{#if flow.type === "m.login.sso"}
|
||||||
|
<a
|
||||||
|
href={$matrixClient.getSsoLoginUrl(`${window.location.origin}/chat/`)}
|
||||||
|
>
|
||||||
|
{#each flow.identity_providers as idp}
|
||||||
|
{#if idp.icon}
|
||||||
|
<img src={$matrixClient.mxcUrlToHttp(idp.icon)} alt={idp.name} />
|
||||||
|
{:else}
|
||||||
|
{idp.name}
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
</a>
|
||||||
|
{:else if flow.type === "m.login.password"}
|
||||||
|
<!-- TODO: unambigous sso
|
||||||
|
<form onsubmit={passwordLogin}>
|
||||||
|
<input name="username" type="text" placeholder="Username" />
|
||||||
|
<input name="password" type="password" placeholder="Password" />
|
||||||
|
<button type="submit">Login</button>
|
||||||
|
</form>
|
||||||
|
-->
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
{/await}
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
nav {
|
.chat {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
> *:not(:last-child) {
|
||||||
|
border-right: 1px solid var(--md-sys-color-outline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.room {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.layout {
|
.timeline {
|
||||||
display: flex;
|
flex-grow: 1;
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hr {
|
.rooms {
|
||||||
width: 60%;
|
flex-shrink: 0;
|
||||||
height: 1px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ul {
|
.members {
|
||||||
list-style: none;
|
width: 200px;
|
||||||
padding: 0;
|
flex-shrink: 0;
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
button,
|
|
||||||
a {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
overflow: hidden;
|
|
||||||
width: 56px;
|
|
||||||
height: 56px;
|
|
||||||
background: var(--md-sys-color-surface-variant);
|
|
||||||
}
|
|
||||||
|
|
||||||
.chats {
|
|
||||||
font-size: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.space {
|
|
||||||
font-size: 20px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
Reference in New Issue
Block a user