update temp landing page

This commit is contained in:
EGOIST 2022-05-20 01:03:13 +08:00
parent 1732d61e46
commit 85c0019d22
23 changed files with 275 additions and 163 deletions

View File

@ -68,6 +68,7 @@
"@types/sortablejs": "^1.13.0",
"@types/ua-parser-js": "^0.7.36",
"@types/uuid": "^8.3.4",
"autoprefixer": "^10.4.7",
"eslint": "^8.15.0",
"eslint-config-next": "^12.1.6",
"postcss-import": "^14.1.0",

View File

@ -29,6 +29,7 @@ specifiers:
'@types/uuid': ^8.3.4
'@web-std/form-data': ^3.0.2
async-busboy: ^1.1.0
autoprefixer: ^10.4.7
busboy: ^1.6.0
clsx: ^1.1.1
cookie: ^0.5.0
@ -119,6 +120,7 @@ devDependencies:
'@types/sortablejs': 1.13.0
'@types/ua-parser-js': 0.7.36
'@types/uuid': 8.3.4
autoprefixer: 10.4.7
eslint: 8.15.0
eslint-config-next: 12.1.6_6vdljae35l7howjttefzzsim3e
postcss-import: 14.1.0
@ -1085,6 +1087,21 @@ packages:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: false
/autoprefixer/10.4.7:
resolution: {integrity: sha512-ypHju4Y2Oav95SipEcCcI5J7CGPuvz8oat7sUtYj3ClK44bldfvtvcxK6IEK++7rqB7YchDGzweZIBG+SD0ZAA==}
engines: {node: ^10 || ^12 || >=14}
hasBin: true
peerDependencies:
postcss: ^8.1.0
dependencies:
browserslist: 4.20.3
caniuse-lite: 1.0.30001338
fraction.js: 4.2.0
normalize-range: 0.1.2
picocolors: 1.0.0
postcss-value-parser: 4.2.0
dev: true
/available-typed-arrays/1.0.5:
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
engines: {node: '>= 0.4'}
@ -1189,7 +1206,6 @@ packages:
escalade: 3.1.1
node-releases: 2.0.4
picocolors: 1.0.0
dev: false
/busboy/0.3.1:
resolution: {integrity: sha512-y7tTxhGKXcyBxRKAni+awqx8uqaJKrSFSNFSeRG5CsWNdmy2BIK+6VGWEW7TZnIO/533mtMEA4rOevQV815YJw==}
@ -1223,7 +1239,6 @@ packages:
/caniuse-lite/1.0.30001338:
resolution: {integrity: sha512-1gLHWyfVoRDsHieO+CaeYe7jSo/MT7D7lhaXUiwwbuR5BwQxORs0f1tAwUSQr3YbxRXJvxHM/PA5FfPQRnsPeQ==}
dev: false
/chalk/2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
@ -1469,7 +1484,6 @@ packages:
/electron-to-chromium/1.4.137:
resolution: {integrity: sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==}
dev: false
/emoji-regex/9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
@ -1525,7 +1539,6 @@ packages:
/escalade/3.1.1:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'}
dev: false
/escape-string-regexp/1.0.5:
resolution: {integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=}
@ -1896,6 +1909,10 @@ packages:
mime-types: 2.1.35
dev: false
/fraction.js/4.2.0:
resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
dev: true
/fs.realpath/1.0.0:
resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=}
@ -2500,13 +2517,17 @@ packages:
/node-releases/2.0.4:
resolution: {integrity: sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==}
dev: false
/normalize-path/3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
dev: true
/normalize-range/0.1.2:
resolution: {integrity: sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=}
engines: {node: '>=0.10.0'}
dev: true
/object-assign/4.1.1:
resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=}
engines: {node: '>=0.10.0'}

View File

@ -2,5 +2,6 @@ module.exports = {
plugins: {
"postcss-import": {},
tailwindcss: {},
autoprefixer: {},
},
}

View File

