mirror of
https://github.com/seriousm4x/UpSnap.git
synced 2026-03-31 06:24:09 -04:00
feat: support for sub path hosting
This commit is contained in:
15
README.md
15
README.md
@@ -116,6 +116,21 @@ upsnap.example.com {
|
||||
}
|
||||
```
|
||||
|
||||
### Run in sub path
|
||||
|
||||
You can run UpSnap on a different path than `/`, e.g. `/upsnap-sub-path/`. To do this in caddy, set the following:
|
||||
|
||||
```
|
||||
http://localhost:8091 {
|
||||
handle /upsnap-sub-path/* {
|
||||
uri strip_prefix /upsnap-sub-path
|
||||
reverse_proxy localhost:8090
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Paths must end with a trailing `/`.
|
||||
|
||||
## 🐧 Install from the [AUR](https://aur.archlinux.org/packages/upsnap-bin)
|
||||
|
||||
```bash
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { resolve } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { asset, resolve } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import { m } from '$lib/paraglide/messages';
|
||||
import { backendUrl, permission, pocketbase } from '$lib/stores/pocketbase';
|
||||
import { settingsPub } from '$lib/stores/settings';
|
||||
@@ -111,7 +111,7 @@
|
||||
</div>
|
||||
{/if}
|
||||
<li>
|
||||
<a href={resolve('/')} class="px-4 py-2" class:active={$page.url.pathname === '/'}
|
||||
<a href={resolve('/')} class="px-4 py-2" class:active={page.url.pathname === resolve('/')}
|
||||
><Fa icon={faHome} />{m.home_page_title()}</a
|
||||
>
|
||||
</li>
|
||||
@@ -120,7 +120,7 @@
|
||||
<a
|
||||
href={resolve('/users')}
|
||||
class="px-4 py-2"
|
||||
class:active={$page.url.pathname.startsWith('/users')}
|
||||
class:active={page.url.pathname.startsWith(resolve('/users'))}
|
||||
><Fa icon={faUsersGear} />{m.users_page_title()}</a
|
||||
>
|
||||
</li>
|
||||
@@ -128,7 +128,7 @@
|
||||
<a
|
||||
href={resolve('/settings/')}
|
||||
class="px-4 py-2"
|
||||
class:active={$page.url.pathname.startsWith('/settings')}
|
||||
class:active={page.url.pathname.startsWith(resolve('/settings'))}
|
||||
><Fa icon={faCog} />{m.settings_page_title()}</a
|
||||
>
|
||||
</li>
|
||||
@@ -173,7 +173,7 @@
|
||||
<img
|
||||
src={$settingsPub?.id && $settingsPub?.favicon
|
||||
? `${backendUrl}api/files/settings_public/${$settingsPub?.id}/${$settingsPub?.favicon}`
|
||||
: '/gopher.svg'}
|
||||
: asset('/gopher.svg')}
|
||||
alt={$settingsPub?.website_title ? $settingsPub?.website_title : 'UpSnap'}
|
||||
width="45"
|
||||
height="45"
|
||||
@@ -186,7 +186,7 @@
|
||||
{/if}
|
||||
<ul class="menu menu-horizontal h-full gap-1 px-1">
|
||||
<li class="h-full">
|
||||
<a href={resolve('/')} class="p-2" class:menu-active={$page.url.pathname === '/'}
|
||||
<a href={resolve('/')} class="p-2" class:menu-active={page.url.pathname === resolve('/')}
|
||||
><Fa icon={faHome} />{m.home_page_title()}</a
|
||||
>
|
||||
</li>
|
||||
@@ -195,7 +195,7 @@
|
||||
<a
|
||||
href={resolve('/users')}
|
||||
class="p-2"
|
||||
class:menu-active={$page.url.pathname.startsWith('/users')}
|
||||
class:menu-active={page.url.pathname.startsWith(resolve('/users'))}
|
||||
><Fa icon={faUsersGear} />{m.users_page_title()}</a
|
||||
>
|
||||
</li>
|
||||
@@ -203,7 +203,7 @@
|
||||
<a
|
||||
href={resolve('/settings/')}
|
||||
class="p-2"
|
||||
class:menu-active={$page.url.pathname.startsWith('/settings')}
|
||||
class:menu-active={page.url.pathname.startsWith(resolve('/settings'))}
|
||||
><Fa icon={faCog} />{m.settings_page_title()}</a
|
||||
>
|
||||
</li>
|
||||
@@ -254,7 +254,7 @@
|
||||
<div class="dropdown dropdown-end">
|
||||
<label tabindex="-1" class="avatar btn btn-circle btn-ghost" for="avatar">
|
||||
<div class="w-10 rounded-full" id="avatar">
|
||||
<img src="/avatars/avatar{avatar}.svg" alt="Avatar {avatar}" />
|
||||
<img src={asset(`/avatars/avatar${avatar}.svg`)} alt="Avatar {avatar}" />
|
||||
</div>
|
||||
</label>
|
||||
<ul
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { resolve } from '$app/paths';
|
||||
import type { Permission } from '$lib/types/permission';
|
||||
import PocketBase from 'pocketbase';
|
||||
import { writable } from 'svelte/store';
|
||||
|
||||
// set backend url based on environment
|
||||
export const backendUrl = import.meta.env.DEV ? 'http://127.0.0.1:8090/' : '/';
|
||||
export const backendUrl = import.meta.env.DEV ? 'http://127.0.0.1:8090/' : resolve('/');
|
||||
|
||||
// connect to backend
|
||||
const pb = new PocketBase(backendUrl);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { resolve } from '$app/paths';
|
||||
import { asset, resolve } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import Navbar from '$lib/components/Navbar.svelte';
|
||||
import Transition from '$lib/components/Transition.svelte';
|
||||
@@ -90,7 +90,7 @@
|
||||
rel="shortcut icon"
|
||||
href={$settingsPub?.id && $settingsPub?.favicon
|
||||
? `${backendUrl}api/files/settings_public/${$settingsPub?.id}/${$settingsPub?.favicon}`
|
||||
: '/gopher.svg'}
|
||||
: asset('/gopher.svg')}
|
||||
/>
|
||||
{#if $settingsPub === undefined}
|
||||
<title>UpSnap</title>
|
||||
@@ -99,7 +99,7 @@
|
||||
{/if}
|
||||
</svelte:head>
|
||||
|
||||
{#if authIsValid && !page.url.pathname.startsWith('/welcome')}
|
||||
{#if authIsValid && !page.url.pathname.startsWith(resolve('/welcome'))}
|
||||
<Navbar />
|
||||
{/if}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { resolve } from '$app/paths';
|
||||
import { asset, resolve } from '$app/paths';
|
||||
import { m } from '$lib/paraglide/messages';
|
||||
import type { Locale } from '$lib/paraglide/runtime';
|
||||
import { getLocale, locales, setLocale } from '$lib/paraglide/runtime';
|
||||
@@ -145,7 +145,7 @@
|
||||
<div class="w-16 rounded-full">
|
||||
{#if $pocketbase.authStore.record?.id}
|
||||
<img
|
||||
src="/avatars/avatar{newAvatar ?? $pocketbase.authStore.record?.avatar}.svg"
|
||||
src={asset(`/avatars/avatar${newAvatar ?? $pocketbase.authStore.record?.avatar}.svg`)}
|
||||
alt="Avatar {newAvatar ?? $pocketbase.authStore.record?.avatar}"
|
||||
/>
|
||||
{/if}
|
||||
@@ -192,7 +192,7 @@
|
||||
role="none"
|
||||
>
|
||||
{#if $pocketbase.authStore.record?.id}
|
||||
<img src="/avatars/avatar{i}.svg" alt="{m.account_avatar_title()} {i}" />
|
||||
<img src={asset(`/avatars/avatar${i}.svg`)} alt="{m.account_avatar_title()} {i}" />
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { resolve } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { page } from '$app/state';
|
||||
import DeviceForm from '$lib/components/DeviceForm.svelte';
|
||||
import NetworkScan from '$lib/components/NetworkScan.svelte';
|
||||
import { m } from '$lib/paraglide/messages';
|
||||
@@ -49,7 +49,7 @@
|
||||
$effect(() => {
|
||||
if (Object.hasOwn($permission, 'create')) {
|
||||
if (!$pocketbase.authStore.isSuperuser && !$permission.create) {
|
||||
toast(m.toasts_no_permission({ url: $page.url.pathname }), {
|
||||
toast(m.toasts_no_permission({ url: page.url.pathname }), {
|
||||
icon: '⛔'
|
||||
});
|
||||
goto(resolve('/'));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { resolve } from '$app/paths';
|
||||
import { asset, resolve } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import { PUBLIC_VERSION } from '$env/static/public';
|
||||
import PageLoading from '$lib/components/PageLoading.svelte';
|
||||
@@ -194,7 +194,7 @@ second (0–59, optional)
|
||||
class="h-36"
|
||||
src={$settingsPub.favicon !== ''
|
||||
? `${backendUrl}api/files/settings_public/${$settingsPub.id}/${$settingsPub.favicon}`
|
||||
: '/gopher.svg'}
|
||||
: asset('/gopher.svg')}
|
||||
alt="Favicon preview"
|
||||
bind:this={faviconPreview}
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { goto } from '$app/navigation';
|
||||
import { resolve } from '$app/paths';
|
||||
import { page } from '$app/stores';
|
||||
import { asset, resolve } from '$app/paths';
|
||||
import { page } from '$app/state';
|
||||
import PageLoading from '$lib/components/PageLoading.svelte';
|
||||
import { m } from '$lib/paraglide/messages';
|
||||
import { pocketbase } from '$lib/stores/pocketbase';
|
||||
@@ -37,7 +37,7 @@
|
||||
|
||||
onMount(() => {
|
||||
if (!$pocketbase.authStore.isSuperuser) {
|
||||
toast(m.toasts_no_permission({ url: $page.url.pathname }), {
|
||||
toast(m.toasts_no_permission({ url: page.url.pathname }), {
|
||||
icon: '⛔'
|
||||
});
|
||||
goto(resolve('/'));
|
||||
@@ -197,7 +197,7 @@
|
||||
<h2 class="card-title">
|
||||
<label tabindex="-1" class="avatar" for="avatar{index}">
|
||||
<div class="w-10 rounded-full" id="avatar{index}">
|
||||
<img src="/avatars/avatar{user.avatar}.svg" alt="Avatar {user.avatar}" />
|
||||
<img src={asset(`/avatars/avatar${user.avatar}.svg`)} alt="Avatar {user.avatar}" />
|
||||
</div>
|
||||
</label>
|
||||
{user.username}
|
||||
|
||||
Reference in New Issue
Block a user