@stacksjs/defaults 0.72.49 → 0.72.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ide/vscode/package.json +1 -1
- package/lang/de.yml +0 -1
- package/package.json +2 -2
- package/resources/components/Dashboard/Auth/ForgotPasswordDashboard.stx +8 -0
- package/resources/components/Dashboard/Auth/Login.stx +8 -0
- package/resources/components/Dashboard/Auth/LoginDashboard.stx +5 -1
- package/resources/components/Dashboard/Auth/MagicLink.stx +94 -0
- package/resources/components/Dashboard/Auth/Register.stx +7 -0
- package/resources/components/Dashboard/Auth/RegisterDashboard.stx +5 -1
- package/resources/components/Dashboard/Auth/ResetPassword.stx +163 -0
- package/resources/components/Dashboard/Auth/ResetPasswordDashboard.stx +95 -0
- package/resources/layouts/403.stx +15 -148
- package/resources/layouts/404.stx +4 -1
- package/resources/views/auth/magic/[token].stx +24 -0
- package/resources/views/errors/404.stx +36 -0
- package/resources/views/forgot-password.stx +13 -0
- package/resources/views/login.stx +68 -0
- package/resources/views/password/reset/[token].stx +18 -0
- package/resources/views/register.stx +64 -0
- package/views/[...all].stx +0 -7
- package/views/about.md +0 -3
- package/views/auth/login.stx +0 -1
- package/views/auth/magic/[token].stx +0 -88
- package/views/auth/signup.stx +0 -120
- package/views/forum/category.stx +0 -92
- package/views/forum/index.stx +0 -209
- package/views/forum/new-topic.stx +0 -113
- package/views/forum/profile.stx +0 -1
- package/views/forum/topic.stx +0 -143
- package/views/hello-world/[name].stx +0 -47
- package/views/index.stx +0 -21
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
import { config } from '@stacksjs/config'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Where a magic sign-in link lands, at `/auth/magic/{token}`.
|
|
6
|
+
*
|
|
7
|
+
* The logic sits in the component, like every other auth page here.
|
|
8
|
+
*
|
|
9
|
+
* It used to sit in a page-level `<script client>` that read a `useRef` from
|
|
10
|
+
* inside a top-level `effect`, and that combination left the page inert: the
|
|
11
|
+
* setup registered, no directive bound, and the page rendered perfectly while
|
|
12
|
+
* its button did nothing. The cause was in stx - `useRef()` returned an object
|
|
13
|
+
* rather than a callable, so `shell()` threw out of the effect and out of the
|
|
14
|
+
* setup function, taking every binding with it. Fixed upstream in stx 0.2.217;
|
|
15
|
+
* the ref is also gone from here, because a template ref is not reactive and
|
|
16
|
+
* reading one during setup only ever answers null.
|
|
17
|
+
*
|
|
18
|
+
* `autoConsume` is passed as an attribute because it is a server decision a
|
|
19
|
+
* client script cannot read.
|
|
20
|
+
*/
|
|
21
|
+
const autoConsume = config.auth.magicLink?.confirmInteraction !== true
|
|
22
|
+
</script>
|
|
23
|
+
|
|
24
|
+
<MagicLink autoConsume="{{ autoConsume }}" />
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
// The frontend's not-found page. When no view matches a URL, stx-serve looks
|
|
3
|
+
// for a route at `/404` or `/errors/404` first. Without this file it falls
|
|
4
|
+
// through to its own generic page, which carries none of the app's design
|
|
5
|
+
// (and, on the server `stx build` produces, to the bare string "Not Found").
|
|
6
|
+
//
|
|
7
|
+
// Same split as the framework's production error page in
|
|
8
|
+
// @stacksjs/error-handling, so a 404 looks the same whether the router or the
|
|
9
|
+
// views server answered it. The scene is Laravel 5.7's 404 illustration (MIT),
|
|
10
|
+
// served from public/svgs.
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<div class="flex flex-col md:flex-row min-h-screen bg-neutral-50 dark:bg-neutral-900">
|
|
14
|
+
<div class="overflow-hidden md:order-2 h-56 sm:h-72 md:h-auto md:w-1/2 bg-neutral-200 dark:bg-neutral-800">
|
|
15
|
+
<img src="/svgs/404.svg" alt="" class="object-cover h-full w-full">
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<section class="flex md:order-1 flex-1 flex-col items-start justify-center md:flex-none px-8 py-12 md:px-16 md:w-1/2">
|
|
19
|
+
<div class="font-extrabold text-6xl text-neutral-950 tracking-tight md:text-8xl dark:text-white">404</div>
|
|
20
|
+
|
|
21
|
+
<div class="my-6 h-1 w-14 bg-blue-600 dark:bg-blue-500 rounded-full"></div>
|
|
22
|
+
|
|
23
|
+
<h1 class="mb-2 font-semibold text-2xl text-neutral-950 dark:text-white">Page not found</h1>
|
|
24
|
+
|
|
25
|
+
<p class="mb-8 max-w-md text-neutral-500 dark:text-neutral-400">
|
|
26
|
+
The page you are looking for does not exist, or it has moved.
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
<a
|
|
30
|
+
href="/"
|
|
31
|
+
class="inline-block px-5 py-2.5 font-medium text-neutral-950 text-sm dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800 border border-neutral-300 rounded-lg dark:border-neutral-700"
|
|
32
|
+
>
|
|
33
|
+
Back to home
|
|
34
|
+
</a>
|
|
35
|
+
</section>
|
|
36
|
+
</div>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
/**
|
|
3
|
+
* The site's forgot-password page, at `/forgot-password` - the address the
|
|
4
|
+
* sign-in card's "Forgot password?" link has always pointed at, and which
|
|
5
|
+
* had nothing behind it outside the dashboard.
|
|
6
|
+
*
|
|
7
|
+
* The container posts to `/password/forgot`, which answers the same neutral
|
|
8
|
+
* 202 whether or not the address has an account, so this page must never
|
|
9
|
+
* report back whether it matched.
|
|
10
|
+
*/
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<ForgotPasswordDashboard />
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
/**
|
|
3
|
+
* The site's sign-in page, at `/login`.
|
|
4
|
+
*
|
|
5
|
+
* It lived at `defaults/views/auth/login.stx` and was one line mounting the
|
|
6
|
+
* presentational `Login` component, from a directory no server serves. That
|
|
7
|
+
* component only emits `submit`, so even reachable it would have rendered a
|
|
8
|
+
* form that swallowed every sign-in. The container below is what listens: it
|
|
9
|
+
* calls `useAuth().login`, surfaces the error, and honours `?redirect=`. Its
|
|
10
|
+
* name is where the auth components happen to live, not where it can run.
|
|
11
|
+
*
|
|
12
|
+
* `POST /login` reaches the API without a proxy rule of its own, because the
|
|
13
|
+
* views server forwards every mutating verb to bun-router (DEFAULT_API_METHODS
|
|
14
|
+
* in core/server/src/proxy.ts). GET `/login` is this page.
|
|
15
|
+
*
|
|
16
|
+
* The social buttons go in through the card's `social` slot rather than after
|
|
17
|
+
* it, so they sit with the credentials instead of below the sign-up line.
|
|
18
|
+
* `configuredSocialProviders()` knows each provider's own required config, so
|
|
19
|
+
* a provider missing credentials never reaches a visitor as a button that
|
|
20
|
+
* fails at the redirect. Adding credentials to `config/services.ts` is the
|
|
21
|
+
* whole of what turns one on. Icons come from hugeicons, the collection Stacks
|
|
22
|
+
* defaults to; swap the map if your app standardises on another.
|
|
23
|
+
*/
|
|
24
|
+
import { configuredSocialProviders } from '@stacksjs/socials'
|
|
25
|
+
|
|
26
|
+
const PROVIDER_ICONS = {
|
|
27
|
+
apple: 'i-hugeicons-apple',
|
|
28
|
+
facebook: 'i-hugeicons-facebook-01',
|
|
29
|
+
github: 'i-hugeicons-github',
|
|
30
|
+
google: 'i-hugeicons-google',
|
|
31
|
+
twitter: 'i-hugeicons-new-twitter',
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const socialSignIn = configuredSocialProviders().map(provider => ({
|
|
35
|
+
label: provider.label,
|
|
36
|
+
href: `/auth/${provider.name}/redirect`,
|
|
37
|
+
icon: PROVIDER_ICONS[provider.name] ?? 'i-hugeicons-user-circle',
|
|
38
|
+
}))
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<LoginDashboard>
|
|
42
|
+
<template #social>
|
|
43
|
+
@if (socialSignIn.length)
|
|
44
|
+
<div class="mt-6">
|
|
45
|
+
<div class="relative">
|
|
46
|
+
<div class="flex absolute inset-0 items-center" aria-hidden="true">
|
|
47
|
+
<div class="w-full border-neutral-200 border-t dark:border-neutral-700"></div>
|
|
48
|
+
</div>
|
|
49
|
+
<div class="flex relative justify-center text-sm">
|
|
50
|
+
<span class="px-4 text-neutral-500 dark:text-neutral-400 bg-white dark:bg-neutral-800">Or continue with</span>
|
|
51
|
+
</div>
|
|
52
|
+
</div>
|
|
53
|
+
|
|
54
|
+
<div class="grid gap-3 mt-6 {{ socialSignIn.length > 1 ? 'grid-cols-2' : 'grid-cols-1' }}">
|
|
55
|
+
@foreach (socialSignIn as provider)
|
|
56
|
+
<a
|
|
57
|
+
href="{{ provider.href }}"
|
|
58
|
+
class="flex gap-2 items-center justify-center px-3 py-2 font-medium text-neutral-900 text-sm dark:text-white bg-white dark:bg-neutral-800 hover:bg-neutral-50 dark:hover:bg-neutral-700 border border-neutral-300 rounded-lg dark:border-neutral-600"
|
|
59
|
+
>
|
|
60
|
+
<i class="h-5 w-5 {{ provider.icon }}" aria-hidden="true"></i>
|
|
61
|
+
<span>{{ provider.label }}</span>
|
|
62
|
+
</a>
|
|
63
|
+
@endforeach
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
@endif
|
|
67
|
+
</template>
|
|
68
|
+
</LoginDashboard>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
/**
|
|
3
|
+
* Where a mailed password-reset link lands, at `/password/reset/{token}`.
|
|
4
|
+
*
|
|
5
|
+
* The framework has been sending people here for as long as it has had a
|
|
6
|
+
* reset mailer - `core/auth/src/password/reset.ts` builds the link from
|
|
7
|
+
* `config.auth.passwordReset.url`, whose default is
|
|
8
|
+
* `/password/reset/{token}?email={email}` - and nothing has ever served the
|
|
9
|
+
* address. Every reset email ended at a 404, which made the whole flow
|
|
10
|
+
* (the send endpoint, the token store, the reset action, the mail template)
|
|
11
|
+
* unreachable from a browser.
|
|
12
|
+
*
|
|
13
|
+
* An app that points `config.auth.passwordReset.url` somewhere else is free
|
|
14
|
+
* to keep its own page; this is the page the default link needs.
|
|
15
|
+
*/
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<ResetPasswordDashboard />
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<script server>
|
|
2
|
+
/**
|
|
3
|
+
* The site's sign-up page, at `/register`.
|
|
4
|
+
*
|
|
5
|
+
* It lived at `defaults/views/auth/signup.stx`, in a directory no server
|
|
6
|
+
* serves, and carried its own hand-written form whose `action="#"` posted
|
|
7
|
+
* nowhere. It also declared `id="password"` twice and named the confirmation
|
|
8
|
+
* field `password` as well, so the two inputs collided. The container below is
|
|
9
|
+
* what actually registers: it calls `useAuth().register`, surfaces the error,
|
|
10
|
+
* and honours `?redirect=`. Its name is where the auth components happen to
|
|
11
|
+
* live, not where it can run.
|
|
12
|
+
*
|
|
13
|
+
* The social block is what that page did get right, kept here and moved inside
|
|
14
|
+
* the card through its `social` slot. `configuredSocialProviders()` knows each
|
|
15
|
+
* provider's own required config (Apple has no clientSecret and is validated
|
|
16
|
+
* on its signing key instead), so what renders is exactly the set that will
|
|
17
|
+
* complete a sign-in. Adding credentials to `config/services.ts` is the whole
|
|
18
|
+
* of what turns one on.
|
|
19
|
+
*/
|
|
20
|
+
import { configuredSocialProviders } from '@stacksjs/socials'
|
|
21
|
+
|
|
22
|
+
const PROVIDER_ICONS = {
|
|
23
|
+
apple: 'i-hugeicons-apple',
|
|
24
|
+
facebook: 'i-hugeicons-facebook-01',
|
|
25
|
+
github: 'i-hugeicons-github',
|
|
26
|
+
google: 'i-hugeicons-google',
|
|
27
|
+
twitter: 'i-hugeicons-new-twitter',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const socialSignUp = configuredSocialProviders().map(provider => ({
|
|
31
|
+
label: provider.label,
|
|
32
|
+
href: `/auth/${provider.name}/redirect`,
|
|
33
|
+
icon: PROVIDER_ICONS[provider.name] ?? 'i-hugeicons-user-circle',
|
|
34
|
+
}))
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<RegisterDashboard>
|
|
38
|
+
<template #social>
|
|
39
|
+
@if (socialSignUp.length)
|
|
40
|
+
<div class="mt-6">
|
|
41
|
+
<div class="relative">
|
|
42
|
+
<div class="flex absolute inset-0 items-center" aria-hidden="true">
|
|
43
|
+
<div class="w-full border-neutral-200 border-t dark:border-neutral-700"></div>
|
|
44
|
+
</div>
|
|
45
|
+
<div class="flex relative justify-center text-sm">
|
|
46
|
+
<span class="px-4 text-neutral-500 dark:text-neutral-400 bg-white dark:bg-neutral-800">Or continue with</span>
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
|
|
50
|
+
<div class="grid gap-3 mt-6 {{ socialSignUp.length > 1 ? 'grid-cols-2' : 'grid-cols-1' }}">
|
|
51
|
+
@foreach (socialSignUp as provider)
|
|
52
|
+
<a
|
|
53
|
+
href="{{ provider.href }}"
|
|
54
|
+
class="flex gap-2 items-center justify-center px-3 py-2 font-medium text-neutral-900 text-sm dark:text-white bg-white dark:bg-neutral-800 hover:bg-neutral-50 dark:hover:bg-neutral-700 border border-neutral-300 rounded-lg dark:border-neutral-600"
|
|
55
|
+
>
|
|
56
|
+
<i class="h-5 w-5 {{ provider.icon }}" aria-hidden="true"></i>
|
|
57
|
+
<span>{{ provider.label }}</span>
|
|
58
|
+
</a>
|
|
59
|
+
@endforeach
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
@endif
|
|
63
|
+
</template>
|
|
64
|
+
</RegisterDashboard>
|
package/views/[...all].stx
DELETED
package/views/about.md
DELETED
package/views/auth/login.stx
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<Login />
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
import { config } from '@stacksjs/config'
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* The magic-link interstitial. The email's GET lands here and this page
|
|
6
|
-
* POSTs the token to the consume endpoint - a GET must never consume,
|
|
7
|
-
* because mail-security scanners prefetch links and would burn the
|
|
8
|
-
* single-use token before the person ever taps it.
|
|
9
|
-
*
|
|
10
|
-
* `confirmInteraction` renders a button instead of auto-submitting, for
|
|
11
|
-
* environments whose scanners execute page scripts too.
|
|
12
|
-
*/
|
|
13
|
-
const autoConsume = config.auth.magicLink?.confirmInteraction !== true
|
|
14
|
-
</script>
|
|
15
|
-
|
|
16
|
-
<script client>
|
|
17
|
-
const route = useRoute()
|
|
18
|
-
const status = state('ready') // ready | working | done | failed
|
|
19
|
-
const message = state('')
|
|
20
|
-
const shell = useRef('shell')
|
|
21
|
-
|
|
22
|
-
async function consume() {
|
|
23
|
-
if (status() === 'working' || status() === 'done')
|
|
24
|
-
return
|
|
25
|
-
|
|
26
|
-
status.set('working')
|
|
27
|
-
try {
|
|
28
|
-
const reply = await fetch('/auth/magic-link/consume', {
|
|
29
|
-
method: 'POST',
|
|
30
|
-
headers: { 'Content-Type': 'application/json' },
|
|
31
|
-
credentials: 'same-origin',
|
|
32
|
-
body: JSON.stringify({ token: String(route.params.token || '') }),
|
|
33
|
-
})
|
|
34
|
-
const body = await reply.json().catch(() => ({}))
|
|
35
|
-
|
|
36
|
-
if (!reply.ok) {
|
|
37
|
-
status.set('failed')
|
|
38
|
-
message.set(body.message || body.error || 'That sign-in link is not valid.')
|
|
39
|
-
return
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
status.set('done')
|
|
43
|
-
const redirect = String(body.redirect_to || '/')
|
|
44
|
-
navigate(redirect.startsWith('/') && !redirect.startsWith('//') ? redirect : '/')
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
status.set('failed')
|
|
48
|
-
message.set('Something went wrong. Request a new link and try again.')
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
effect(() => {
|
|
53
|
-
// Auto-consume only when the server said so - the flag rides a data
|
|
54
|
-
// attribute because client scripts cannot read server config directly.
|
|
55
|
-
if (shell() && shell().dataset.autoConsume === 'true')
|
|
56
|
-
consume()
|
|
57
|
-
})
|
|
58
|
-
</script>
|
|
59
|
-
|
|
60
|
-
<template>
|
|
61
|
-
<main ref="shell" data-auto-consume="{{ autoConsume }}" class="min-h-[100dvh] flex items-center justify-center px-6">
|
|
62
|
-
<div class="w-full max-w-sm text-center">
|
|
63
|
-
<div :if="status() === 'failed'">
|
|
64
|
-
<div class="mx-auto h-12 w-12 rounded-full bg-red-50 flex items-center justify-center">
|
|
65
|
-
<span class="h-6 w-6 text-red-500 i-hugeicons-alert-02"></span>
|
|
66
|
-
</div>
|
|
67
|
-
<h1 class="mt-5 text-xl font-semibold tracking-tight">Sign-in link problem</h1>
|
|
68
|
-
<p class="mt-2 text-[15px] text-gray-600">{{ message() }}</p>
|
|
69
|
-
<a href="/login" class="mt-6 inline-block rounded-lg px-5 py-2.5 font-medium bg-gray-900 text-white">Back to sign in</a>
|
|
70
|
-
</div>
|
|
71
|
-
<div :else-if="status() === 'working' || status() === 'done'">
|
|
72
|
-
<div class="mx-auto h-12 w-12 rounded-full bg-gray-100 flex items-center justify-center">
|
|
73
|
-
<span class="h-6 w-6 text-gray-500 animate-spin i-hugeicons-loading-03"></span>
|
|
74
|
-
</div>
|
|
75
|
-
<h1 class="mt-5 text-xl font-semibold tracking-tight">Signing you in</h1>
|
|
76
|
-
<p class="mt-2 text-[15px] text-gray-600">One moment.</p>
|
|
77
|
-
</div>
|
|
78
|
-
<div :else>
|
|
79
|
-
<div class="mx-auto h-12 w-12 rounded-full bg-gray-100 flex items-center justify-center">
|
|
80
|
-
<span class="h-6 w-6 text-gray-600 i-hugeicons-mail-open-01"></span>
|
|
81
|
-
</div>
|
|
82
|
-
<h1 class="mt-5 text-xl font-semibold tracking-tight">Continue to sign in</h1>
|
|
83
|
-
<p class="mt-2 text-[15px] text-gray-600">Tap below to finish signing in with your emailed link.</p>
|
|
84
|
-
<button type="button" @click="consume" class="mt-6 rounded-lg px-6 py-3 font-medium bg-gray-900 text-white transition-transform active:scale-[0.98]">Continue</button>
|
|
85
|
-
</div>
|
|
86
|
-
</div>
|
|
87
|
-
</main>
|
|
88
|
-
</template>
|
package/views/auth/signup.stx
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
/**
|
|
3
|
-
* The providers whose buttons are worth rendering.
|
|
4
|
-
*
|
|
5
|
-
* `configuredSocialProviders()` knows each provider's own required config,
|
|
6
|
-
* so a provider missing credentials never reaches a visitor as a button
|
|
7
|
-
* that fails at the redirect. Adding credentials to `config/services.ts`
|
|
8
|
-
* is the whole of what turns one on.
|
|
9
|
-
*
|
|
10
|
-
* Icons come from hugeicons, the collection Stacks defaults to. Swap the
|
|
11
|
-
* map if your app standardises on another one.
|
|
12
|
-
*/
|
|
13
|
-
import { configuredSocialProviders } from '@stacksjs/socials'
|
|
14
|
-
|
|
15
|
-
const PROVIDER_ICONS = {
|
|
16
|
-
apple: 'i-hugeicons-apple',
|
|
17
|
-
facebook: 'i-hugeicons-facebook-01',
|
|
18
|
-
github: 'i-hugeicons-github',
|
|
19
|
-
google: 'i-hugeicons-google',
|
|
20
|
-
twitter: 'i-hugeicons-new-twitter',
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const socialSignIn = configuredSocialProviders().map(provider => ({
|
|
24
|
-
label: provider.label,
|
|
25
|
-
href: `/auth/${provider.name}/redirect`,
|
|
26
|
-
icon: PROVIDER_ICONS[provider.name] ?? 'i-hugeicons-user-circle',
|
|
27
|
-
}))
|
|
28
|
-
</script>
|
|
29
|
-
|
|
30
|
-
<div class="flex flex-col justify-center py-12 sm:px-6 lg:px-8 min-h-full">
|
|
31
|
-
<div class="sm:mx-auto sm:max-w-md sm:w-full">
|
|
32
|
-
<Logo class="mx-auto h-11 w-auto" />
|
|
33
|
-
<h2 class="mt-6 font-bold leading-9 text-2xl text-center text-gray-900 tracking-tight">
|
|
34
|
-
Sign up to your account
|
|
35
|
-
</h2>
|
|
36
|
-
</div>
|
|
37
|
-
|
|
38
|
-
<div class="mt-10 sm:mx-auto sm:max-w-[480px] sm:w-full">
|
|
39
|
-
<div class="px-6 py-12 sm:px-12 bg-white sm:rounded-lg shadow">
|
|
40
|
-
<form class="space-y-6" action="#" method="POST">
|
|
41
|
-
<div>
|
|
42
|
-
<label for="name" class="block font-medium leading-6 text-gray-900 text-sm">Name</label>
|
|
43
|
-
<div class="mt-2">
|
|
44
|
-
<input id="name" name="name" type="text" autocomplete="name" required class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm placeholder:text-gray-400 border-0 ring-1 ring-gray-300 ring-inset rounded-md focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm">
|
|
45
|
-
</div>
|
|
46
|
-
</div>
|
|
47
|
-
|
|
48
|
-
<div>
|
|
49
|
-
<label for="email" class="block font-medium leading-6 text-gray-900 text-sm">Email address</label>
|
|
50
|
-
<div class="mt-2">
|
|
51
|
-
<input id="email" name="email" type="email" autocomplete="email" required class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm placeholder:text-gray-400 border-0 ring-1 ring-gray-300 ring-inset rounded-md focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm">
|
|
52
|
-
</div>
|
|
53
|
-
</div>
|
|
54
|
-
|
|
55
|
-
<div>
|
|
56
|
-
<label for="password" class="block font-medium leading-6 text-gray-900 text-sm">Password</label>
|
|
57
|
-
<div class="mt-2">
|
|
58
|
-
<input id="password" name="password" type="password" autocomplete="current-password" required class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm placeholder:text-gray-400 border-0 ring-1 ring-gray-300 ring-inset rounded-md focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm">
|
|
59
|
-
</div>
|
|
60
|
-
</div>
|
|
61
|
-
|
|
62
|
-
<div>
|
|
63
|
-
<label for="password" class="block font-medium leading-6 text-gray-900 text-sm">Confirm Password</label>
|
|
64
|
-
<div class="mt-2">
|
|
65
|
-
<input id="password" name="password" type="password" autocomplete="current-password" required class="block py-1.5 w-full text-gray-900 sm:leading-6 sm:text-sm placeholder:text-gray-400 border-0 ring-1 ring-gray-300 ring-inset rounded-md focus:ring-2 focus:ring-blue-600 focus:ring-inset shadow-sm">
|
|
66
|
-
</div>
|
|
67
|
-
</div>
|
|
68
|
-
|
|
69
|
-
<div>
|
|
70
|
-
<div>
|
|
71
|
-
<button type="submit" class="flex justify-center px-3 py-1.5 w-full font-semibold leading-6 text-sm text-white bg-blue-600 hover:bg-blue-500 rounded-md focus-visible:outline focus-visible:outline-2 focus-visible:outline-blue-600 focus-visible:outline-offset-2 shadow-sm">
|
|
72
|
-
Sign up
|
|
73
|
-
</button>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
</form>
|
|
77
|
-
|
|
78
|
-
{{--
|
|
79
|
-
Social sign-in, driven by which providers are actually configured.
|
|
80
|
-
|
|
81
|
-
This block used to be two hardcoded buttons pointing at `href="#"`,
|
|
82
|
-
so a scaffolded app shipped a Google and a GitHub button that both
|
|
83
|
-
did nothing, and offered them whether or not either provider had
|
|
84
|
-
credentials. `configuredSocialProviders()` answers that per
|
|
85
|
-
provider on each provider's own terms (Apple has no clientSecret
|
|
86
|
-
and is validated on its signing key instead), so what renders here
|
|
87
|
-
is exactly the set that will complete a sign-in.
|
|
88
|
-
--}}
|
|
89
|
-
@if (socialSignIn.length)
|
|
90
|
-
<div>
|
|
91
|
-
<div class="relative mt-10">
|
|
92
|
-
<div class="flex absolute inset-0 items-center" aria-hidden="true">
|
|
93
|
-
<div class="w-full border-gray-200 border-t"></div>
|
|
94
|
-
</div>
|
|
95
|
-
<div class="flex relative justify-center font-medium leading-6 text-sm">
|
|
96
|
-
<span class="px-6 text-gray-900 bg-white">Or continue with</span>
|
|
97
|
-
</div>
|
|
98
|
-
</div>
|
|
99
|
-
|
|
100
|
-
<div class="grid gap-4 mt-6 {{ socialSignIn.length > 1 ? 'grid-cols-2' : 'grid-cols-1' }}">
|
|
101
|
-
@foreach (socialSignIn as provider)
|
|
102
|
-
<a
|
|
103
|
-
href="{{ provider.href }}"
|
|
104
|
-
class="flex gap-3 items-center justify-center px-3 py-2 w-full font-semibold text-gray-900 text-sm bg-white hover:bg-gray-50 ring-1 ring-gray-300 ring-inset rounded-md focus-visible:ring-transparent shadow-sm"
|
|
105
|
-
>
|
|
106
|
-
<i class="h-5 w-5 {{ provider.icon }}" aria-hidden="true"></i>
|
|
107
|
-
<span class="font-semibold leading-6 text-sm">{{ provider.label }}</span>
|
|
108
|
-
</a>
|
|
109
|
-
@endforeach
|
|
110
|
-
</div>
|
|
111
|
-
</div>
|
|
112
|
-
@endif
|
|
113
|
-
</div>
|
|
114
|
-
|
|
115
|
-
<p class="mt-10 text-center text-gray-500 text-sm">
|
|
116
|
-
Already have an account?
|
|
117
|
-
<a href="/login" class="font-semibold leading-6 text-blue-600 hover:text-blue-500">Sign in</a>
|
|
118
|
-
</p>
|
|
119
|
-
</div>
|
|
120
|
-
</div>
|
package/views/forum/category.stx
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
<script server>
|
|
2
|
-
const category = ''
|
|
3
|
-
const subcategory = ''
|
|
4
|
-
const filter = ''
|
|
5
|
-
</script>
|
|
6
|
-
<ForumLayout :route="routeType">
|
|
7
|
-
<div class="grid gap-8 grid-cols-1 lg:grid-cols-3">
|
|
8
|
-
<div class="lg:col-span-2">
|
|
9
|
-
<ForumBreadcrumb :items="breadcrumbItems" />
|
|
10
|
-
|
|
11
|
-
<div class="mb-6">
|
|
12
|
-
<div class="flex items-center justify-between px-4 py-3 bg-gray-100 rounded-t-md">
|
|
13
|
-
<div>
|
|
14
|
-
<h1 class="font-bold text-xl">{{ categoryTitle }}</h1>
|
|
15
|
-
<p class="mt-1 text-gray-600 text-sm">{{ categoryDescription }}</p>
|
|
16
|
-
</div>
|
|
17
|
-
|
|
18
|
-
<div>
|
|
19
|
-
<a href="/forum/new-topic" class="px-4 py-2 text-white bg-primary rounded-md hover:opacity-90">New Topic</a>
|
|
20
|
-
</div>
|
|
21
|
-
</div>
|
|
22
|
-
</div>
|
|
23
|
-
|
|
24
|
-
<ForumTopicList :title="listTitle">
|
|
25
|
-
@foreach (topic in topics)
|
|
26
|
-
<ForumTopicItem
|
|
27
|
-
:key="topic.id"
|
|
28
|
-
:title="topic.title"
|
|
29
|
-
:link="topic.link"
|
|
30
|
-
:authorName="topic.authorName"
|
|
31
|
-
:authorAvatar="topic.authorAvatar"
|
|
32
|
-
:createdAt="topic.createdAt"
|
|
33
|
-
:viewCount="topic.viewCount"
|
|
34
|
-
:replyCount="topic.replyCount"
|
|
35
|
-
:likeCount="topic.likeCount"
|
|
36
|
-
:category="topic.category"
|
|
37
|
-
:categoryLink="topic.categoryLink"
|
|
38
|
-
:excerpt="topic.excerpt || ''"
|
|
39
|
-
:isPinned="!!topic.isPinned"
|
|
40
|
-
:isSolved="!!topic.isSolved"
|
|
41
|
-
:lastReplyAuthorName="topic.lastReplyAuthorName || ''"
|
|
42
|
-
:lastReplyAuthorAvatar="topic.lastReplyAuthorAvatar || ''"
|
|
43
|
-
:lastReplyAt="topic.lastReplyAt || ''"
|
|
44
|
-
/>
|
|
45
|
-
@endforeach
|
|
46
|
-
</ForumTopicList>
|
|
47
|
-
|
|
48
|
-
<ForumPagination :currentPage="1" :totalPages="5" />
|
|
49
|
-
</div>
|
|
50
|
-
|
|
51
|
-
<div class="lg:col-span-1">
|
|
52
|
-
<ForumSidebar
|
|
53
|
-
:stats="{
|
|
54
|
-
topics: 540,
|
|
55
|
-
posts: 3287,
|
|
56
|
-
members: 1245,
|
|
57
|
-
newestMember: 'NewUser123'
|
|
58
|
-
}"
|
|
59
|
-
:popularTopics="[
|
|
60
|
-
{
|
|
61
|
-
id: 1,
|
|
62
|
-
title: 'How to implement authentication in a new Stacks.js project?',
|
|
63
|
-
link: '/forum/topic/1',
|
|
64
|
-
replyCount: 3,
|
|
65
|
-
viewCount: 45
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
id: 2,
|
|
69
|
-
title: 'Best practices for database migrations in Stacks.js',
|
|
70
|
-
link: '/forum/topic/3',
|
|
71
|
-
replyCount: 15,
|
|
72
|
-
viewCount: 128
|
|
73
|
-
},
|
|
74
|
-
{
|
|
75
|
-
id: 3,
|
|
76
|
-
title: 'Introducing myself to the community!',
|
|
77
|
-
link: '/forum/topic/2',
|
|
78
|
-
replyCount: 8,
|
|
79
|
-
viewCount: 32
|
|
80
|
-
}
|
|
81
|
-
]"
|
|
82
|
-
:onlineUsers="[
|
|
83
|
-
{ id: 1, name: 'JohnDoe', avatar: '/images/avatars/default.png' },
|
|
84
|
-
{ id: 2, name: 'DatabaseGuru', avatar: '/images/avatars/default.png' },
|
|
85
|
-
{ id: 3, name: 'NewUser123', avatar: '/images/avatars/default.png' },
|
|
86
|
-
{ id: 4, name: 'ExpertUser', avatar: '/images/avatars/default.png' },
|
|
87
|
-
{ id: 5, name: 'StacksMaster', avatar: '/images/avatars/default.png' }
|
|
88
|
-
]"
|
|
89
|
-
/>
|
|
90
|
-
</div>
|
|
91
|
-
</div>
|
|
92
|
-
</ForumLayout>
|