mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
Reorganize FE
This commit is contained in:
parent
e27a80c40a
commit
354493133c
29
packages/frontend/composables/useConfig.ts
Normal file
29
packages/frontend/composables/useConfig.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
export const useConfig = async () => {
|
||||||
|
let host = useRequestHeader("X-Forwarded-Host");
|
||||||
|
|
||||||
|
if (!host && process.server) {
|
||||||
|
host = process.env.BUILD_HOST;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!host?.includes("http")) {
|
||||||
|
// On server, this will be some kind of localhost
|
||||||
|
host = `http://${host}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.client) {
|
||||||
|
host = useRequestURL().origin.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(host);
|
||||||
|
|
||||||
|
if (!host) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 500,
|
||||||
|
statusMessage: "No X-Forwarded-Host header found",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return await fetch(new URL("/api/_fe/config", host)).then((res) =>
|
||||||
|
res.json(),
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="flex min-h-screen flex-col justify-center px-6 py-12 lg:px-8 relative">
|
<div class="flex min-h-screen flex-col justify-center px-6 py-12 lg:px-8 relative">
|
||||||
<div class="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80" aria-hidden="true">
|
<div class="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
|
||||||
|
aria-hidden="true">
|
||||||
<div class="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
|
<div class="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
|
||||||
style="clip-path: polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)" />
|
style="clip-path: polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)" />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -14,7 +15,7 @@ import { getHighlighterCore } from "shiki/core";
|
||||||
import getWasm from "shiki/wasm";
|
import getWasm from "shiki/wasm";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
const config = (await useFetch("/api/config")).data.value;
|
const config = await useConfig();
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
throw new Error("Config not found");
|
throw new Error("Config not found");
|
||||||
|
|
@ -51,17 +52,17 @@ const code = highlighter.codeToHtml(JSON.stringify(data, null, 4), {
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
pre:has(code) {
|
pre:has(code) {
|
||||||
word-wrap: normal;
|
word-wrap: normal;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
-webkit-hyphens: none;
|
-webkit-hyphens: none;
|
||||||
hyphens: none;
|
hyphens: none;
|
||||||
-moz-tab-size: 4;
|
-moz-tab-size: 4;
|
||||||
-o-tab-size: 4;
|
-o-tab-size: 4;
|
||||||
tab-size: 4;
|
tab-size: 4;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
word-break: normal;
|
word-break: normal;
|
||||||
word-spacing: normal;
|
word-spacing: normal;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
@apply ring-1 ring-white/10 mt-4 bg-white/5 px-4 py-3 rounded;
|
@apply ring-1 ring-white/10 mt-4 bg-white/5 px-4 py-3 rounded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="flex min-h-screen flex-col justify-center px-6 py-12 lg:px-8 relative">
|
<div class="flex min-h-screen flex-col justify-center px-6 py-12 lg:px-8 relative">
|
||||||
<div class="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80" aria-hidden="true">
|
<div class="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
|
||||||
|
aria-hidden="true">
|
||||||
<div class="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
|
<div class="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
|
||||||
style="clip-path: polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)" />
|
style="clip-path: polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)" />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -14,7 +15,7 @@ import { getHighlighterCore } from "shiki/core";
|
||||||
import getWasm from "shiki/wasm";
|
import getWasm from "shiki/wasm";
|
||||||
import { useRoute } from "vue-router";
|
import { useRoute } from "vue-router";
|
||||||
|
|
||||||
const config = (await useFetch("/api/config")).data.value;
|
const config = await useConfig();
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
throw new Error("Config not found");
|
throw new Error("Config not found");
|
||||||
|
|
@ -62,17 +63,17 @@ const code = highlighter.codeToHtml(JSON.stringify(data, null, 4), {
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
pre:has(code) {
|
pre:has(code) {
|
||||||
word-wrap: normal;
|
word-wrap: normal;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
-webkit-hyphens: none;
|
-webkit-hyphens: none;
|
||||||
hyphens: none;
|
hyphens: none;
|
||||||
-moz-tab-size: 4;
|
-moz-tab-size: 4;
|
||||||
-o-tab-size: 4;
|
-o-tab-size: 4;
|
||||||
tab-size: 4;
|
tab-size: 4;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
word-break: normal;
|
word-break: normal;
|
||||||
word-spacing: normal;
|
word-spacing: normal;
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
@apply ring-1 ring-white/10 mt-4 bg-white/5 px-4 py-3 rounded;
|
@apply ring-1 ring-white/10 mt-4 bg-white/5 px-4 py-3 rounded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,8 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<h1 class="text-4xl font-bold tracking-tight text-gray-900 sm:text-6xl">Welcome to Lysand</h1>
|
<h1 class="text-4xl font-bold tracking-tight text-gray-900 sm:text-6xl">Welcome to Lysand</h1>
|
||||||
<p class="mt-6 text-lg leading-8 text-gray-600">You can login to this server by pointing any Mastodon
|
<p class="mt-6 text-lg leading-8 text-gray-600">You can login to this server by pointing any
|
||||||
|
Mastodon
|
||||||
client at <strong class="font-bold">{{ config?.http.base_url }}</strong></p>
|
client at <strong class="font-bold">{{ config?.http.base_url }}</strong></p>
|
||||||
<div class="mt-10 flex items-center justify-center gap-6 md:flex-row flex-col">
|
<div class="mt-10 flex items-center justify-center gap-6 md:flex-row flex-col">
|
||||||
<a href="https://github.com/lysand-org/lysand" target="_blank"
|
<a href="https://github.com/lysand-org/lysand" target="_blank"
|
||||||
|
|
@ -29,7 +30,8 @@
|
||||||
<p class="mt-6 text-lg leading-8 text-gray-600">Here are some recommended clients:</p>
|
<p class="mt-6 text-lg leading-8 text-gray-600">Here are some recommended clients:</p>
|
||||||
<ul class="w-full flex flex-col gap-3 mt-4">
|
<ul class="w-full flex flex-col gap-3 mt-4">
|
||||||
<li v-for="client of recommendedClients" :key="client.name" class="w-full">
|
<li v-for="client of recommendedClients" :key="client.name" class="w-full">
|
||||||
<a :href="client.link" class="rounded-sm ring-2 ring-black/10 px-4 py-2 w-full flex flex-row gap-3 items-center">
|
<a :href="client.link"
|
||||||
|
class="rounded-sm ring-2 ring-black/10 px-4 py-2 w-full flex flex-row gap-3 items-center">
|
||||||
<img :src="client.icon" :alt="client.name" class="h-10 w-10" />
|
<img :src="client.icon" :alt="client.name" class="h-10 w-10" />
|
||||||
<div class="flex flex-col justify-between items-start">
|
<div class="flex flex-col justify-between items-start">
|
||||||
<h2 class="font-bold">{{ client.name }}</h2>
|
<h2 class="font-bold">{{ client.name }}</h2>
|
||||||
|
|
@ -39,11 +41,13 @@
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p class="mt-6 text-lg leading-8 text-gray-600">
|
<p class="mt-6 text-lg leading-8 text-gray-600">
|
||||||
Many other clients exist, but <strong class="font-bold">they have not been tested for compatibility</strong>. Bug reports are nevertheless welcome.
|
Many other clients exist, but <strong class="font-bold">they have not been tested for
|
||||||
|
compatibility</strong>. Bug reports are nevertheless welcome.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p class="mt-6 text-lg leading-8 text-gray-600">
|
<p class="mt-6 text-lg leading-8 text-gray-600">
|
||||||
Found a problem? Report it on <a href="https://github.com/lysand-org/lysand/issues/new/choose" class="underline text-purple-700">the issue tracker</a>.
|
Found a problem? Report it on <a href="https://github.com/lysand-org/lysand/issues/new/choose"
|
||||||
|
class="underline text-purple-700">the issue tracker</a>.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -60,8 +64,7 @@
|
||||||
import { recommendedClients } from "../constants";
|
import { recommendedClients } from "../constants";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const version = __VERSION__;
|
const version = __VERSION__;
|
||||||
|
const config = await useConfig();
|
||||||
const config = (await useFetch("/api/config")).data.value;
|
|
||||||
|
|
||||||
useServerSeoMeta({
|
useServerSeoMeta({
|
||||||
title: "Welcome to Lysand!",
|
title: "Welcome to Lysand!",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="flex min-h-screen flex-col justify-center px-6 py-12 lg:px-8 relative">
|
<div class="flex min-h-screen flex-col justify-center px-6 py-12 lg:px-8 relative">
|
||||||
<div class="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80" aria-hidden="true">
|
<div class="absolute inset-x-0 -top-40 -z-10 transform-gpu overflow-hidden blur-3xl sm:-top-80"
|
||||||
|
aria-hidden="true">
|
||||||
<div class="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
|
<div class="relative left-[calc(50%-11rem)] aspect-[1155/678] w-[36.125rem] -translate-x-1/2 rotate-[30deg] bg-gradient-to-tr from-[#ff80b5] to-[#9089fc] opacity-30 sm:left-[calc(50%-30rem)] sm:w-[72.1875rem]"
|
||||||
style="clip-path: polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)" />
|
style="clip-path: polygon(74.1% 44.1%, 100% 61.6%, 97.5% 26.9%, 85.5% 0.1%, 80.7% 2%, 72.5% 32.5%, 60.2% 62.4%, 52.4% 68.1%, 47.5% 58.3%, 45.2% 34.5%, 27.5% 76.7%, 0.1% 64.9%, 17.9% 100%, 27.6% 76.8%, 76.1% 97.7%, 74.1% 44.1%)" />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -66,7 +67,8 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="">
|
<div class="">
|
||||||
<input type="checkbox" :value="tosAccepted" @input="tosAccepted = Boolean(($event.target as any).value)"
|
<input type="checkbox" :value="tosAccepted"
|
||||||
|
@input="tosAccepted = Boolean(($event.target as any).value)"
|
||||||
class="rounded mr-1 align-middle mb-0.5" /> <span class="text-sm">I agree to the
|
class="rounded mr-1 align-middle mb-0.5" /> <span class="text-sm">I agree to the
|
||||||
terms and
|
terms and
|
||||||
conditions
|
conditions
|
||||||
|
|
@ -89,9 +91,11 @@
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<h1 class="text-2xl font-bold tracking-tight text-gray-900 sm:text-4xl text-center">Registrations are disabled
|
<h1 class="text-2xl font-bold tracking-tight text-gray-900 sm:text-4xl text-center">Registrations are
|
||||||
|
disabled
|
||||||
</h1>
|
</h1>
|
||||||
<p class="mt-6 text-lg leading-8 text-gray-600 text-center">Ask this instance's admin to enable them in config!
|
<p class="mt-6 text-lg leading-8 text-gray-600 text-center">Ask this instance's admin to enable them in
|
||||||
|
config!
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -101,7 +105,7 @@
|
||||||
import type { APIInstance } from "../../../../types/entities/instance";
|
import type { APIInstance } from "../../../../types/entities/instance";
|
||||||
import LoginInput from "../../components/LoginInput.vue";
|
import LoginInput from "../../components/LoginInput.vue";
|
||||||
|
|
||||||
const config = (await useFetch("/api/config")).data.value;
|
const config = await useConfig();
|
||||||
|
|
||||||
if (!config) {
|
if (!config) {
|
||||||
throw new Error("Config not found");
|
throw new Error("Config not found");
|
||||||
|
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
import { loadConfig } from "c12";
|
|
||||||
import { type Config, defaultConfig } from "config-manager/config.type";
|
|
||||||
|
|
||||||
const promise = loadConfig<Config>({
|
|
||||||
configFile: "./config/config.toml",
|
|
||||||
defaultConfig: defaultConfig,
|
|
||||||
});
|
|
||||||
|
|
||||||
export default defineEventHandler(async () => {
|
|
||||||
const { config } = await promise;
|
|
||||||
return {
|
|
||||||
http: {
|
|
||||||
bind: config?.http.bind,
|
|
||||||
bind_port: config?.http.bind_port,
|
|
||||||
base_url: config?.http.base_url,
|
|
||||||
url: config?.http.bind.includes("http")
|
|
||||||
? `${config?.http.bind}:${config?.http.bind_port}`
|
|
||||||
: `http://${config?.http.bind}:${config?.http.bind_port}`,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "../.nuxt/tsconfig.server.json"
|
|
||||||
}
|
|
||||||
|
|
@ -82,6 +82,7 @@ export const rawRoutes = {
|
||||||
"/api/v1/statuses/[id]/unpin": "./server/api/api/v1/statuses/[id]/unpin",
|
"/api/v1/statuses/[id]/unpin": "./server/api/api/v1/statuses/[id]/unpin",
|
||||||
"/api/v1/statuses/[id]/unreblog":
|
"/api/v1/statuses/[id]/unreblog":
|
||||||
"./server/api/api/v1/statuses/[id]/unreblog",
|
"./server/api/api/v1/statuses/[id]/unreblog",
|
||||||
|
"/api/_fe/config": "./server/api/api/_fe/config/index",
|
||||||
"/media/[id]": "./server/api/media/[id]/index",
|
"/media/[id]": "./server/api/media/[id]/index",
|
||||||
"/oauth/callback/[issuer]": "./server/api/oauth/callback/[issuer]/index",
|
"/oauth/callback/[issuer]": "./server/api/oauth/callback/[issuer]/index",
|
||||||
"/objects/note/[uuid]": "./server/api/objects/note/[uuid]/index",
|
"/objects/note/[uuid]": "./server/api/objects/note/[uuid]/index",
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,12 @@ export const createServer = (
|
||||||
.replace(config.http.base_url, "http://localhost:5173")
|
.replace(config.http.base_url, "http://localhost:5173")
|
||||||
.replace(base_url_with_http, "http://localhost:5173");
|
.replace(base_url_with_http, "http://localhost:5173");
|
||||||
|
|
||||||
const proxy = await fetch(replacedUrl).catch(async (e) => {
|
const proxy = await fetch(replacedUrl, {
|
||||||
|
headers: {
|
||||||
|
// Include for SSR
|
||||||
|
"X-Forwarded-Host": `${config.http.bind}:${config.http.bind_port}`,
|
||||||
|
},
|
||||||
|
}).catch(async (e) => {
|
||||||
await logger.logError(
|
await logger.logError(
|
||||||
LogLevel.ERROR,
|
LogLevel.ERROR,
|
||||||
"Server.Proxy",
|
"Server.Proxy",
|
||||||
|
|
|
||||||
29
server/api/api/_fe/config/index.ts
Normal file
29
server/api/api/_fe/config/index.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import { apiRoute, applyConfig } from "@api";
|
||||||
|
import { jsonResponse } from "@response";
|
||||||
|
|
||||||
|
export const meta = applyConfig({
|
||||||
|
allowedMethods: ["GET"],
|
||||||
|
ratelimits: {
|
||||||
|
max: 60,
|
||||||
|
duration: 120,
|
||||||
|
},
|
||||||
|
route: "/api/_fe/config",
|
||||||
|
auth: {
|
||||||
|
required: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export default apiRoute(async (req, matchedRoute, extraData) => {
|
||||||
|
const config = await extraData.configManager.getConfig();
|
||||||
|
|
||||||
|
return jsonResponse({
|
||||||
|
http: {
|
||||||
|
bind: config.http.bind,
|
||||||
|
bind_port: config.http.bind_port,
|
||||||
|
base_url: config.http.base_url,
|
||||||
|
url: config.http.bind.includes("http")
|
||||||
|
? `${config.http.bind}:${config.http.bind_port}`
|
||||||
|
: `http://${config.http.bind}:${config.http.bind_port}`,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue