allow guest on home and shared convo (#1960)
Browse files* allow guest on home and shared convo
* lint
* more interactions
* add also to mobile nav menu
- src/hooks.server.ts +31 -10
- src/lib/components/MobileNav.svelte +10 -1
- src/lib/components/NavConversationItem.svelte +5 -0
- src/lib/components/NavMenu.svelte +14 -1
- src/lib/components/chat/ChatInput.svelte +8 -0
- src/lib/components/chat/ChatMessage.svelte +5 -1
- src/lib/components/chat/ChatWindow.svelte +9 -2
- src/lib/components/chat/FileDropzone.svelte +2 -1
- src/lib/utils/auth.ts +15 -0
- src/routes/+layout.svelte +8 -6
- src/routes/conversation/[id]/+page.svelte +3 -0
src/hooks.server.ts
CHANGED
|
@@ -138,16 +138,37 @@ export const handle: Handle = async ({ event, resolve }) => {
|
|
| 138 |
|
| 139 |
event.locals.sessionId = auth.sessionId;
|
| 140 |
|
| 141 |
-
if (
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
}
|
| 152 |
|
| 153 |
event.locals.user = auth.user || undefined;
|
|
|
|
| 138 |
|
| 139 |
event.locals.sessionId = auth.sessionId;
|
| 140 |
|
| 141 |
+
if (loginEnabled && !auth.user) {
|
| 142 |
+
if (config.AUTOMATIC_LOGIN === "true") {
|
| 143 |
+
// AUTOMATIC_LOGIN: always redirect to OAuth flow (unless already on login or healthcheck pages)
|
| 144 |
+
if (
|
| 145 |
+
!event.url.pathname.startsWith(`${base}/login`) &&
|
| 146 |
+
!event.url.pathname.startsWith(`${base}/healthcheck`)
|
| 147 |
+
) {
|
| 148 |
+
// To get the same CSRF token after callback
|
| 149 |
+
refreshSessionCookie(event.cookies, auth.secretSessionId);
|
| 150 |
+
return await triggerOauthFlow({
|
| 151 |
+
request: event.request,
|
| 152 |
+
url: event.url,
|
| 153 |
+
locals: event.locals,
|
| 154 |
+
});
|
| 155 |
+
}
|
| 156 |
+
} else {
|
| 157 |
+
// Redirect to OAuth flow unless on the authorized pages (home, shared conversation, login, healthcheck)
|
| 158 |
+
if (
|
| 159 |
+
event.url.pathname !== `${base}/` &&
|
| 160 |
+
event.url.pathname !== `${base}` &&
|
| 161 |
+
!event.url.pathname.startsWith(`${base}/login`) &&
|
| 162 |
+
!event.url.pathname.startsWith(`${base}/login/callback`) &&
|
| 163 |
+
!event.url.pathname.startsWith(`${base}/healthcheck`) &&
|
| 164 |
+
!event.url.pathname.startsWith(`${base}/r/`) &&
|
| 165 |
+
!event.url.pathname.startsWith(`${base}/conversation/`) &&
|
| 166 |
+
!event.url.pathname.startsWith(`${base}/api`)
|
| 167 |
+
) {
|
| 168 |
+
refreshSessionCookie(event.cookies, auth.secretSessionId);
|
| 169 |
+
return triggerOauthFlow({ request: event.request, url: event.url, locals: event.locals });
|
| 170 |
+
}
|
| 171 |
+
}
|
| 172 |
}
|
| 173 |
|
| 174 |
event.locals.user = auth.user || undefined;
|
src/lib/components/MobileNav.svelte
CHANGED
|
@@ -17,6 +17,7 @@
|
|
| 17 |
import { Spring } from "svelte/motion";
|
| 18 |
import { shareModal } from "$lib/stores/shareModal";
|
| 19 |
import { loading } from "$lib/stores/loading";
|
|
|
|
| 20 |
interface Props {
|
| 21 |
title: string | undefined;
|
| 22 |
children?: import("svelte").Snippet;
|
|
@@ -105,7 +106,15 @@
|
|
| 105 |
<IconShare classNames={!canShare ? "opacity-40" : ""} />
|
| 106 |
</button>
|
| 107 |
{/if}
|
| 108 |
-
<a
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
<IconNew />
|
| 110 |
</a>
|
| 111 |
</div>
|
|
|
|
| 17 |
import { Spring } from "svelte/motion";
|
| 18 |
import { shareModal } from "$lib/stores/shareModal";
|
| 19 |
import { loading } from "$lib/stores/loading";
|
| 20 |
+
import { requireAuthUser } from "$lib/utils/auth";
|
| 21 |
interface Props {
|
| 22 |
title: string | undefined;
|
| 23 |
children?: import("svelte").Snippet;
|
|
|
|
| 106 |
<IconShare classNames={!canShare ? "opacity-40" : ""} />
|
| 107 |
</button>
|
| 108 |
{/if}
|
| 109 |
+
<a
|
| 110 |
+
href="{base}/"
|
| 111 |
+
class="flex size-8 shrink-0 items-center justify-center text-lg"
|
| 112 |
+
onclick={(e) => {
|
| 113 |
+
if (requireAuthUser()) {
|
| 114 |
+
e.preventDefault();
|
| 115 |
+
}
|
| 116 |
+
}}
|
| 117 |
+
>
|
| 118 |
<IconNew />
|
| 119 |
</a>
|
| 120 |
</div>
|
src/lib/components/NavConversationItem.svelte
CHANGED
|
@@ -9,6 +9,7 @@
|
|
| 9 |
import type { ConvSidebar } from "$lib/types/ConvSidebar";
|
| 10 |
|
| 11 |
import EditConversationModal from "$lib/components/EditConversationModal.svelte";
|
|
|
|
| 12 |
|
| 13 |
interface Props {
|
| 14 |
conv: ConvSidebar;
|
|
@@ -49,6 +50,7 @@
|
|
| 49 |
title="Cancel delete action"
|
| 50 |
onclick={(e) => {
|
| 51 |
e.preventDefault();
|
|
|
|
| 52 |
confirmDelete = false;
|
| 53 |
}}
|
| 54 |
>
|
|
@@ -60,6 +62,7 @@
|
|
| 60 |
title="Confirm delete action"
|
| 61 |
onclick={(e) => {
|
| 62 |
e.preventDefault();
|
|
|
|
| 63 |
confirmDelete = false;
|
| 64 |
ondeleteConversation?.(conv.id.toString());
|
| 65 |
}}
|
|
@@ -75,6 +78,7 @@
|
|
| 75 |
title="Edit conversation title"
|
| 76 |
onclick={(e) => {
|
| 77 |
e.preventDefault();
|
|
|
|
| 78 |
renameOpen = true;
|
| 79 |
}}
|
| 80 |
>
|
|
@@ -87,6 +91,7 @@
|
|
| 87 |
title="Delete conversation"
|
| 88 |
onclick={(event) => {
|
| 89 |
event.preventDefault();
|
|
|
|
| 90 |
if (event.shiftKey) {
|
| 91 |
ondeleteConversation?.(conv.id.toString());
|
| 92 |
} else {
|
|
|
|
| 9 |
import type { ConvSidebar } from "$lib/types/ConvSidebar";
|
| 10 |
|
| 11 |
import EditConversationModal from "$lib/components/EditConversationModal.svelte";
|
| 12 |
+
import { requireAuthUser } from "$lib/utils/auth";
|
| 13 |
|
| 14 |
interface Props {
|
| 15 |
conv: ConvSidebar;
|
|
|
|
| 50 |
title="Cancel delete action"
|
| 51 |
onclick={(e) => {
|
| 52 |
e.preventDefault();
|
| 53 |
+
if (requireAuthUser()) return;
|
| 54 |
confirmDelete = false;
|
| 55 |
}}
|
| 56 |
>
|
|
|
|
| 62 |
title="Confirm delete action"
|
| 63 |
onclick={(e) => {
|
| 64 |
e.preventDefault();
|
| 65 |
+
if (requireAuthUser()) return;
|
| 66 |
confirmDelete = false;
|
| 67 |
ondeleteConversation?.(conv.id.toString());
|
| 68 |
}}
|
|
|
|
| 78 |
title="Edit conversation title"
|
| 79 |
onclick={(e) => {
|
| 80 |
e.preventDefault();
|
| 81 |
+
if (requireAuthUser()) return;
|
| 82 |
renameOpen = true;
|
| 83 |
}}
|
| 84 |
>
|
|
|
|
| 91 |
title="Delete conversation"
|
| 92 |
onclick={(event) => {
|
| 93 |
event.preventDefault();
|
| 94 |
+
if (requireAuthUser()) return;
|
| 95 |
if (event.shiftKey) {
|
| 96 |
ondeleteConversation?.(conv.id.toString());
|
| 97 |
} else {
|
src/lib/components/NavMenu.svelte
CHANGED
|
@@ -27,6 +27,7 @@
|
|
| 27 |
import { browser } from "$app/environment";
|
| 28 |
import { usePublicConfig } from "$lib/utils/PublicConfig.svelte";
|
| 29 |
import { useAPIClient, handleResponse } from "$lib/APIClient";
|
|
|
|
| 30 |
|
| 31 |
const publicConfig = usePublicConfig();
|
| 32 |
const client = useAPIClient();
|
|
@@ -49,8 +50,18 @@
|
|
| 49 |
|
| 50 |
let hasMore = $state(true);
|
| 51 |
|
| 52 |
-
function handleNewChatClick() {
|
| 53 |
isAborted.set(true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
}
|
| 55 |
|
| 56 |
const dateRanges = [
|
|
@@ -174,6 +185,7 @@
|
|
| 174 |
<a
|
| 175 |
href="{base}/models"
|
| 176 |
class="flex h-9 flex-none items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
|
|
|
|
| 177 |
>
|
| 178 |
Models
|
| 179 |
<span
|
|
@@ -186,6 +198,7 @@
|
|
| 186 |
<a
|
| 187 |
href="{base}/settings/application"
|
| 188 |
class="flex h-9 flex-none flex-grow items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
|
|
|
|
| 189 |
>
|
| 190 |
Settings
|
| 191 |
</a>
|
|
|
|
| 27 |
import { browser } from "$app/environment";
|
| 28 |
import { usePublicConfig } from "$lib/utils/PublicConfig.svelte";
|
| 29 |
import { useAPIClient, handleResponse } from "$lib/APIClient";
|
| 30 |
+
import { requireAuthUser } from "$lib/utils/auth";
|
| 31 |
|
| 32 |
const publicConfig = usePublicConfig();
|
| 33 |
const client = useAPIClient();
|
|
|
|
| 50 |
|
| 51 |
let hasMore = $state(true);
|
| 52 |
|
| 53 |
+
function handleNewChatClick(e: MouseEvent) {
|
| 54 |
isAborted.set(true);
|
| 55 |
+
|
| 56 |
+
if (requireAuthUser()) {
|
| 57 |
+
e.preventDefault();
|
| 58 |
+
}
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
function handleNavItemClick(e: MouseEvent) {
|
| 62 |
+
if (requireAuthUser()) {
|
| 63 |
+
e.preventDefault();
|
| 64 |
+
}
|
| 65 |
}
|
| 66 |
|
| 67 |
const dateRanges = [
|
|
|
|
| 185 |
<a
|
| 186 |
href="{base}/models"
|
| 187 |
class="flex h-9 flex-none items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
|
| 188 |
+
onclick={handleNavItemClick}
|
| 189 |
>
|
| 190 |
Models
|
| 191 |
<span
|
|
|
|
| 198 |
<a
|
| 199 |
href="{base}/settings/application"
|
| 200 |
class="flex h-9 flex-none flex-grow items-center gap-1.5 rounded-lg pl-2.5 pr-2 text-gray-500 hover:bg-gray-100 dark:text-gray-400 dark:hover:bg-gray-700"
|
| 201 |
+
onclick={handleNavItemClick}
|
| 202 |
>
|
| 203 |
Settings
|
| 204 |
</a>
|
src/lib/components/chat/ChatInput.svelte
CHANGED
|
@@ -7,6 +7,8 @@
|
|
| 7 |
import IconPaperclip from "$lib/components/icons/IconPaperclip.svelte";
|
| 8 |
|
| 9 |
import { isVirtualKeyboard } from "$lib/utils/isVirtualKeyboard";
|
|
|
|
|
|
|
| 10 |
interface Props {
|
| 11 |
files?: File[];
|
| 12 |
mimeTypes?: string[];
|
|
@@ -160,6 +162,7 @@
|
|
| 160 |
{disabled}
|
| 161 |
onfocus={handleFocus}
|
| 162 |
onblur={handleBlur}
|
|
|
|
| 163 |
></textarea>
|
| 164 |
|
| 165 |
{#if !showNoTools}
|
|
@@ -194,6 +197,11 @@
|
|
| 194 |
aria-label="Upload file"
|
| 195 |
type="file"
|
| 196 |
onchange={onFileChange}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 197 |
accept={mimeTypes.join(",")}
|
| 198 |
/>
|
| 199 |
<IconPaperclip classNames="text-xl" />
|
|
|
|
| 7 |
import IconPaperclip from "$lib/components/icons/IconPaperclip.svelte";
|
| 8 |
|
| 9 |
import { isVirtualKeyboard } from "$lib/utils/isVirtualKeyboard";
|
| 10 |
+
import { requireAuthUser } from "$lib/utils/auth";
|
| 11 |
+
|
| 12 |
interface Props {
|
| 13 |
files?: File[];
|
| 14 |
mimeTypes?: string[];
|
|
|
|
| 162 |
{disabled}
|
| 163 |
onfocus={handleFocus}
|
| 164 |
onblur={handleBlur}
|
| 165 |
+
onbeforeinput={requireAuthUser}
|
| 166 |
></textarea>
|
| 167 |
|
| 168 |
{#if !showNoTools}
|
|
|
|
| 197 |
aria-label="Upload file"
|
| 198 |
type="file"
|
| 199 |
onchange={onFileChange}
|
| 200 |
+
onclick={(e) => {
|
| 201 |
+
if (requireAuthUser()) {
|
| 202 |
+
e.preventDefault();
|
| 203 |
+
}
|
| 204 |
+
}}
|
| 205 |
accept={mimeTypes.join(",")}
|
| 206 |
/>
|
| 207 |
<IconPaperclip classNames="text-xl" />
|
src/lib/components/chat/ChatMessage.svelte
CHANGED
|
@@ -17,6 +17,7 @@
|
|
| 17 |
import Alternatives from "./Alternatives.svelte";
|
| 18 |
import MessageAvatar from "./MessageAvatar.svelte";
|
| 19 |
import { PROVIDERS_HUB_ORGS } from "@huggingface/inference";
|
|
|
|
| 20 |
|
| 21 |
interface Props {
|
| 22 |
message: Message;
|
|
@@ -329,7 +330,10 @@
|
|
| 329 |
class="hidden cursor-pointer items-center gap-1 rounded-md border border-gray-200 px-1.5 py-0.5 text-xs text-gray-400 group-hover:flex hover:flex hover:text-gray-500 dark:border-gray-700 dark:text-gray-400 dark:hover:text-gray-300 lg:-right-2"
|
| 330 |
title="Edit"
|
| 331 |
type="button"
|
| 332 |
-
onclick={() =>
|
|
|
|
|
|
|
|
|
|
| 333 |
>
|
| 334 |
<CarbonPen />
|
| 335 |
Edit
|
|
|
|
| 17 |
import Alternatives from "./Alternatives.svelte";
|
| 18 |
import MessageAvatar from "./MessageAvatar.svelte";
|
| 19 |
import { PROVIDERS_HUB_ORGS } from "@huggingface/inference";
|
| 20 |
+
import { requireAuthUser } from "$lib/utils/auth";
|
| 21 |
|
| 22 |
interface Props {
|
| 23 |
message: Message;
|
|
|
|
| 330 |
class="hidden cursor-pointer items-center gap-1 rounded-md border border-gray-200 px-1.5 py-0.5 text-xs text-gray-400 group-hover:flex hover:flex hover:text-gray-500 dark:border-gray-700 dark:text-gray-400 dark:hover:text-gray-300 lg:-right-2"
|
| 331 |
title="Edit"
|
| 332 |
type="button"
|
| 333 |
+
onclick={() => {
|
| 334 |
+
if (requireAuthUser()) return;
|
| 335 |
+
editMsdgId = message.id;
|
| 336 |
+
}}
|
| 337 |
>
|
| 338 |
<CarbonPen />
|
| 339 |
Edit
|
src/lib/components/chat/ChatWindow.svelte
CHANGED
|
@@ -32,6 +32,7 @@
|
|
| 32 |
import { cubicInOut } from "svelte/easing";
|
| 33 |
|
| 34 |
import { isVirtualKeyboard } from "$lib/utils/isVirtualKeyboard";
|
|
|
|
| 35 |
|
| 36 |
interface Props {
|
| 37 |
messages?: Message[];
|
|
@@ -74,7 +75,7 @@
|
|
| 74 |
let pastedLongContent = $state(false);
|
| 75 |
|
| 76 |
const handleSubmit = () => {
|
| 77 |
-
if (loading || !draft) return;
|
| 78 |
onmessage?.(draft);
|
| 79 |
draft = "";
|
| 80 |
};
|
|
@@ -273,12 +274,13 @@
|
|
| 273 |
});
|
| 274 |
|
| 275 |
function triggerPrompt(prompt: string) {
|
| 276 |
-
if (loading) return;
|
| 277 |
draft = prompt;
|
| 278 |
handleSubmit();
|
| 279 |
}
|
| 280 |
|
| 281 |
async function startExample(example: RouterExample) {
|
|
|
|
| 282 |
activeRouterExamplePrompt = example.prompt;
|
| 283 |
|
| 284 |
if (browser && example.attachments?.length) {
|
|
@@ -533,6 +535,11 @@
|
|
| 533 |
{#if !currentModel.isRouter || !loading}
|
| 534 |
<a
|
| 535 |
href="{base}/settings/{currentModel.id}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 536 |
class="inline-flex items-center gap-1 hover:underline"
|
| 537 |
>
|
| 538 |
{#if currentModel.isRouter}
|
|
|
|
| 32 |
import { cubicInOut } from "svelte/easing";
|
| 33 |
|
| 34 |
import { isVirtualKeyboard } from "$lib/utils/isVirtualKeyboard";
|
| 35 |
+
import { requireAuthUser } from "$lib/utils/auth";
|
| 36 |
|
| 37 |
interface Props {
|
| 38 |
messages?: Message[];
|
|
|
|
| 75 |
let pastedLongContent = $state(false);
|
| 76 |
|
| 77 |
const handleSubmit = () => {
|
| 78 |
+
if (requireAuthUser() || loading || !draft) return;
|
| 79 |
onmessage?.(draft);
|
| 80 |
draft = "";
|
| 81 |
};
|
|
|
|
| 274 |
});
|
| 275 |
|
| 276 |
function triggerPrompt(prompt: string) {
|
| 277 |
+
if (requireAuthUser() || loading) return;
|
| 278 |
draft = prompt;
|
| 279 |
handleSubmit();
|
| 280 |
}
|
| 281 |
|
| 282 |
async function startExample(example: RouterExample) {
|
| 283 |
+
if (requireAuthUser()) return;
|
| 284 |
activeRouterExamplePrompt = example.prompt;
|
| 285 |
|
| 286 |
if (browser && example.attachments?.length) {
|
|
|
|
| 535 |
{#if !currentModel.isRouter || !loading}
|
| 536 |
<a
|
| 537 |
href="{base}/settings/{currentModel.id}"
|
| 538 |
+
onclick={(e) => {
|
| 539 |
+
if (requireAuthUser()) {
|
| 540 |
+
e.preventDefault();
|
| 541 |
+
}
|
| 542 |
+
}}
|
| 543 |
class="inline-flex items-center gap-1 hover:underline"
|
| 544 |
>
|
| 545 |
{#if currentModel.isRouter}
|
src/lib/components/chat/FileDropzone.svelte
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
<script lang="ts">
|
|
|
|
| 2 |
import CarbonImage from "~icons/carbon/image";
|
| 3 |
|
| 4 |
interface Props {
|
|
@@ -18,7 +19,7 @@
|
|
| 18 |
|
| 19 |
async function dropHandle(event: DragEvent) {
|
| 20 |
event.preventDefault();
|
| 21 |
-
if (event.dataTransfer && event.dataTransfer.items) {
|
| 22 |
// Use DataTransferItemList interface to access the file(s)
|
| 23 |
if (files.length > 0) {
|
| 24 |
files = [];
|
|
|
|
| 1 |
<script lang="ts">
|
| 2 |
+
import { requireAuthUser } from "$lib/utils/auth";
|
| 3 |
import CarbonImage from "~icons/carbon/image";
|
| 4 |
|
| 5 |
interface Props {
|
|
|
|
| 19 |
|
| 20 |
async function dropHandle(event: DragEvent) {
|
| 21 |
event.preventDefault();
|
| 22 |
+
if (!requireAuthUser() && event.dataTransfer && event.dataTransfer.items) {
|
| 23 |
// Use DataTransferItemList interface to access the file(s)
|
| 24 |
if (files.length > 0) {
|
| 25 |
files = [];
|
src/lib/utils/auth.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import { goto } from "$app/navigation";
|
| 2 |
+
import { base } from "$app/paths";
|
| 3 |
+
import { page } from "$app/state";
|
| 4 |
+
|
| 5 |
+
/**
|
| 6 |
+
* Redirects to the login page if the user is not authenticated
|
| 7 |
+
* and the login feature is enabled.
|
| 8 |
+
*/
|
| 9 |
+
export function requireAuthUser(): boolean {
|
| 10 |
+
if (page.data.loginEnabled && !page.data.user) {
|
| 11 |
+
goto(`${base}/login`, { invalidateAll: true });
|
| 12 |
+
return true;
|
| 13 |
+
}
|
| 14 |
+
return false;
|
| 15 |
+
}
|
src/routes/+layout.svelte
CHANGED
|
@@ -22,6 +22,7 @@
|
|
| 22 |
import IconShare from "$lib/components/icons/IconShare.svelte";
|
| 23 |
import { shareModal } from "$lib/stores/shareModal";
|
| 24 |
import BackgroundGenerationPoller from "$lib/components/BackgroundGenerationPoller.svelte";
|
|
|
|
| 25 |
|
| 26 |
let { data = $bindable(), children } = $props();
|
| 27 |
|
|
@@ -95,11 +96,8 @@
|
|
| 95 |
}
|
| 96 |
|
| 97 |
function closeWelcomeModal() {
|
|
|
|
| 98 |
settings.set({ welcomeModalSeen: true });
|
| 99 |
-
|
| 100 |
-
if (!data.user && data.loginEnabled) {
|
| 101 |
-
goto(`${base}/login`, { invalidateAll: true });
|
| 102 |
-
}
|
| 103 |
}
|
| 104 |
|
| 105 |
onDestroy(() => {
|
|
@@ -161,6 +159,7 @@
|
|
| 161 |
if (oPressed && e.shiftKey && metaOrCtrl) {
|
| 162 |
e.preventDefault();
|
| 163 |
isAborted.set(true);
|
|
|
|
| 164 |
goto(`${base}/`, { invalidateAll: true });
|
| 165 |
}
|
| 166 |
};
|
|
@@ -176,7 +175,10 @@
|
|
| 176 |
);
|
| 177 |
|
| 178 |
// Show the welcome modal once on first app load
|
| 179 |
-
let showWelcome = $derived(
|
|
|
|
|
|
|
|
|
|
| 180 |
</script>
|
| 181 |
|
| 182 |
<svelte:head>
|
|
@@ -223,7 +225,7 @@
|
|
| 223 |
{/if}
|
| 224 |
</svelte:head>
|
| 225 |
|
| 226 |
-
{#if showWelcome
|
| 227 |
<WelcomeModal close={closeWelcomeModal} />
|
| 228 |
{/if}
|
| 229 |
|
|
|
|
| 22 |
import IconShare from "$lib/components/icons/IconShare.svelte";
|
| 23 |
import { shareModal } from "$lib/stores/shareModal";
|
| 24 |
import BackgroundGenerationPoller from "$lib/components/BackgroundGenerationPoller.svelte";
|
| 25 |
+
import { requireAuthUser } from "$lib/utils/auth";
|
| 26 |
|
| 27 |
let { data = $bindable(), children } = $props();
|
| 28 |
|
|
|
|
| 96 |
}
|
| 97 |
|
| 98 |
function closeWelcomeModal() {
|
| 99 |
+
if (requireAuthUser()) return;
|
| 100 |
settings.set({ welcomeModalSeen: true });
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
}
|
| 102 |
|
| 103 |
onDestroy(() => {
|
|
|
|
| 159 |
if (oPressed && e.shiftKey && metaOrCtrl) {
|
| 160 |
e.preventDefault();
|
| 161 |
isAborted.set(true);
|
| 162 |
+
if (requireAuthUser()) return;
|
| 163 |
goto(`${base}/`, { invalidateAll: true });
|
| 164 |
}
|
| 165 |
};
|
|
|
|
| 175 |
);
|
| 176 |
|
| 177 |
// Show the welcome modal once on first app load
|
| 178 |
+
let showWelcome = $derived(
|
| 179 |
+
!$settings.welcomeModalSeen &&
|
| 180 |
+
!(page.data.shared === true && page.route.id?.startsWith("/conversation/"))
|
| 181 |
+
);
|
| 182 |
</script>
|
| 183 |
|
| 184 |
<svelte:head>
|
|
|
|
| 225 |
{/if}
|
| 226 |
</svelte:head>
|
| 227 |
|
| 228 |
+
{#if showWelcome}
|
| 229 |
<WelcomeModal close={closeWelcomeModal} />
|
| 230 |
{/if}
|
| 231 |
|
src/routes/conversation/[id]/+page.svelte
CHANGED
|
@@ -27,6 +27,7 @@
|
|
| 27 |
import { updateDebouncer } from "$lib/utils/updates.js";
|
| 28 |
import SubscribeModal from "$lib/components/SubscribeModal.svelte";
|
| 29 |
import { loading } from "$lib/stores/loading.js";
|
|
|
|
| 30 |
|
| 31 |
let { data = $bindable() } = $props();
|
| 32 |
|
|
@@ -393,6 +394,8 @@
|
|
| 393 |
}
|
| 394 |
|
| 395 |
async function onRetry(payload: { id: Message["id"]; content?: string }) {
|
|
|
|
|
|
|
| 396 |
const lastMsgId = payload.id;
|
| 397 |
messagesPath = createMessagesPath(messages, lastMsgId);
|
| 398 |
|
|
|
|
| 27 |
import { updateDebouncer } from "$lib/utils/updates.js";
|
| 28 |
import SubscribeModal from "$lib/components/SubscribeModal.svelte";
|
| 29 |
import { loading } from "$lib/stores/loading.js";
|
| 30 |
+
import { requireAuthUser } from "$lib/utils/auth.js";
|
| 31 |
|
| 32 |
let { data = $bindable() } = $props();
|
| 33 |
|
|
|
|
| 394 |
}
|
| 395 |
|
| 396 |
async function onRetry(payload: { id: Message["id"]; content?: string }) {
|
| 397 |
+
if (requireAuthUser()) return;
|
| 398 |
+
|
| 399 |
const lastMsgId = payload.id;
|
| 400 |
messagesPath = createMessagesPath(messages, lastMsgId);
|
| 401 |
|