create-nexgen 1.0.4
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/package.json +26 -0
- package/src/index.js +108 -0
- package/template/.dockerignore +14 -0
- package/template/.env +58 -0
- package/template/.env.example +59 -0
- package/template/.prettierignore +5 -0
- package/template/.prettierrc +8 -0
- package/template/README.md +447 -0
- package/template/drizzle.config.ts +29 -0
- package/template/eslint.config.js +52 -0
- package/template/gitignore-stub +24 -0
- package/template/package.json +96 -0
- package/template/public/assets/AuthLayout-CbswhpjJ.js +1 -0
- package/template/public/assets/Button-_7aQ7gHL.js +1 -0
- package/template/public/assets/Input-CLNJXmKc.css +1 -0
- package/template/public/assets/Input-z8GI8Aqo.js +1 -0
- package/template/public/assets/InputPasswordToggle-BxlzVGp3.js +1 -0
- package/template/public/assets/InputPasswordToggle-C77FI9Eg.css +1 -0
- package/template/public/assets/Layout-DotR1sQC.js +1 -0
- package/template/public/assets/Refresh-BdqsPPBC.js +1 -0
- package/template/public/assets/admin-ui-CU34rLdN.js +1 -0
- package/template/public/assets/bootstrap-icons-BeopsB42.woff +0 -0
- package/template/public/assets/bootstrap-icons-mSm7cUeB.woff2 +0 -0
- package/template/public/assets/dashboard-CwybEyLc.js +1 -0
- package/template/public/assets/dashboard-Dc4d-Pi7.css +1 -0
- package/template/public/assets/forgetPassword-CKEJaXsq.js +1 -0
- package/template/public/assets/index-Bleyx5dm.js +64 -0
- package/template/public/assets/index-DUw8E6Yg.css +1 -0
- package/template/public/assets/login-DC7PTlQF.js +1 -0
- package/template/public/assets/realtime-test-BPQdrFym.css +1 -0
- package/template/public/assets/realtime-test-tQZ0rBEJ.js +1 -0
- package/template/public/assets/register-3O7Qs28C.js +1 -0
- package/template/public/assets/resetPassword-A5AzMWKs.js +1 -0
- package/template/public/assets/verifyEmail-DDBEQHOv.js +1 -0
- package/template/public/index.html +17 -0
- package/template/src/database/migrations/mysql/0000_init.sql +73 -0
- package/template/src/database/migrations/mysql/meta/0000_snapshot.json +484 -0
- package/template/src/database/migrations/mysql/meta/_journal.json +13 -0
- package/template/src/database/schema.ts +4 -0
- package/template/src/env.ts +107 -0
- package/template/src/framework/cache/cache.ts +81 -0
- package/template/src/framework/database/connection.ts +168 -0
- package/template/src/framework/database/optional-db-drivers.d.ts +9 -0
- package/template/src/framework/database/paginate.ts +200 -0
- package/template/src/framework/database/schema.ts +26 -0
- package/template/src/framework/database/seed.ts +33 -0
- package/template/src/framework/events/dispatcher.ts +57 -0
- package/template/src/framework/facade.ts +27 -0
- package/template/src/framework/http/app.ts +61 -0
- package/template/src/framework/http/cors.ts +19 -0
- package/template/src/framework/http/logger.ts +85 -0
- package/template/src/framework/http/openapi.ts +34 -0
- package/template/src/framework/http/ratelimiter.ts +13 -0
- package/template/src/framework/http/router.ts +76 -0
- package/template/src/framework/http/static.ts +33 -0
- package/template/src/framework/http/validation.ts +24 -0
- package/template/src/framework/kernel.ts +40 -0
- package/template/src/framework/maker-cli/src/index.mjs +51 -0
- package/template/src/framework/maker-cli/src/levels/level-1/env-db.mjs +57 -0
- package/template/src/framework/maker-cli/src/levels/level-1/file-ops.mjs +30 -0
- package/template/src/framework/maker-cli/src/levels/level-1/flags.mjs +16 -0
- package/template/src/framework/maker-cli/src/levels/level-1/help.mjs +24 -0
- package/template/src/framework/maker-cli/src/levels/level-1/naming.mjs +13 -0
- package/template/src/framework/maker-cli/src/levels/level-1/process.mjs +47 -0
- package/template/src/framework/maker-cli/src/levels/level-2/db/core.mjs +299 -0
- package/template/src/framework/maker-cli/src/levels/level-2/db/index.mjs +177 -0
- package/template/src/framework/maker-cli/src/levels/level-2/deploy/core.mjs +635 -0
- package/template/src/framework/maker-cli/src/levels/level-2/deploy/index.mjs +145 -0
- package/template/src/framework/maker-cli/src/levels/level-2/module/core.mjs +707 -0
- package/template/src/framework/maker-cli/src/levels/level-2/module/index.mjs +116 -0
- package/template/src/framework/maker-cli/src/levels/level-2/runtime/build-frontend.mjs +16 -0
- package/template/src/framework/maker-cli/src/levels/level-2/runtime/core.mjs +311 -0
- package/template/src/framework/maker-cli/src/levels/level-2/runtime/index.mjs +71 -0
- package/template/src/framework/maker-cli/stubs/controller/openapi.ts.stub +55 -0
- package/template/src/framework/maker-cli/stubs/controller/openapi.with-model.ts.stub +56 -0
- package/template/src/framework/maker-cli/stubs/controller/plain.ts.stub +57 -0
- package/template/src/framework/maker-cli/stubs/controller/schema.plain.ts.stub +13 -0
- package/template/src/framework/maker-cli/stubs/controller/schema.ts.stub +32 -0
- package/template/src/framework/maker-cli/stubs/deploy/Dockerfile.bun.stub +49 -0
- package/template/src/framework/maker-cli/stubs/deploy/Dockerfile.pnpm.stub +53 -0
- package/template/src/framework/maker-cli/stubs/deploy/Dockerfile.stub +49 -0
- package/template/src/framework/maker-cli/stubs/deploy/Dockerfile.yarn.stub +53 -0
- package/template/src/framework/maker-cli/stubs/deploy/README.stub +55 -0
- package/template/src/framework/maker-cli/stubs/deploy/compose/mysql.server.stub +29 -0
- package/template/src/framework/maker-cli/stubs/deploy/compose/postgres.server.stub +29 -0
- package/template/src/framework/maker-cli/stubs/deploy/compose/sqlite.stub +29 -0
- package/template/src/framework/maker-cli/stubs/deploy/env/mysql.server.stub +73 -0
- package/template/src/framework/maker-cli/stubs/deploy/env/postgres.server.stub +73 -0
- package/template/src/framework/maker-cli/stubs/deploy/env/sqlite.stub +72 -0
- package/template/src/framework/maker-cli/stubs/deploy/scripts/auto-migrate.sh.stub +15 -0
- package/template/src/framework/maker-cli/stubs/deploy/server/README.stub +77 -0
- package/template/src/framework/maker-cli/stubs/deploy/server/compose/noredis.stub +118 -0
- package/template/src/framework/maker-cli/stubs/deploy/server/compose/redis.dev.stub +131 -0
- package/template/src/framework/maker-cli/stubs/deploy/server/compose/redis.stub +129 -0
- package/template/src/framework/maker-cli/stubs/deploy/server/env/local.example.stub +10 -0
- package/template/src/framework/maker-cli/stubs/deploy/server/env/noredis.stub +24 -0
- package/template/src/framework/maker-cli/stubs/deploy/server/env/redis.stub +24 -0
- package/template/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/README.stub +15 -0
- package/template/src/framework/maker-cli/stubs/deploy/server/nginx-vhost/app.example.com.stub +12 -0
- package/template/src/framework/maker-cli/stubs/deploy/server/pgadmin/servers.stub +13 -0
- package/template/src/framework/maker-cli/stubs/deploy/server/redis/redis.conf.stub +6 -0
- package/template/src/framework/maker-cli/stubs/deploy/supervisor/noredis.stub +53 -0
- package/template/src/framework/maker-cli/stubs/deploy/supervisor/redis.stub +69 -0
- package/template/src/framework/maker-cli/stubs/deploy/workflow/local.json.stub +24 -0
- package/template/src/framework/maker-cli/stubs/deploy/workflow/remote.json.stub +20 -0
- package/template/src/framework/maker-cli/stubs/example/console.ts.stub +33 -0
- package/template/src/framework/maker-cli/stubs/example/controller.ts.stub +503 -0
- package/template/src/framework/maker-cli/stubs/example/job.ts.stub +74 -0
- package/template/src/framework/maker-cli/stubs/example/route.api.ts.stub +206 -0
- package/template/src/framework/maker-cli/stubs/example/schema.ts.stub +41 -0
- package/template/src/framework/maker-cli/stubs/job/name.ts.stub +24 -0
- package/template/src/framework/maker-cli/stubs/model/name.mysql.ts.stub +8 -0
- package/template/src/framework/maker-cli/stubs/model/name.postgresql.ts.stub +8 -0
- package/template/src/framework/maker-cli/stubs/model/name.sqlite.ts.stub +8 -0
- package/template/src/framework/maker-cli/stubs/notification/NotificationBell.vue.stub +218 -0
- package/template/src/framework/maker-cli/stubs/notification/controller.ts.stub +85 -0
- package/template/src/framework/maker-cli/stubs/notification/index.vue.stub +211 -0
- package/template/src/framework/maker-cli/stubs/notification/job.ts.stub +12 -0
- package/template/src/framework/maker-cli/stubs/notification/route.api.ts.stub +49 -0
- package/template/src/framework/maker-cli/stubs/notification/schema.ts.stub +25 -0
- package/template/src/framework/maker-cli/stubs/route/api.ts.stub +79 -0
- package/template/src/framework/maker-cli/stubs/route/plain.ts.stub +10 -0
- package/template/src/framework/maker-cli/stubs/schedule/name.ts.stub +35 -0
- package/template/src/framework/maker-cli/stubs/seeder/name.ts.stub +17 -0
- package/template/src/framework/modules/discover.ts +54 -0
- package/template/src/framework/modules/routes.ts +26 -0
- package/template/src/framework/notification/index.ts +109 -0
- package/template/src/framework/queue/clear.ts +20 -0
- package/template/src/framework/queue/queue.ts +213 -0
- package/template/src/framework/queue/ui.ts +104 -0
- package/template/src/framework/queue/worker.ts +33 -0
- package/template/src/framework/realtime/broadcast.ts +27 -0
- package/template/src/framework/realtime/index.ts +1 -0
- package/template/src/framework/realtime/socket-cookie.ts +65 -0
- package/template/src/framework/realtime/socket.ts +132 -0
- package/template/src/framework/realtime/types.ts +6 -0
- package/template/src/framework/realtime/ui.ts +16 -0
- package/template/src/framework/redis/client.ts +126 -0
- package/template/src/framework/scheduler/lock.ts +124 -0
- package/template/src/framework/scheduler/run.ts +26 -0
- package/template/src/framework/scheduler/scheduler.ts +82 -0
- package/template/src/framework/server.ts +147 -0
- package/template/src/framework/session/session.ts +116 -0
- package/template/src/framework/storage/storage.ts +743 -0
- package/template/src/framework/support/cookie.ts +78 -0
- package/template/src/framework/support/jwt.ts +45 -0
- package/template/src/framework/support/lifecycle.ts +35 -0
- package/template/src/framework/support/logger.ts +102 -0
- package/template/src/framework/support/mail.ts +43 -0
- package/template/src/framework/support/password.ts +23 -0
- package/template/src/framework/support/url.ts +25 -0
- package/template/src/middlewares/auth-middleware.ts +98 -0
- package/template/src/middlewares/role-middleware.ts +24 -0
- package/template/src/modules/auth/controllers/auth.controller.ts +445 -0
- package/template/src/modules/auth/controllers/auth.helpers.ts +110 -0
- package/template/src/modules/auth/controllers/auth.schema.ts +102 -0
- package/template/src/modules/auth/controllers/role.controller.ts +25 -0
- package/template/src/modules/auth/database/models/notifications.ts +22 -0
- package/template/src/modules/auth/database/models/role.ts +14 -0
- package/template/src/modules/auth/database/models/user.ts +46 -0
- package/template/src/modules/auth/database/seeders/role.ts +19 -0
- package/template/src/modules/auth/database/seeders/user.ts +33 -0
- package/template/src/modules/auth/jobs/forgetpass.ts +18 -0
- package/template/src/modules/auth/jobs/registeruser.ts +31 -0
- package/template/src/modules/auth/jobs/verifyemail.ts +18 -0
- package/template/src/modules/auth/routes/api.ts +151 -0
- package/template/src/modules/auth/routes/role.ts +39 -0
- package/template/src/modules/welcome/controllers/welcome.controller.ts +14 -0
- package/template/src/modules/welcome/controllers/welcome.schema.ts +6 -0
- package/template/src/modules/welcome/database/models/welcome.ts +6 -0
- package/template/src/modules/welcome/routes/api.ts +20 -0
- package/template/src/resources/index.html +16 -0
- package/template/src/resources/src/App.vue +5 -0
- package/template/src/resources/src/assets/css/styles.css +14934 -0
- package/template/src/resources/src/assets/css/styles.css.map +1 -0
- package/template/src/resources/src/assets/images/favicon/favicon.ico +0 -0
- package/template/src/resources/src/assets/images/favicon/favicon1.ico +0 -0
- package/template/src/resources/src/assets/images/logo-1.png +0 -0
- package/template/src/resources/src/assets/images/logo-dark-sm.png +0 -0
- package/template/src/resources/src/assets/images/logo-dark.png +0 -0
- package/template/src/resources/src/assets/images/logo-dark1.png +0 -0
- package/template/src/resources/src/assets/images/logo-sm.png +0 -0
- package/template/src/resources/src/assets/images/logo1.png +0 -0
- package/template/src/resources/src/assets/images/logo2.png +0 -0
- package/template/src/resources/src/assets/scss/custom.css +217 -0
- package/template/src/resources/src/assets/scss/custom.css.map +1 -0
- package/template/src/resources/src/assets/scss/custom.scss +1100 -0
- package/template/src/resources/src/components/Button.vue +35 -0
- package/template/src/resources/src/components/Checkbox.vue +29 -0
- package/template/src/resources/src/components/FloatButton.vue +36 -0
- package/template/src/resources/src/components/Href.vue +32 -0
- package/template/src/resources/src/components/Input.vue +227 -0
- package/template/src/resources/src/components/InputGroup.vue +153 -0
- package/template/src/resources/src/components/InputPasswordToggle.vue +226 -0
- package/template/src/resources/src/components/Modal.vue +102 -0
- package/template/src/resources/src/components/Pagebar.vue +28 -0
- package/template/src/resources/src/components/Refresh.vue +26 -0
- package/template/src/resources/src/components/Select.vue +390 -0
- package/template/src/resources/src/components/Spinner.vue +42 -0
- package/template/src/resources/src/components/Switch.vue +65 -0
- package/template/src/resources/src/components/TextArea.vue +121 -0
- package/template/src/resources/src/components/Toast.vue +56 -0
- package/template/src/resources/src/components/datatable/DataTableSkeleton.vue +99 -0
- package/template/src/resources/src/components/datatable/Pagination.vue +161 -0
- package/template/src/resources/src/components/datatable/SelectOpption.vue +54 -0
- package/template/src/resources/src/components/datatable/index.vue +237 -0
- package/template/src/resources/src/composables/useAuth.ts +52 -0
- package/template/src/resources/src/composables/useBrowserDetect.ts +5 -0
- package/template/src/resources/src/composables/useDialog.ts +5 -0
- package/template/src/resources/src/composables/useGum.ts +3 -0
- package/template/src/resources/src/composables/usePulse.ts +5 -0
- package/template/src/resources/src/env.d.ts +20 -0
- package/template/src/resources/src/helpers/nformatter.ts +10 -0
- package/template/src/resources/src/helpers/utils.ts +68 -0
- package/template/src/resources/src/layouts/AuthLayout.vue +20 -0
- package/template/src/resources/src/layouts/Layout/Footer.vue +23 -0
- package/template/src/resources/src/layouts/Layout/Header.vue +90 -0
- package/template/src/resources/src/layouts/Layout/Sidebar.vue +137 -0
- package/template/src/resources/src/layouts/Layout/index.vue +76 -0
- package/template/src/resources/src/main.ts +27 -0
- package/template/src/resources/src/pages/auth/forgetPassword.vue +76 -0
- package/template/src/resources/src/pages/auth/login.vue +93 -0
- package/template/src/resources/src/pages/auth/register.vue +130 -0
- package/template/src/resources/src/pages/auth/resetPassword.vue +119 -0
- package/template/src/resources/src/pages/auth/verifyEmail.vue +60 -0
- package/template/src/resources/src/pages/dashboard/index.vue +76 -0
- package/template/src/resources/src/plugins/axios.ts +33 -0
- package/template/src/resources/src/plugins/browserDetect.ts +55 -0
- package/template/src/resources/src/plugins/dialog.ts +167 -0
- package/template/src/resources/src/plugins/gum.ts +343 -0
- package/template/src/resources/src/plugins/pulse.ts +141 -0
- package/template/src/resources/src/plugins/routeProgress.ts +87 -0
- package/template/src/resources/src/router/index.ts +85 -0
- package/template/src/resources/src/stores/admin-ui.ts +148 -0
- package/template/src/resources/src/stores/auth.ts +151 -0
- package/template/src/resources/tsconfig.json +19 -0
- package/template/src/resources/vite.config.ts +43 -0
- package/template/src/storage/logs/app.log +20179 -0
- package/template/src/storage/logs/fatal.log +727 -0
- package/template/tsconfig.json +20 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="container position-absolute start-50 top-50 translate-middle">
|
|
3
|
+
<div class="auth col-12 col-sm-9 col-md-7 col-lg-5 col-xl-4 mx-auto py-5">
|
|
4
|
+
<div class="card card-body border-0">
|
|
5
|
+
<div class="d-block mb-2">
|
|
6
|
+
<h3 class="m-0 text-uppercase text-center fw-semibold">nexgen</h3>
|
|
7
|
+
</div>
|
|
8
|
+
<h4 class="text-center">Create Account</h4>
|
|
9
|
+
<p
|
|
10
|
+
v-if="message"
|
|
11
|
+
class="text-center alert py-1 mt-2"
|
|
12
|
+
:class="isError ? 'alert-danger text-danger' : 'alert-success text-success'">
|
|
13
|
+
{{ message }}
|
|
14
|
+
</p>
|
|
15
|
+
<form @submit.prevent="onSubmit">
|
|
16
|
+
<div class="mb-4">
|
|
17
|
+
<Input
|
|
18
|
+
id="name"
|
|
19
|
+
v-model="form.name"
|
|
20
|
+
type="text"
|
|
21
|
+
label="name"
|
|
22
|
+
placeholder="Enter your name..."
|
|
23
|
+
:err="false"
|
|
24
|
+
focus
|
|
25
|
+
must />
|
|
26
|
+
</div>
|
|
27
|
+
<div class="mb-4">
|
|
28
|
+
<Input
|
|
29
|
+
id="email"
|
|
30
|
+
v-model="form.email"
|
|
31
|
+
type="email"
|
|
32
|
+
label="email"
|
|
33
|
+
placeholder="Enter your email..."
|
|
34
|
+
:err="false"
|
|
35
|
+
must />
|
|
36
|
+
</div>
|
|
37
|
+
<div class="mb-4">
|
|
38
|
+
<InputPasswordToggle
|
|
39
|
+
id="password"
|
|
40
|
+
v-model="form.password"
|
|
41
|
+
label="password"
|
|
42
|
+
placeholder="Create a password..."
|
|
43
|
+
:err="false"
|
|
44
|
+
must />
|
|
45
|
+
</div>
|
|
46
|
+
<div class="mb-4">
|
|
47
|
+
<InputPasswordToggle
|
|
48
|
+
id="password_confirmation"
|
|
49
|
+
v-model="form.password_confirmation"
|
|
50
|
+
label="confirm password"
|
|
51
|
+
placeholder="Confirm your password..."
|
|
52
|
+
:err="false"
|
|
53
|
+
must />
|
|
54
|
+
</div>
|
|
55
|
+
<button type="submit" class="btn btn-primary w-100" :disabled="auth.processing">
|
|
56
|
+
<span>Create Account</span>
|
|
57
|
+
<i class="bi bi-person-plus ms-2"></i>
|
|
58
|
+
</button>
|
|
59
|
+
</form>
|
|
60
|
+
<div class="text-center mt-3">
|
|
61
|
+
<span class="text-muted">Already have an account?</span>
|
|
62
|
+
<router-link to="/login" class="ms-1 text-decoration-none">Login</router-link>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</div>
|
|
67
|
+
</template>
|
|
68
|
+
|
|
69
|
+
<script setup lang="ts">
|
|
70
|
+
import { reactive, ref } from "vue";
|
|
71
|
+
import { useRouter } from "vue-router";
|
|
72
|
+
import { useHead } from "@vueuse/head";
|
|
73
|
+
import { useAuthStore } from "@/stores/auth";
|
|
74
|
+
import Input from "@/components/Input.vue";
|
|
75
|
+
import InputPasswordToggle from "@/components/InputPasswordToggle.vue";
|
|
76
|
+
|
|
77
|
+
useHead({ title: "Register" });
|
|
78
|
+
|
|
79
|
+
const router = useRouter();
|
|
80
|
+
const auth = useAuthStore();
|
|
81
|
+
|
|
82
|
+
interface RegisterForm {
|
|
83
|
+
name: string;
|
|
84
|
+
email: string;
|
|
85
|
+
password: string;
|
|
86
|
+
password_confirmation: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const form = reactive<RegisterForm>({
|
|
90
|
+
name: "",
|
|
91
|
+
email: "",
|
|
92
|
+
password: "",
|
|
93
|
+
password_confirmation: ""
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const message = ref("");
|
|
97
|
+
const isError = ref(false);
|
|
98
|
+
|
|
99
|
+
const onSubmit = async () => {
|
|
100
|
+
message.value = "";
|
|
101
|
+
isError.value = false;
|
|
102
|
+
|
|
103
|
+
if (form.password !== form.password_confirmation) {
|
|
104
|
+
isError.value = true;
|
|
105
|
+
message.value = "Password confirmation does not match";
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
const result = await auth.register({
|
|
111
|
+
name: form.name.trim(),
|
|
112
|
+
email: form.email.trim(),
|
|
113
|
+
password: form.password,
|
|
114
|
+
password_confirmation: form.password_confirmation
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (auth.isAuthenticated) {
|
|
118
|
+
await router.push("/");
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
message.value = result || "Registration successful. Please verify your email.";
|
|
123
|
+
} catch (error: unknown) {
|
|
124
|
+
isError.value = true;
|
|
125
|
+
message.value = error instanceof Error ? error.message : "Unable to register right now";
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
</script>
|
|
129
|
+
|
|
130
|
+
<style lang="scss" scoped></style>
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="container position-absolute start-50 top-50 translate-middle">
|
|
3
|
+
<div class="auth col-12 col-sm-9 col-md-7 col-lg-5 col-xl-4 mx-auto py-5">
|
|
4
|
+
<div class="card card-body border-0">
|
|
5
|
+
<div class="d-block mb-2">
|
|
6
|
+
<h3 class="m-0 text-uppercase text-center fw-semibold">nexgen</h3>
|
|
7
|
+
</div>
|
|
8
|
+
<h4 class="text-center">Reset Password</h4>
|
|
9
|
+
<p
|
|
10
|
+
v-if="message"
|
|
11
|
+
class="text-center alert py-1 mt-2"
|
|
12
|
+
:class="isError ? 'alert-danger text-danger' : 'alert-success text-success'">
|
|
13
|
+
{{ message }}
|
|
14
|
+
</p>
|
|
15
|
+
<form
|
|
16
|
+
id="formAuthentication"
|
|
17
|
+
:class="{ 'pe-none opacity-50': !isLinkValid }"
|
|
18
|
+
@submit.prevent="onSubmit">
|
|
19
|
+
<div class="mb-4">
|
|
20
|
+
<Input
|
|
21
|
+
id="password"
|
|
22
|
+
v-model="form.password"
|
|
23
|
+
type="password"
|
|
24
|
+
label="new password"
|
|
25
|
+
placeholder="Enter new password..."
|
|
26
|
+
:err="false"
|
|
27
|
+
focus
|
|
28
|
+
must />
|
|
29
|
+
</div>
|
|
30
|
+
<div class="mb-4">
|
|
31
|
+
<Input
|
|
32
|
+
id="password_confirmation"
|
|
33
|
+
v-model="form.password_confirmation"
|
|
34
|
+
type="password"
|
|
35
|
+
label="confirm password"
|
|
36
|
+
placeholder="Confirm new password..."
|
|
37
|
+
:err="false"
|
|
38
|
+
must />
|
|
39
|
+
</div>
|
|
40
|
+
<Button
|
|
41
|
+
type="submit"
|
|
42
|
+
label="Reset Password"
|
|
43
|
+
class="btn btn-primary d-grid w-100"
|
|
44
|
+
icon="bi bi-key ms-2"
|
|
45
|
+
:disabled="auth.processing" />
|
|
46
|
+
</form>
|
|
47
|
+
<div class="text-center mt-2">
|
|
48
|
+
<router-link to="/login">
|
|
49
|
+
<i class="bx bx-chevron-left scaleX-n1-rtl me-1"></i>
|
|
50
|
+
<span>Back to login</span>
|
|
51
|
+
</router-link>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</template>
|
|
57
|
+
|
|
58
|
+
<script setup lang="ts">
|
|
59
|
+
import { reactive, ref } from "vue";
|
|
60
|
+
import { useRoute, useRouter } from "vue-router";
|
|
61
|
+
import { useHead } from "@vueuse/head";
|
|
62
|
+
import Input from "../../components/Input.vue";
|
|
63
|
+
import Button from "../../components/Button.vue";
|
|
64
|
+
import { useAuthStore } from "@/stores/auth";
|
|
65
|
+
|
|
66
|
+
useHead({ title: "Reset Password" });
|
|
67
|
+
|
|
68
|
+
const route = useRoute();
|
|
69
|
+
const router = useRouter();
|
|
70
|
+
const auth = useAuthStore();
|
|
71
|
+
|
|
72
|
+
interface ResetPasswordForm {
|
|
73
|
+
email: string;
|
|
74
|
+
token: string;
|
|
75
|
+
password: string;
|
|
76
|
+
password_confirmation: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const form = reactive<ResetPasswordForm>({
|
|
80
|
+
email: String(route.query.email || ""),
|
|
81
|
+
token: String(route.query.token || ""),
|
|
82
|
+
password: "",
|
|
83
|
+
password_confirmation: ""
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const isLinkValid = !!(form.token && form.email);
|
|
87
|
+
const message = ref(
|
|
88
|
+
isLinkValid ? "Set your new password" : "Invalid reset link. Please request a new one."
|
|
89
|
+
);
|
|
90
|
+
const isError = ref(!isLinkValid);
|
|
91
|
+
|
|
92
|
+
const onSubmit = async () => {
|
|
93
|
+
if (!isLinkValid) return;
|
|
94
|
+
|
|
95
|
+
message.value = "";
|
|
96
|
+
isError.value = false;
|
|
97
|
+
|
|
98
|
+
if (form.password !== form.password_confirmation) {
|
|
99
|
+
isError.value = true;
|
|
100
|
+
message.value = "Password confirmation does not match";
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
try {
|
|
105
|
+
message.value = await auth.resetPassword({
|
|
106
|
+
email: form.email.trim(),
|
|
107
|
+
token: form.token.trim(),
|
|
108
|
+
password: form.password,
|
|
109
|
+
password_confirmation: form.password_confirmation
|
|
110
|
+
});
|
|
111
|
+
await router.push("/login");
|
|
112
|
+
} catch (error: unknown) {
|
|
113
|
+
isError.value = true;
|
|
114
|
+
message.value = error instanceof Error ? error.message : "Failed to reset password";
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
</script>
|
|
118
|
+
|
|
119
|
+
<style lang="scss" scoped></style>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="container position-absolute start-50 top-50 translate-middle">
|
|
3
|
+
<div class="auth col-12 col-sm-9 col-md-7 col-lg-5 col-xl-4 mx-auto py-5">
|
|
4
|
+
<div class="card card-body border-0">
|
|
5
|
+
<div class="d-block mb-2">
|
|
6
|
+
<h3 class="m-0 text-uppercase text-center fw-semibold">nexgen</h3>
|
|
7
|
+
</div>
|
|
8
|
+
<h4 class="text-center">Email Verification</h4>
|
|
9
|
+
<p
|
|
10
|
+
v-if="message"
|
|
11
|
+
class="text-center alert py-2 mt-2"
|
|
12
|
+
:class="isError ? 'alert-danger text-danger' : 'alert-success text-success'">
|
|
13
|
+
{{ message }}
|
|
14
|
+
</p>
|
|
15
|
+
<div class="text-center mt-2">
|
|
16
|
+
<router-link to="/login">
|
|
17
|
+
<span>Back to login</span>
|
|
18
|
+
</router-link>
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
</div>
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup lang="ts">
|
|
26
|
+
import { ref } from "vue";
|
|
27
|
+
import { useHead } from "@vueuse/head";
|
|
28
|
+
import { useRoute } from "vue-router";
|
|
29
|
+
import { useAuthStore } from "@/stores/auth";
|
|
30
|
+
|
|
31
|
+
useHead({ title: "Verify Email" });
|
|
32
|
+
|
|
33
|
+
const route = useRoute();
|
|
34
|
+
const auth = useAuthStore();
|
|
35
|
+
|
|
36
|
+
const email = String(route.query.email || "").trim();
|
|
37
|
+
const token = String(route.query.token || "").trim();
|
|
38
|
+
const message = ref("Verifying your email...");
|
|
39
|
+
const isError = ref(false);
|
|
40
|
+
|
|
41
|
+
const verify = async () => {
|
|
42
|
+
if (!email || !token) {
|
|
43
|
+
isError.value = true;
|
|
44
|
+
message.value = "Invalid verification link. Please request a new one.";
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
message.value = await auth.verifyEmail({ email, token });
|
|
50
|
+
isError.value = false;
|
|
51
|
+
} catch (error: unknown) {
|
|
52
|
+
isError.value = true;
|
|
53
|
+
message.value = error instanceof Error ? error.message : "Failed to verify email";
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
void verify();
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
<style lang="scss" scoped></style>
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Pagebar title="Dashboard" />
|
|
3
|
+
<!-- <Refresh @click="hardRefresh" /> -->
|
|
4
|
+
|
|
5
|
+
<div class="dashboard-placeholder">
|
|
6
|
+
<div class="row g-2 mb-2">
|
|
7
|
+
<div class="col-12 col-md-4">
|
|
8
|
+
<div class="placeholder-card"></div>
|
|
9
|
+
</div>
|
|
10
|
+
<div class="col-12 col-md-4">
|
|
11
|
+
<div class="placeholder-card"></div>
|
|
12
|
+
</div>
|
|
13
|
+
<div class="col-12 col-md-4">
|
|
14
|
+
<div class="placeholder-card"></div>
|
|
15
|
+
</div>
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
<div class="placeholder-panel"></div>
|
|
19
|
+
</div>
|
|
20
|
+
</template>
|
|
21
|
+
|
|
22
|
+
<script setup lang="ts">
|
|
23
|
+
import { onMounted, onUnmounted } from "vue";
|
|
24
|
+
import { useHead } from "@vueuse/head";
|
|
25
|
+
import { pulse } from "@/plugins/pulse";
|
|
26
|
+
import { useAuth } from "@/composables/useAuth";
|
|
27
|
+
import Pagebar from "@/components/Pagebar.vue";
|
|
28
|
+
import Refresh from "@/components/Refresh.vue";
|
|
29
|
+
|
|
30
|
+
useHead({ title: "Dashboard" });
|
|
31
|
+
|
|
32
|
+
const { user } = useAuth();
|
|
33
|
+
|
|
34
|
+
let unsubscribe: (() => void) | null = null;
|
|
35
|
+
|
|
36
|
+
onMounted(() => {
|
|
37
|
+
if (!user.value) return;
|
|
38
|
+
|
|
39
|
+
const channel = pulse.channel(`user:${user.value.id}`);
|
|
40
|
+
channel.listen("user.registered", () => alert("me"));
|
|
41
|
+
unsubscribe = () => channel.stopListening("user.registered");
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
onUnmounted(() => {
|
|
45
|
+
unsubscribe?.();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// const hardRefresh = () => window.location.reload();
|
|
49
|
+
</script>
|
|
50
|
+
|
|
51
|
+
<style scoped>
|
|
52
|
+
.placeholder-card,
|
|
53
|
+
.placeholder-panel {
|
|
54
|
+
border: 1px solid var(--app-border);
|
|
55
|
+
border-radius: 0.3rem;
|
|
56
|
+
background: var(--app-surface);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.placeholder-card {
|
|
60
|
+
min-height: 220px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.placeholder-panel {
|
|
64
|
+
min-height: 520px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
@media (max-width: 768px) {
|
|
68
|
+
.placeholder-card {
|
|
69
|
+
min-height: 160px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.placeholder-panel {
|
|
73
|
+
min-height: 360px;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
</style>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
|
|
3
|
+
if (import.meta.env.VITE_API_URL) {
|
|
4
|
+
axios.defaults.baseURL = import.meta.env.VITE_API_URL;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
axios.defaults.withCredentials = true;
|
|
8
|
+
axios.defaults.headers.common["X-Requested-With"] = "XMLHttpRequest";
|
|
9
|
+
axios.defaults.headers.common.Accept = "application/json";
|
|
10
|
+
|
|
11
|
+
axios.interceptors.response.use(
|
|
12
|
+
(response) => response,
|
|
13
|
+
(error) => {
|
|
14
|
+
const status = error?.response?.status;
|
|
15
|
+
const isAuthPage =
|
|
16
|
+
window.location.pathname === "/register" ||
|
|
17
|
+
window.location.pathname === "/login" ||
|
|
18
|
+
window.location.pathname === "/forget-password" ||
|
|
19
|
+
window.location.pathname === "/reset-password" ||
|
|
20
|
+
window.location.pathname === "/verify-email";
|
|
21
|
+
|
|
22
|
+
if (status === 401 && !isAuthPage) {
|
|
23
|
+
const redirect = encodeURIComponent(
|
|
24
|
+
window.location.pathname + window.location.search + window.location.hash
|
|
25
|
+
);
|
|
26
|
+
window.location.href = `/login?redirect=${redirect}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return Promise.reject(error);
|
|
30
|
+
}
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
export default axios;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { App, ComputedRef } from "vue";
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
|
|
4
|
+
export type BrowserDetectResult = {
|
|
5
|
+
userAgent: string;
|
|
6
|
+
isFirefox: ComputedRef<boolean>;
|
|
7
|
+
isChrome: ComputedRef<boolean>;
|
|
8
|
+
isSafari: ComputedRef<boolean>;
|
|
9
|
+
isEdge: ComputedRef<boolean>;
|
|
10
|
+
isOpera: ComputedRef<boolean>;
|
|
11
|
+
isBrave: ComputedRef<boolean>;
|
|
12
|
+
isAndroid: ComputedRef<boolean>;
|
|
13
|
+
isIOS: ComputedRef<boolean>;
|
|
14
|
+
isWindows: ComputedRef<boolean>;
|
|
15
|
+
isMac: ComputedRef<boolean>;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const userAgent = typeof navigator !== "undefined" ? navigator.userAgent.toLowerCase() : "";
|
|
19
|
+
|
|
20
|
+
const isFirefoxRaw = userAgent.includes("firefox");
|
|
21
|
+
const isEdgeRaw = userAgent.includes("edg");
|
|
22
|
+
const isOperaRaw = userAgent.includes("opr") || userAgent.includes("opera");
|
|
23
|
+
const isBraveRaw = userAgent.includes("brave");
|
|
24
|
+
const isChromeRaw = userAgent.includes("chrome") && !isEdgeRaw && !isOperaRaw && !isBraveRaw;
|
|
25
|
+
const isAndroidRaw = userAgent.includes("android");
|
|
26
|
+
const isSafariRaw = userAgent.includes("safari") && !isChromeRaw && !isAndroidRaw;
|
|
27
|
+
const isIOSRaw = /iphone|ipad|ipod/.test(userAgent);
|
|
28
|
+
const isWindowsRaw = userAgent.includes("windows");
|
|
29
|
+
const isMacRaw = userAgent.includes("macintosh");
|
|
30
|
+
|
|
31
|
+
export const browserDetect: BrowserDetectResult = {
|
|
32
|
+
userAgent,
|
|
33
|
+
isFirefox: computed(() => isFirefoxRaw),
|
|
34
|
+
isChrome: computed(() => isChromeRaw),
|
|
35
|
+
isSafari: computed(() => isSafariRaw),
|
|
36
|
+
isEdge: computed(() => isEdgeRaw),
|
|
37
|
+
isOpera: computed(() => isOperaRaw),
|
|
38
|
+
isBrave: computed(() => isBraveRaw),
|
|
39
|
+
isAndroid: computed(() => isAndroidRaw),
|
|
40
|
+
isIOS: computed(() => isIOSRaw),
|
|
41
|
+
isWindows: computed(() => isWindowsRaw),
|
|
42
|
+
isMac: computed(() => isMacRaw)
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export const BrowserDetectPlugin = {
|
|
46
|
+
install(app: App) {
|
|
47
|
+
app.config.globalProperties.$browserDetect = browserDetect;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
declare module "vue" {
|
|
52
|
+
interface ComponentCustomProperties {
|
|
53
|
+
$browserDetect: BrowserDetectResult;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import type { App } from "vue";
|
|
2
|
+
|
|
3
|
+
type PromptOptions = {
|
|
4
|
+
limit?: number;
|
|
5
|
+
placeholder?: string;
|
|
6
|
+
defaultValue?: string;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
type DialogClient = {
|
|
10
|
+
alert: (text?: string) => Promise<void>;
|
|
11
|
+
confirm: (text?: string) => Promise<boolean>;
|
|
12
|
+
prompt: (text?: string, options?: PromptOptions) => Promise<{ ok: boolean; value: string }>;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function hostNode() {
|
|
16
|
+
return document.querySelector("#modal-show") || document.body;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function siteLabel() {
|
|
20
|
+
return `${location.protocol}//${location.hostname}`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function buildShell(content: string) {
|
|
24
|
+
const root = document.createElement("div");
|
|
25
|
+
root.className = "position-fixed w-100 h-100 top-0 start-0";
|
|
26
|
+
root.style.background = "rgba(0, 0, 0, .5)";
|
|
27
|
+
root.style.zIndex = "100000";
|
|
28
|
+
root.innerHTML = content;
|
|
29
|
+
return root;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function closeShell(shell: HTMLElement) {
|
|
33
|
+
if (shell.parentElement) shell.parentElement.removeChild(shell);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const dialog: DialogClient = {
|
|
37
|
+
alert(text = "") {
|
|
38
|
+
return new Promise<void>((resolve) => {
|
|
39
|
+
const shell = buildShell(`
|
|
40
|
+
<div class='card position-absolute top-50 start-50 translate-middle border' style='width:300px'>
|
|
41
|
+
<div class='card-header d-flex justify-content-between align-items-center px-2 py-1 bg-white border-0'>
|
|
42
|
+
<span class='d-flex align-items-center'>
|
|
43
|
+
<i class="bi bi-exclamation-circle"></i> <span class='ms-2'>${siteLabel()}</span>
|
|
44
|
+
</span>
|
|
45
|
+
<button class='btn btn-sm p-0' type='button' data-dialog='close'>
|
|
46
|
+
<i class='bi bi-x fs-3'></i>
|
|
47
|
+
</button>
|
|
48
|
+
</div>
|
|
49
|
+
<div class='card-body overflow-x-hidden overflow-y-scroll p-2 text-center' style='max-height:200px'>
|
|
50
|
+
${text}
|
|
51
|
+
</div>
|
|
52
|
+
<div class='card-footer d-flex justify-content-end align-items-center px-2 py-1 bg-white border-0'>
|
|
53
|
+
<button type='button' class='btn btn-primary btn-sm' data-dialog='ok'>OK</button>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
`);
|
|
57
|
+
|
|
58
|
+
shell.addEventListener("click", (event) => {
|
|
59
|
+
const target = event.target as HTMLElement;
|
|
60
|
+
const action = target.closest("[data-dialog]")?.getAttribute("data-dialog");
|
|
61
|
+
if (action === "ok" || action === "close") {
|
|
62
|
+
closeShell(shell);
|
|
63
|
+
resolve();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
hostNode().appendChild(shell);
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
confirm(text = "") {
|
|
72
|
+
return new Promise<boolean>((resolve) => {
|
|
73
|
+
const shell = buildShell(`
|
|
74
|
+
<div class='card position-absolute top-50 start-50 translate-middle border' style='width:300px'>
|
|
75
|
+
<div class='card-header d-flex justify-content-between align-items-center px-2 py-1 bg-white border-0'>
|
|
76
|
+
<span class='d-flex align-items-center'>
|
|
77
|
+
<i class="bi bi-globe"></i> <span class='ms-2'>${siteLabel()}</span>
|
|
78
|
+
</span>
|
|
79
|
+
<button class='btn btn-sm p-0' type='button' data-dialog='cancel'>
|
|
80
|
+
<i class='bi bi-x fs-3'></i>
|
|
81
|
+
</button>
|
|
82
|
+
</div>
|
|
83
|
+
<div class='card-body overflow-x-hidden overflow-y-scroll p-2 text-center' style='max-height:200px'>
|
|
84
|
+
${text}
|
|
85
|
+
</div>
|
|
86
|
+
<div class='card-footer d-flex justify-content-end align-items-center px-2 py-1 bg-white border-0'>
|
|
87
|
+
<button type='button' class='btn btn-primary btn-sm' data-dialog='ok'>OK</button>
|
|
88
|
+
<button type='button' class='btn btn-secondary btn-sm ms-1' data-dialog='cancel'>Cancel</button>
|
|
89
|
+
</div>
|
|
90
|
+
</div>
|
|
91
|
+
`);
|
|
92
|
+
|
|
93
|
+
shell.addEventListener("click", (event) => {
|
|
94
|
+
const target = event.target as HTMLElement;
|
|
95
|
+
const action = target.closest("[data-dialog]")?.getAttribute("data-dialog");
|
|
96
|
+
if (action === "ok") {
|
|
97
|
+
closeShell(shell);
|
|
98
|
+
resolve(true);
|
|
99
|
+
}
|
|
100
|
+
if (action === "cancel") {
|
|
101
|
+
closeShell(shell);
|
|
102
|
+
resolve(false);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
hostNode().appendChild(shell);
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
prompt(text = "", options: PromptOptions = {}) {
|
|
111
|
+
const { limit = 0, placeholder = "Remarks...", defaultValue = "" } = options;
|
|
112
|
+
|
|
113
|
+
return new Promise<{ ok: boolean; value: string }>((resolve) => {
|
|
114
|
+
const shell = buildShell(`
|
|
115
|
+
<div class='card position-absolute top-50 start-50 translate-middle border' style='width:300px'>
|
|
116
|
+
<div class='card-header d-flex justify-content-between align-items-center px-2 py-1 bg-white border-0'>
|
|
117
|
+
<span class='d-flex align-items-center'>
|
|
118
|
+
<i class="bi bi-globe"></i> <span class='ms-2'>${siteLabel()}</span>
|
|
119
|
+
</span>
|
|
120
|
+
<button class='btn btn-sm p-0' type='button' data-dialog='cancel'>
|
|
121
|
+
<i class='bi bi-x fs-3'></i>
|
|
122
|
+
</button>
|
|
123
|
+
</div>
|
|
124
|
+
<div class='card-body overflow-x-hidden overflow-y-scroll p-2 position-relative'>
|
|
125
|
+
${text} <sup style='font-size: 10px'>${limit} char</sup>
|
|
126
|
+
<textarea class='form-control border-dark' rows='4' placeholder='${placeholder}' data-dialog='input' ${limit > 0 ? `maxlength='${limit}'` : ""}>${defaultValue}</textarea>
|
|
127
|
+
</div>
|
|
128
|
+
<div class='card-footer d-flex justify-content-end align-items-center px-2 py-1 bg-white border-0'>
|
|
129
|
+
<button type='button' class='btn btn-primary btn-sm' data-dialog='ok'>OK</button>
|
|
130
|
+
<button type='button' class='btn btn-secondary btn-sm ms-1' data-dialog='cancel'>Cancel</button>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
`);
|
|
134
|
+
|
|
135
|
+
shell.addEventListener("click", (event) => {
|
|
136
|
+
const target = event.target as HTMLElement;
|
|
137
|
+
const action = target.closest("[data-dialog]")?.getAttribute("data-dialog");
|
|
138
|
+
const input = shell.querySelector(
|
|
139
|
+
"textarea[data-dialog='input']"
|
|
140
|
+
) as HTMLTextAreaElement | null;
|
|
141
|
+
|
|
142
|
+
if (action === "ok") {
|
|
143
|
+
closeShell(shell);
|
|
144
|
+
resolve({ ok: true, value: input?.value || "" });
|
|
145
|
+
}
|
|
146
|
+
if (action === "cancel") {
|
|
147
|
+
closeShell(shell);
|
|
148
|
+
resolve({ ok: false, value: "" });
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
hostNode().appendChild(shell);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
export const DialogPlugin = {
|
|
158
|
+
install(app: App) {
|
|
159
|
+
app.config.globalProperties.$dialog = dialog;
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
declare module "vue" {
|
|
164
|
+
interface ComponentCustomProperties {
|
|
165
|
+
$dialog: DialogClient;
|
|
166
|
+
}
|
|
167
|
+
}
|