@ -1,13 +1,15 @@
import Head from "next/head"
export const SEOHead: React.FC<{
title: string
siteName: string
title: string | undefined
description?: string | null
image?: string | null
}> = ({ title, description, image }) => {
}> = ({ siteName, title, description, image }) => {
return (
<Head>
<title>{title}</title>
<title>{title ? `${title} - ${siteName}` : siteName}</title>
<meta name="og:site_name" content={siteName} />
<meta name="og:title" content={title} />
<meta name="twitter:title" content={title} />
<meta name="description" content={description || ""} />

View File

@ -2,25 +2,31 @@ import clsx from "clsx"
import Link from "next/link"
import { useRouter } from "next/router"
import React from "react"
import { APP_NAME } from "~/lib/env"
import { getSiteLink } from "~/lib/helpers"
import { trpc } from "~/lib/trpc"
import { SEOHead } from "../common/SEOHead"
import { DashboardIcon } from "../icons/DashboardIcon"
import { UniLink } from "../ui/UniLink"
import { DashboardSidebar } from "./DashboardSidebar"
import { SiteSwitcher } from "./SiteSwitcher"
export function DashboardLayout({ children }: { children: React.ReactNode }) {
export function DashboardLayout({
children,
title,
}: {
children: React.ReactNode
title: string
}) {
const router = useRouter()
const subdomain = router.query.subdomain as string
const subscriptionsQuery = trpc.useQuery(
const { data: subscriptions } = trpc.useQuery(
["user.getSubscriptions", { canManage: true }],
{}
)
const subscriptions = subscriptionsQuery.data
const viewerResult = trpc.useQuery(["auth.viewer"])
const viewer = viewerResult.data
const { data: viewer } = trpc.useQuery(["auth.viewer"])
const links: {
href: string
@ -108,6 +114,7 @@ export function DashboardLayout({ children }: { children: React.ReactNode }) {
return (
<>
<SEOHead title={title} siteName={APP_NAME} />
<div className="flex">
<DashboardSidebar>
<div className="mb-2">

View File

@ -1,84 +1,77 @@
import Link from "next/link"
import { logout } from "~/lib/auth.client"
import { APP_NAME } from "~/lib/env"
import { APP_DESCRIPTION, APP_NAME } from "~/lib/env"
import { useStore } from "~/lib/store"
import { truthy } from "~/lib/utils"
import { SEOHead } from "../common/SEOHead"
import { UniLink } from "../ui/UniLink"
export function MainLayout({
isLoggedIn,
children,
region,
title,
}: {
isLoggedIn: boolean
children?: React.ReactNode
region: string | null
title?: string
}) {
const setLoginModalOpened = useStore((store) => store.setLoginModalOpened)
const links: Array<{ text: string; href?: string; onClick?: () => void }> =
isLoggedIn
? [
{
text: "Dashboard",
href: "/dashboard",
},
{
text: "Log out",
onClick() {
logout()
},
},
]
: [
{
text: "Log in",
onClick() {
setLoginModalOpened(true)
},
},
]
return (
<>
<div className="h-screen flex items-center justify-center">
<div className="-mt-20">
<div className="max-w-screen-md mx-auto px-5">
<div>
<span className="inline-block text-3xl lg:text-7xl px-3 rounded-lg py-2 font-bold bg-indigo-600 text-white">
{APP_NAME}
</span>
</div>
<div className="italic text-zinc-500 text-sm mt-1">
..is under early testing, don{`'`}t use this app in production.
</div>
<div className="space-x-5 mt-10">
{links.map((link) => {
if (link.href) {
return (
<Link href={link.href} key={link.text}>
<a className="font-bold nav-link underline">
{link.text}
</a>
</Link>
)
}
return (
<button
type="button"
className="font-bold nav-link underline"
onClick={link.onClick}
key={link.text}
>
{link.text}
</button>
)
})}
</div>
<div className="mt-10 text-zinc-300 text-xs">
<span className="uppercase">Region: {region}</span>
</div>
<SEOHead
title={title}
siteName={APP_NAME}
description={APP_DESCRIPTION}
/>
<header className="py-10">
<div className="max-w-screen-md px-5 mx-auto flex justify-between items-center">
<h1 className="inline-block text-2xl font-extrabold">{APP_NAME}</h1>
<div className="space-x-5">
{isLoggedIn ? (
<UniLink
onClick={logout}
className="space-x-2 rounded-full px-4 h-8 inline-flex items-center text-sm text-indigo-500 font-medium hover:bg-indigo-50"
>
<span>Sign Out</span>
<svg
className="w-5 h-5"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
d="M3 3a1 1 0 00-1 1v12a1 1 0 102 0V4a1 1 0 00-1-1zm10.293 9.293a1 1 0 001.414 1.414l3-3a1 1 0 000-1.414l-3-3a1 1 0 10-1.414 1.414L14.586 9H7a1 1 0 100 2h7.586l-1.293 1.293z"
clipRule="evenodd"
/>
</svg>
</UniLink>
) : (
<UniLink
onClick={() => {
setLoginModalOpened(true)
}}
className="bg-indigo-100 rounded-full px-4 h-8 inline-flex items-center text-sm text-indigo-500 font-medium"
>
Sign In
</UniLink>
)}
</div>
</div>
</div>
</header>
{children}
<footer className="mt-10 text-sm font-medium text-zinc-500">
<div className="max-w-screen-md px-5 mx-auto">
<span>&copy; {APP_NAME}</span>
<span className="mx-3">·</span>
<span>
Region: <span className="uppercase">{region}</span>
</span>
</div>
</footer>
</>
)
}

View File

@ -68,9 +68,6 @@ export const SiteHeader: React.FC<{
{
label: "Sign out",
onClick() {
if (!confirm(`Are you sure you want to log out?`)) {
return
}
logout()
},
},

View File

@ -28,12 +28,11 @@ export const SiteLayout: React.FC<SiteLayoutProps> = ({
children,
title,
}) => {
const docTitle = title ? `${title} - ${site.name}` : site.name
return (
<>
<SEOHead
title={docTitle}
title={title || ""}
siteName={site.name}
description={site.description}
image={getUserContentsUrl(site.icon)}
/>

View File

@ -56,7 +56,7 @@
.prose a {
@apply text-indigo-600;
@apply underline;
@apply hover:underline;
}
.prose pre {

View File

@ -1,6 +1,8 @@
import { OUR_DOMAIN } from "./env"
export const logout = () => {
if (!confirm(`Are you sure you want to log out?`)) return
const url = new URL(`${location.protocol}//${OUR_DOMAIN}/api/logout`)
if (location.host !== OUR_DOMAIN) {
url.searchParams.set(

View File

@ -4,3 +4,4 @@ export const APP_NAME = process.env.NEXT_PUBLIC_APP_NAME
export const OUR_DOMAIN = process.env.NEXT_PUBLIC_OUR_DOMAIN
export const SITE_URL = `${IS_PROD ? "https" : "http"}://${OUR_DOMAIN}`
export const R2_URL = process.env.NEXT_PUBLIC_R2_URL
export const APP_DESCRIPTION = process.env.APP_DESCRIPTION

View File

@ -50,7 +50,7 @@ export default function AccountProfilePage() {
}, [viewer.data, setValue])
return (
<DashboardLayout>
<DashboardLayout title="Account">
<SettingsLayout title="Account" type="account">
{viewer.data && (
<div>

View File

@ -167,7 +167,7 @@ export default function SubdomainEditor() {
}, [page])
return (
<DashboardLayout>
<DashboardLayout title="Editor">
<DashboardMain fullWidth>
<header className="flex justify-between absolute top-0 left-0 right-0 z-10 px-5 h-14 border-b items-center text-sm">
<div></div>

View File

@ -1,10 +1,48 @@
import { useRouter } from "next/router"
import { DashboardLayout } from "~/components/dashboard/DashboardLayout"
import { DashboardMain } from "~/components/dashboard/DashboardMain"
import { UniLink } from "~/components/ui/UniLink"
export default function SubdomainIndex() {
const router = useRouter()
const subdomain = router.query.subdomain as string
return (
<DashboardLayout>
<DashboardMain>hi</DashboardMain>
<DashboardLayout title="Dashboard">
<DashboardMain>
<div className="prose max-w-screen-md">
<p>
<svg className="w-8 h-8" viewBox="0 0 24 24">
<path
fill="currentColor"
d="M7.03 4.95L3.5 8.5c-3.33 3.31-3.33 8.69 0 12s8.69 3.33 12 0l6-6c1-.97 1-2.56 0-3.54c-.1-.12-.23-.23-.37-.32l.37-.39c1-.97 1-2.56 0-3.54c-.14-.16-.33-.3-.5-.41c.38-.92.21-2.02-.54-2.77c-.87-.87-2.22-.96-3.2-.28a2.517 2.517 0 0 0-3.88-.42l-2.51 2.51c-.09-.14-.2-.27-.32-.39a2.53 2.53 0 0 0-3.52 0m1.41 1.42c.2-.2.51-.2.71 0s.2.51 0 .71l-3.18 3.18a3 3 0 0 1 0 4.24l1.41 1.41a5.004 5.004 0 0 0 1.12-5.36l6.3-6.3c.2-.2.51-.2.7 0s.21.51 0 .71l-4.59 4.6l1.41 1.41l6.01-6.01c.2-.2.51-.2.71 0c.2.2.2.51 0 .71l-6.01 6.01l1.41 1.41l4.95-4.95c.2-.2.51-.2.71 0c.2.2.2.51 0 .71l-5.66 5.65l1.41 1.42l3.54-3.54c.2-.2.51-.2.71 0c.2.2.2.51 0 .71l-6 6.01c-2.54 2.54-6.65 2.54-9.19 0s-2.54-6.65 0-9.19l3.53-3.54M23 17c0 3.31-2.69 6-6 6v-1.5c2.5 0 4.5-2 4.5-4.5H23M1 7c0-3.31 2.69-6 6-6v1.5c-2.5 0-4.5 2-4.5 4.5H1Z"
></path>
</svg>
</p>
<p>Hello there,</p>
<p>
This page is quite empty for now, but we will polish it very soon!
Maybe some useful analytics!
</p>
<p>Here{`'`}re some useful links:</p>
<ul>
<li>
<UniLink href={`/dashboard/${subdomain}/editor?type=post`}>
Create a Post
</UniLink>
</li>
<li>
<UniLink href={`/dashboard/${subdomain}/settings/general`}>
Change Site Name or Icon
</UniLink>
</li>
<li>
<UniLink href={`/dashboard/${subdomain}/account/profile`}>
Profile Settings
</UniLink>
</li>
</ul>
</div>
</DashboardMain>
</DashboardLayout>
)
}

View File

@ -3,7 +3,7 @@ import { PagesManager } from "~/components/dashboard/PagesManager"
export default function SubdomainPages() {
return (
<DashboardLayout>
<DashboardLayout title="Pages">
<PagesManager isPost={false} />
</DashboardLayout>
)

View File

@ -3,7 +3,7 @@ import { PagesManager } from "~/components/dashboard/PagesManager"
export default function SubdomainPosts() {
return (
<DashboardLayout>
<DashboardLayout title="Posts">
<PagesManager isPost={true} />
</DashboardLayout>
)

View File

@ -52,9 +52,10 @@ export default function SettingsDomainsPage() {
}
}, [form, siteResult.data])
const title = "Site Settings"
return (
<DashboardLayout>
<SettingsLayout title="Site Settings" type="site">
<DashboardLayout title={"Domains"}>
<SettingsLayout title={"Site Settings"} type="site">
<form onSubmit={handleSubmit}>
<div className="">
<Input

View File

@ -52,7 +52,7 @@ export default function SiteSettingsGeneralPage() {
}, [updateSite])
return (
<DashboardLayout>
<DashboardLayout title="Site Settings">
<SettingsLayout title="Site Settings" type="site">
{site && (
<div>

View File

@ -1,6 +1,6 @@
import { Button } from "~/components/ui/Button"
import { Input } from "~/components/ui/Input"
import { FormEvent, useEffect, useMemo, useState } from "react"
import { ChangeEvent, FormEvent, useEffect, useMemo, useState } from "react"
import toast from "react-hot-toast"
import { SettingsLayout } from "~/components/dashboard/SettingsLayout"
import { useRouter } from "next/router"
@ -40,7 +40,9 @@ const SortableNavigationItem: React.FC<{
required
id={`${item.id}-label`}
value={item.label}
onChange={(e) => updateItem(item.id, { label: e.target.value })}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
updateItem(item.id, { label: e.target.value })
}
/>
<Input
label="URL"
@ -50,7 +52,9 @@ const SortableNavigationItem: React.FC<{
value={item.url}
pattern="(https?://|/).+"
title="URL must start with / or http:// or https://"
onChange={(e) => updateItem(item.id, { url: e.target.value })}
onChange={(e: ChangeEvent<HTMLInputElement>) =>
updateItem(item.id, { url: e.target.value })
}
/>
<div className="flex items-end relative -top-[5px]">
<Button onClick={() => removeItem(item.id)} variantColor="red">
@ -122,7 +126,7 @@ export default function SiteSettingsNavigationPage() {
}, [updateSite, trpcContext, subdomain])
return (
<DashboardLayout>
<DashboardLayout title="Navigation">
<SettingsLayout title="Site Settings" type="site">
<form onSubmit={handleSubmit}>
<div className="bg-zinc-50 rounded-lg overflow-hidden">

View File

@ -3,9 +3,10 @@ import { useRouter } from "next/router"
import { useEffect } from "react"
import { useForm } from "react-hook-form"
import toast from "react-hot-toast"
import { SEOHead } from "~/components/common/SEOHead"
import { Button } from "~/components/ui/Button"
import { Input } from "~/components/ui/Input"
import { OUR_DOMAIN } from "~/lib/env"
import { APP_NAME, OUR_DOMAIN } from "~/lib/env"
import { trpc } from "~/lib/trpc"
export default function NewSitePage() {
@ -35,62 +36,65 @@ export default function NewSitePage() {
}, [createSite, router])
return (
<div>
<header className="px-5 text-sm md:px-14 flex justify-between items-start py-10">
<Link href="/dashboard">
<a className="flex space-x-1 items-center">
<svg
className="w-4 h-4"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
clipRule="evenodd"
<>
<SEOHead title="New Site" siteName={APP_NAME} />
<div>
<header className="px-5 text-sm md:px-14 flex justify-between items-start py-10">
<Link href="/dashboard">
<a className="flex space-x-1 items-center">
<svg
className="w-4 h-4"
fill="currentColor"
viewBox="0 0 20 20"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
d="M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z"
clipRule="evenodd"
/>
</svg>
<span>Back to dashboard</span>
</a>
</Link>
<div>
<div className="text-zinc-400">Logged in as:</div>
<div>{viewer.data?.email}</div>
</div>
</header>
<div className="max-w-sm mx-auto mt-20">
<h2 className="text-3xl mb-10 text-center">Create a new site</h2>
<form className="space-y-5" onSubmit={handleSubmit}>
<div>
<Input
id="name"
label="Site Name"
isBlock
required
maxLength={30}
{...form.register("name", {})}
/>
</svg>
<span>Back to dashboard</span>
</a>
</Link>
<div>
<div className="text-zinc-400">Logged in as:</div>
<div>{viewer.data?.email}</div>
</div>
<div>
<Input
id="subdomain"
label="Subdomain"
isBlock
required
addon={`.${OUR_DOMAIN}`}
minLength={3}
maxLength={26}
{...form.register("subdomain", {})}
/>
</div>
<div>
<Button type="submit" isBlock isLoading={createSite.isLoading}>
Create
</Button>
</div>
</form>
</div>
</header>
<div className="max-w-sm mx-auto mt-20">
<h2 className="text-3xl mb-10 text-center">Create a new site</h2>
<form className="space-y-5" onSubmit={handleSubmit}>
<div>
<Input
id="name"
label="Site Name"
isBlock
required
maxLength={30}
{...form.register("name", {})}
/>
</div>
<div>
<Input
id="subdomain"
label="Subdomain"
isBlock
required
addon={`.${OUR_DOMAIN}`}
minLength={3}
maxLength={26}
{...form.register("subdomain", {})}
/>
</div>
<div>
<Button type="submit" isBlock isLoading={createSite.isLoading}>
Create
</Button>
</div>
</form>
</div>
</div>
</>
)
}

View File

@ -1,11 +1,15 @@
import { GetServerSideProps } from "next"
import { DashboardIcon } from "~/components/icons/DashboardIcon"
import { MainLayout } from "~/components/main/MainLayout"
import { UniLink } from "~/components/ui/UniLink"
import { getAuthUser } from "~/lib/auth.server"
import { FLY_REGION } from "~/lib/env.server"
import { useStore } from "~/lib/store"
export const getServerSideProps: GetServerSideProps = async (ctx) => {
const user = await getAuthUser(ctx.req)
const isLoggedIn = !!user
return {
props: {
isLoggedIn,
@ -21,5 +25,47 @@ export default function Home({
isLoggedIn: boolean
region: string | null
}) {
return <MainLayout isLoggedIn={isLoggedIn} region={region}></MainLayout>
const setLoginModalOpened = useStore((store) => store.setLoginModalOpened)
return (
<MainLayout isLoggedIn={isLoggedIn} region={region}>
<section>
<div className="max-w-screen-md px-5 mx-auto">
<div className="bg-zinc-50 rounded-xl p-10">
<h2 className="text-5xl font-extrabold">
Content Creating for
<br />
Absolutely Everyone
</h2>
<h3 className="mt-5 text-zinc-500">
Meet Proselog, the open-source blogging and
<br />
newsletter platform for everyone. Focus on writing, not
distractions.
</h3>
<div className="mt-10">
{isLoggedIn ? (
<UniLink
href="/dashboard"
className="text-indigo-500 inline-flex items-center space-x-2 hover:text-indigo-600"
>
<DashboardIcon />
<span>Dashboard</span>
</UniLink>
) : (
<UniLink
onClick={() => {
setLoginModalOpened(true)
}}
className="bg-indigo-500 hover:bg-indigo-600 rounded-full px-4 h-8 inline-flex items-center text-sm text-white font-medium"
>
Getting Started
</UniLink>
)}
</div>
</div>
</div>
</section>
</MainLayout>
)
}

View File

@ -3,6 +3,7 @@ import { z } from "zod"
import { prismaPrimary } from "~/lib/db.server"
import { sendLoginEmail } from "~/lib/mailgun.server"
import { createRouter } from "~/lib/trpc.server"
import { getViewer } from "~/lib/viewer"
export const authRouter = createRouter()
.query("viewer", {
@ -17,7 +18,7 @@ export const authRouter = createRouter()
})
.nullable(),
async resolve({ ctx }) {
return ctx.user || null
return getViewer(ctx.user)
},
})
.mutation("requestLoginLink", {

18
types.d.ts vendored
View File

@ -1,24 +1,18 @@
declare interface ServerEnv {
declare interface CustomEnv {
// Additional environment variables
APP_NAME: string
NEXT_PUBLIC_APP_NAME: string
NEXT_PUBLIC_R2_URL: string
DATABASE_URL: string
AUTH_COOKIE_NAME: string
OUR_DOMAIN: string
NEXT_PUBLIC_OUR_DOMAIN: string
MAILGUN_APIKEY: string
MAILGUN_DOMAIN: string
FLY_REGION?: string
PRIMARY_REGION?: string
ENCRYPT_SECRET: string
NEXT_PUBLIC_R2_URL: string
R2_API_TOKEN: string
}
declare interface BrowserEnv {
APP_NAME: string
OUR_DOMAIN: string
R2_URL: string
}
declare namespace NodeJS {
interface ProcessEnv extends ServerEnv {}
interface ProcessEnv extends CustomEnv {}
}