@nuxtify/core 0.1.0
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/LICENSE +21 -0
- package/README.md +216 -0
- package/dist/module.d.mts +97 -0
- package/dist/module.json +13 -0
- package/dist/module.mjs +96 -0
- package/dist/runtime/components/app/AppAnnouncementBar.vue +36 -0
- package/dist/runtime/components/app/AppAnnouncementBar.vue.d.ts +2 -0
- package/dist/runtime/components/app/AppDialog.vue +38 -0
- package/dist/runtime/components/app/AppDialog.vue.d.ts +2 -0
- package/dist/runtime/components/app/AppLoading.vue +16 -0
- package/dist/runtime/components/app/AppLoading.vue.d.ts +2 -0
- package/dist/runtime/components/app/AppLogo.vue +41 -0
- package/dist/runtime/components/app/AppLogo.vue.d.ts +23 -0
- package/dist/runtime/components/app/AppToast.vue +16 -0
- package/dist/runtime/components/app/AppToast.vue.d.ts +2 -0
- package/dist/runtime/composables/dialog.d.ts +13 -0
- package/dist/runtime/composables/dialog.js +15 -0
- package/dist/runtime/composables/nuxtify.d.ts +2 -0
- package/dist/runtime/composables/nuxtify.js +2 -0
- package/dist/runtime/composables/state.d.ts +15 -0
- package/dist/runtime/composables/state.js +10 -0
- package/dist/runtime/server/composables/client.d.ts +1 -0
- package/dist/runtime/server/composables/client.js +1 -0
- package/dist/runtime/server/tsconfig.json +3 -0
- package/dist/runtime/server/utils/client.d.ts +1 -0
- package/dist/runtime/server/utils/client.js +1 -0
- package/dist/runtime/utils/formRules.d.ts +19 -0
- package/dist/runtime/utils/formRules.js +23 -0
- package/dist/runtime/utils/io.d.ts +2 -0
- package/dist/runtime/utils/io.js +19 -0
- package/dist/runtime/utils/math.d.ts +2 -0
- package/dist/runtime/utils/math.js +13 -0
- package/dist/runtime/utils/text.d.ts +23 -0
- package/dist/runtime/utils/text.js +157 -0
- package/dist/runtime/utils/time.d.ts +2 -0
- package/dist/runtime/utils/time.js +7 -0
- package/dist/runtime/utils/url.d.ts +9 -0
- package/dist/runtime/utils/url.js +27 -0
- package/dist/runtime/utils/util.d.ts +7 -0
- package/dist/runtime/utils/util.js +5 -0
- package/dist/runtime/utils/youtube.d.ts +1 -0
- package/dist/runtime/utils/youtube.js +13 -0
- package/dist/types.d.mts +7 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023-present - Nuxtify
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
<div align=center>
|
|
2
|
+
<img src="./nuxtify-banner.png"/>
|
|
3
|
+
</div>
|
|
4
|
+
|
|
5
|
+
# Nuxtify Core
|
|
6
|
+
|
|
7
|
+
<!-- [![npm version][npm-version-src]][npm-version-href]
|
|
8
|
+
[![npm downloads][npm-downloads-src]][npm-downloads-href]
|
|
9
|
+
[![License][license-src]][license-href]
|
|
10
|
+
[![Nuxtify Docs][nuxtify-src]][nuxtify-href] -->
|
|
11
|
+
<!-- [π Online playground](https://stackblitz.com/github/nuxtify-dev/core?file=playground%2Fapp.vue) -->
|
|
12
|
+
|
|
13
|
+
> [!NOTE]
|
|
14
|
+
>
|
|
15
|
+
> **Early Access Preview:**
|
|
16
|
+
> This module is under active development. While it is already used to power a [handful of sites](https://nuxtify.dev/showcase) in production, expect things to change frequently. I will do my best to call out breaking changes in the [changelog](https://github.com/nuxtify-dev/core/blob/main/CHANGELOG.md).
|
|
17
|
+
|
|
18
|
+
### Table of Contents
|
|
19
|
+
|
|
20
|
+
- βΎοΈ [Why Nuxtify?](#why-nuxtify)
|
|
21
|
+
- π§© [Nuxtify Modules](#modules)
|
|
22
|
+
- β¨ [Features](#features)
|
|
23
|
+
- π [Quick Start](#quick-start)
|
|
24
|
+
- π§ [Configuration](#configuration)
|
|
25
|
+
- β
[Updates](#updates)
|
|
26
|
+
- β€οΈ [Contributing](#contributing)
|
|
27
|
+
- π [Local Development](#local-development)
|
|
28
|
+
- βοΈ [License](#license)
|
|
29
|
+
|
|
30
|
+
## <a name="why-nuxtify">βΎοΈ Why Nuxtify?</a>
|
|
31
|
+
|
|
32
|
+
Nuxtify is a collection of [Nuxt modules](https://nuxt.com/docs/guide/concepts/modules) that help you stay organized, maintain focus, and _ship weirdly fast_.
|
|
33
|
+
|
|
34
|
+
It's built on a loosely opinionated stack that eliminates decision fatigue and ensures consistency across projects. This extensible approach gives you incredible control over your site's structure and style.
|
|
35
|
+
|
|
36
|
+
Once you add a Nuxtify module (like this one) to a new or existing Nuxt project, you can use any of the components, composables, and other features instantly β no imports necessary. And more importantly, you can override these defaults with your own version at any time.
|
|
37
|
+
|
|
38
|
+
**This unlocks a powerful way of working.**
|
|
39
|
+
|
|
40
|
+
Use the defaults when they're helpful, and progressively upgrade when they're not.
|
|
41
|
+
|
|
42
|
+
This means you can:
|
|
43
|
+
|
|
44
|
+
- Setup a new project using the default configuration in a matter of minutes.
|
|
45
|
+
- Use the default footer component, but completely change the navigation component.
|
|
46
|
+
- Change the colors of all the buttons with one line of code.
|
|
47
|
+
- Override the default button component with a style of your choosing.
|
|
48
|
+
- And much more...
|
|
49
|
+
|
|
50
|
+
In short, Nuxtify helps you build faster, iterate smarter, and maintain consistency β without sacrificing control or creativity.
|
|
51
|
+
|
|
52
|
+
## <a name="modules">π§© Modules</a>
|
|
53
|
+
|
|
54
|
+
### [Nuxtify Core](https://github.com/nuxtify-dev/core) (this module)
|
|
55
|
+
|
|
56
|
+
Provides the core functionality for Nuxtify, including:
|
|
57
|
+
|
|
58
|
+
- Default components, composables, and utilities
|
|
59
|
+
- Global configuration and theming with [Vuetify](https://vuetifyjs.com/en/introduction/why-vuetify/)
|
|
60
|
+
|
|
61
|
+
### [Nuxtify Pages](https://github.com/nuxtify-dev/pages)
|
|
62
|
+
|
|
63
|
+
Provides single and multi-page website building blocks so you can _ship weirdly fast_.
|
|
64
|
+
|
|
65
|
+
- Ready to use page components, page templates, and email subscribe form
|
|
66
|
+
- (coming soon) Robots, sitemaps, schema.org, social share images, broken links, and more powered by [Nuxt SEO](https://nuxtseo.com/)
|
|
67
|
+
|
|
68
|
+
## <a name="features">β¨ Features</a>
|
|
69
|
+
|
|
70
|
+
Nuxtify Core builds on the amazing features of [Vue](https://vuejs.org/guide/introduction), [Nuxt](https://nuxt.com/docs/getting-started/introduction), and [Vuetify](https://vuetifyjs.com/en/introduction/why-vuetify/).
|
|
71
|
+
|
|
72
|
+
### π‘ Intuitive UI & UX
|
|
73
|
+
|
|
74
|
+
- Easily override any component with [Vuetify global defaults](https://vuetifyjs.com/en/features/global-configuration/)
|
|
75
|
+
- Icons powered by [Material Design Icons](https://pictogrammers.com/library/mdi/) via [Vuetify icon fonts](https://vuetifyjs.com/en/features/icon-fonts/)
|
|
76
|
+
- Fully responsive and adapts to all modern browsers and devices
|
|
77
|
+
- (coming soon) Light and dark mode toggle
|
|
78
|
+
|
|
79
|
+
### π Premium DX
|
|
80
|
+
|
|
81
|
+
- Zero-config with sensible defaults for common use cases
|
|
82
|
+
- All components use the modern [Vue Composition API](https://vuejs.org/guide/extras/composition-api-faq) and [Single File Component (SFC) syntax](https://vuejs.org/guide/scaling-up/sfc.html)
|
|
83
|
+
- [TypeScript](https://www.typescriptlang.org/) auto-complete and type safety for all components
|
|
84
|
+
- [ESLint](https://eslint.org/) support out of the box using flat config (v9)
|
|
85
|
+
- Identify performance gaps and seamlessly manage your app with [Nuxt Devtools](https://devtools.nuxt.com/)
|
|
86
|
+
- Clean, elegant code that's easy to understand and customize
|
|
87
|
+
- Loosely opinionated, leveraging ecosystem standards so you're not locked into outdated dependencies and practices
|
|
88
|
+
|
|
89
|
+
### π€ Security & Performance
|
|
90
|
+
|
|
91
|
+
- Fully tree shakeable for small bundle sizes
|
|
92
|
+
- Optimized caching and rendering strategies for each page with [hybrid rendering](https://nuxt.com/docs/guide/concepts/rendering#hybrid-rendering)
|
|
93
|
+
- (coming soon) Fast, responsive, optimized images for [20+ image providers](https://image.nuxt.com/get-started/providers) powered by [Nuxt Image](https://image.nuxt.com/)
|
|
94
|
+
- (coming soon) Load third-party scripts with better performance, privacy, security powered by [Nuxt Scripts](https://scripts.nuxt.com/)
|
|
95
|
+
- (coming soon) Optimal security patterns and principles powered by [Nuxt Security](https://nuxt.com/modules/security)
|
|
96
|
+
|
|
97
|
+
### π Host Anywhere
|
|
98
|
+
|
|
99
|
+
- Deploy to any Node.js server, static host, or serverless edge CDN environment with [20+ hosting providers](https://nuxt.com/deploy) supported
|
|
100
|
+
|
|
101
|
+
## <a name="quick-start">π Quick Start</a>
|
|
102
|
+
|
|
103
|
+
To use this module in your [new](https://nuxt.com/docs/getting-started/installation) or existing Nuxt project:
|
|
104
|
+
|
|
105
|
+
### 1. Install the module
|
|
106
|
+
|
|
107
|
+
Install the module in your Nuxt application with one command:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npx nuxi@latest module add @nuxtify/core
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### 2. Update Nuxt config
|
|
114
|
+
|
|
115
|
+
Add the `@nuxtify/core` module to `nuxt.config.ts` and configure it:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
// nuxt.config.ts
|
|
119
|
+
|
|
120
|
+
export default defineNuxtConfig({
|
|
121
|
+
modules: ["@nuxtify/core"],
|
|
122
|
+
nuxtifyCore: {
|
|
123
|
+
/* module specific options */
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Read the [π documentation](https://nuxtify.dev/docs) for a complete guide on how to configure and use this module.
|
|
129
|
+
|
|
130
|
+
### 3. Start building!
|
|
131
|
+
|
|
132
|
+
Develop and [deploy](https://nuxt.com/docs/getting-started/deployment) your Nuxt app like any other.
|
|
133
|
+
|
|
134
|
+
## <a name="configuration">π§ Configuration</a>
|
|
135
|
+
|
|
136
|
+
### Module configuration
|
|
137
|
+
|
|
138
|
+
To see the full config, check out the [types](https://github.com/nuxtify-dev/core/blob/main/src/types.ts).
|
|
139
|
+
|
|
140
|
+
### Overriding the defaults
|
|
141
|
+
|
|
142
|
+
Nuxtify comes pre-configured with sensible defaults. Both for how the module functions and for the corresponding Nuxt [directory](https://nuxt.com/docs/guide/directory-structure).
|
|
143
|
+
|
|
144
|
+
If you need to override a [component](https://nuxt.com/docs/guide/directory-structure/components), [page](https://nuxt.com/docs/guide/directory-structure/pages), or [layout](https://nuxt.com/docs/guide/directory-structure/layouts), create the a file with the same name in your project (in the appropriate directory).
|
|
145
|
+
|
|
146
|
+
If you need to override a [composable](https://nuxt.com/docs/guide/directory-structure/composables) or [utils](https://nuxt.com/docs/guide/directory-structure/utils) utility function, create a function with the same name in your project (in the appropriate directory).
|
|
147
|
+
|
|
148
|
+
## <a name="updates">β
Updates</a>
|
|
149
|
+
|
|
150
|
+
[β¨ Release Notes](/CHANGELOG.md)
|
|
151
|
+
|
|
152
|
+
It's easy to stay up to date with the latest version of Nuxtify. Just update to the latest package using your favorite package manager.
|
|
153
|
+
|
|
154
|
+
**Minor and patch versions**
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
npm update @nuxtify/core --save
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Major versions**
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npm install @nuxtify/core@latest --save
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## <a name="contributing">β€οΈ Contributing</a>
|
|
167
|
+
|
|
168
|
+
I invite you to contribute and help improve Nuxtify!
|
|
169
|
+
|
|
170
|
+
Here are a few ways you can get involved:
|
|
171
|
+
|
|
172
|
+
- **Reporting Bugs:** If you come across any bugs or issues, please [open a new issue](https://github.com/nuxtify-dev/core/issues/new).
|
|
173
|
+
- **Suggestions:** Have ideas to enhance Nuxtify? I'd love to hear them! You can [open a new issue](https://github.com/nuxtify-dev/core/issues/new) describing your feature request or suggestion.
|
|
174
|
+
- **Local Development:** contribute directly to the framework with a pull request. Just follow the instructions below.
|
|
175
|
+
|
|
176
|
+
## <a name="local-development">π Local Development</a>
|
|
177
|
+
|
|
178
|
+
### CLI commands
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Install dependencies
|
|
182
|
+
npm install
|
|
183
|
+
|
|
184
|
+
# Generate type stubs
|
|
185
|
+
npm run dev:prepare
|
|
186
|
+
|
|
187
|
+
# Develop with the playground
|
|
188
|
+
npm run dev
|
|
189
|
+
|
|
190
|
+
# Build the playground
|
|
191
|
+
npm run dev:build
|
|
192
|
+
|
|
193
|
+
# Run ESLint
|
|
194
|
+
npm run lint
|
|
195
|
+
|
|
196
|
+
# Run Vitest
|
|
197
|
+
npm run test
|
|
198
|
+
npm run test:watch
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Learn about [authoring Nuxt modules](https://nuxt.com/docs/guide/going-further/modules).
|
|
202
|
+
|
|
203
|
+
## <a name="license">βοΈ License</a>
|
|
204
|
+
|
|
205
|
+
[MIT](https://github.com/nuxtify-dev/core/blob/main/LICENSE)
|
|
206
|
+
|
|
207
|
+
<!-- Badges -->
|
|
208
|
+
|
|
209
|
+
[npm-version-src]: https://img.shields.io/npm/v/@nuxtify/core/latest.svg?style=flat&colorA=020420&colorB=00DC82
|
|
210
|
+
[npm-version-href]: https://npmjs.com/package/@nuxtify/core
|
|
211
|
+
[npm-downloads-src]: https://img.shields.io/npm/dm/@nuxtify/core.svg?style=flat&colorA=020420&colorB=00DC82
|
|
212
|
+
[npm-downloads-href]: https://npm.chart.dev/@nuxtify/core
|
|
213
|
+
[license-src]: https://img.shields.io/npm/l/@nuxtify/core.svg?style=flat&colorA=020420&colorB=00DC82
|
|
214
|
+
[license-href]: https://npmjs.com/package/@nuxtify/core
|
|
215
|
+
[nuxtify-src]: https://img.shields.io/badge/Nuxtify_Docs-00DC82
|
|
216
|
+
[nuxtify-href]: https://nuxtify.dev/docs
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
|
|
3
|
+
interface BrandOptions {
|
|
4
|
+
/**
|
|
5
|
+
* The name of the brand.
|
|
6
|
+
*
|
|
7
|
+
* @default "nuxtify-core"
|
|
8
|
+
*/
|
|
9
|
+
name?: string;
|
|
10
|
+
/**
|
|
11
|
+
* The domain of the brand.
|
|
12
|
+
*
|
|
13
|
+
* @default ""
|
|
14
|
+
*/
|
|
15
|
+
domain?: string;
|
|
16
|
+
/**
|
|
17
|
+
* The tagline of the brand.
|
|
18
|
+
*
|
|
19
|
+
* @default ""
|
|
20
|
+
*/
|
|
21
|
+
tagline?: string;
|
|
22
|
+
/**
|
|
23
|
+
* The logo of the brand.
|
|
24
|
+
*/
|
|
25
|
+
logo?: {
|
|
26
|
+
/**
|
|
27
|
+
* The URL of the light logo. Recommended 5:1 aspect ratio (e.g. 400 x 80 px).
|
|
28
|
+
*
|
|
29
|
+
* @default ""
|
|
30
|
+
*/
|
|
31
|
+
lightUrl?: string;
|
|
32
|
+
/**
|
|
33
|
+
* The URL of the dark logo. Recommended 5:1 aspect ratio (e.g. 400 x 80 px).
|
|
34
|
+
*
|
|
35
|
+
* @default ""
|
|
36
|
+
*/
|
|
37
|
+
darkUrl?: string;
|
|
38
|
+
/**
|
|
39
|
+
* The width of the logo.
|
|
40
|
+
*
|
|
41
|
+
* @default 200
|
|
42
|
+
*/
|
|
43
|
+
width?: number;
|
|
44
|
+
/**
|
|
45
|
+
* The width of the logo on mobile.
|
|
46
|
+
*
|
|
47
|
+
* @default 150
|
|
48
|
+
*/
|
|
49
|
+
mobileWidth?: number;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
interface PoliciesOptions {
|
|
53
|
+
privacyUrl: string;
|
|
54
|
+
termsUrl: string;
|
|
55
|
+
}
|
|
56
|
+
interface ModuleOptions {
|
|
57
|
+
/**
|
|
58
|
+
* Brand options
|
|
59
|
+
*/
|
|
60
|
+
brand?: BrandOptions;
|
|
61
|
+
/**
|
|
62
|
+
* Policies options
|
|
63
|
+
*/
|
|
64
|
+
policies?: PoliciesOptions;
|
|
65
|
+
/**
|
|
66
|
+
* Announcement banner options
|
|
67
|
+
*/
|
|
68
|
+
announcement?: {
|
|
69
|
+
show?: boolean;
|
|
70
|
+
message?: string;
|
|
71
|
+
buttonText?: string;
|
|
72
|
+
buttonUrl?: string;
|
|
73
|
+
};
|
|
74
|
+
/**
|
|
75
|
+
* Credits options
|
|
76
|
+
*/
|
|
77
|
+
credits?: {
|
|
78
|
+
creator?: {
|
|
79
|
+
name?: string;
|
|
80
|
+
domain?: string;
|
|
81
|
+
};
|
|
82
|
+
prependText?: string;
|
|
83
|
+
appendText?: string;
|
|
84
|
+
showPoweredBy?: boolean;
|
|
85
|
+
};
|
|
86
|
+
/**
|
|
87
|
+
* Email options
|
|
88
|
+
*/
|
|
89
|
+
email?: {
|
|
90
|
+
general?: string;
|
|
91
|
+
support?: string;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
96
|
+
|
|
97
|
+
export { _default as default };
|
package/dist/module.json
ADDED
package/dist/module.mjs
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { defineNuxtModule, createResolver, installModule, addComponentsDir, addImportsDir, addServerImportsDir } from '@nuxt/kit';
|
|
2
|
+
import { defu } from 'defu';
|
|
3
|
+
|
|
4
|
+
const module = defineNuxtModule({
|
|
5
|
+
meta: {
|
|
6
|
+
name: "nuxtify-core",
|
|
7
|
+
configKey: "nuxtifyCore",
|
|
8
|
+
compatibility: {
|
|
9
|
+
nuxt: ">=3.16.0",
|
|
10
|
+
bridge: false
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
defaults: {
|
|
14
|
+
// Brand
|
|
15
|
+
brand: {
|
|
16
|
+
name: "nuxtify-core",
|
|
17
|
+
domain: "",
|
|
18
|
+
tagline: "",
|
|
19
|
+
logo: {
|
|
20
|
+
lightUrl: "",
|
|
21
|
+
darkUrl: "",
|
|
22
|
+
width: 200,
|
|
23
|
+
mobileWidth: 150
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
// Policies
|
|
27
|
+
policies: {
|
|
28
|
+
privacyUrl: "/privacy",
|
|
29
|
+
termsUrl: "/terms"
|
|
30
|
+
},
|
|
31
|
+
// Announcement
|
|
32
|
+
announcement: {
|
|
33
|
+
show: false,
|
|
34
|
+
message: "",
|
|
35
|
+
buttonText: "",
|
|
36
|
+
buttonUrl: ""
|
|
37
|
+
},
|
|
38
|
+
// Credits
|
|
39
|
+
credits: {
|
|
40
|
+
creator: {
|
|
41
|
+
name: "",
|
|
42
|
+
domain: ""
|
|
43
|
+
},
|
|
44
|
+
prependText: "",
|
|
45
|
+
appendText: "",
|
|
46
|
+
showPoweredBy: true
|
|
47
|
+
},
|
|
48
|
+
// Email
|
|
49
|
+
email: {
|
|
50
|
+
general: "",
|
|
51
|
+
support: ""
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
async setup(_options, _nuxt) {
|
|
55
|
+
const resolver = createResolver(import.meta.url);
|
|
56
|
+
await installModule("vuetify-nuxt-module", {
|
|
57
|
+
vuetifyOptions: {
|
|
58
|
+
icons: {
|
|
59
|
+
defaultSet: "mdi-svg"
|
|
60
|
+
},
|
|
61
|
+
theme: {
|
|
62
|
+
themes: {
|
|
63
|
+
light: {
|
|
64
|
+
colors: {
|
|
65
|
+
primary: "#020420",
|
|
66
|
+
secondary: "#00DC82",
|
|
67
|
+
background: "#fff"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
defaults: {
|
|
73
|
+
VBtn: { color: "secondary", variant: "flat", class: "text-none" },
|
|
74
|
+
VAlert: {
|
|
75
|
+
VBtn: { color: "inherit" }
|
|
76
|
+
},
|
|
77
|
+
VFooter: {
|
|
78
|
+
VBtn: { color: "inherit" }
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
_nuxt.options.appConfig.nuxtify = defu(_nuxt.options.appConfig.nuxtify, {
|
|
84
|
+
..._options
|
|
85
|
+
});
|
|
86
|
+
addComponentsDir({
|
|
87
|
+
path: resolver.resolve("./runtime/components")
|
|
88
|
+
});
|
|
89
|
+
addImportsDir(resolver.resolve("./runtime/composables"));
|
|
90
|
+
addServerImportsDir(resolver.resolve("./runtime/server/composables"));
|
|
91
|
+
addImportsDir(resolver.resolve("./runtime/utils"));
|
|
92
|
+
addServerImportsDir(resolver.resolve("./runtime/server/utils"));
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
export { module as default };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, isExternalUrl, useDisplay, useNuxtifyConfig } from "#imports";
|
|
3
|
+
const nuxtifyConfig = useNuxtifyConfig();
|
|
4
|
+
const { xs } = useDisplay();
|
|
5
|
+
const isExternalLink = computed(
|
|
6
|
+
() => isExternalUrl(nuxtifyConfig.announcement?.buttonUrl ?? "", nuxtifyConfig.brand?.domain ?? "")
|
|
7
|
+
);
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<v-system-bar
|
|
12
|
+
:height="xs ? 60 : 40"
|
|
13
|
+
:order="-100"
|
|
14
|
+
color="primary"
|
|
15
|
+
class="justify-center text-start"
|
|
16
|
+
>
|
|
17
|
+
<div
|
|
18
|
+
v-if="nuxtifyConfig.announcement?.message"
|
|
19
|
+
:class="`${xs ? 'text-subtitle-2' : 'text-subtitle-1'} mr-4`"
|
|
20
|
+
>
|
|
21
|
+
{{ nuxtifyConfig.announcement.message }}
|
|
22
|
+
</div>
|
|
23
|
+
<v-btn
|
|
24
|
+
v-if="
|
|
25
|
+
nuxtifyConfig.announcement?.buttonText && nuxtifyConfig.announcement.buttonUrl
|
|
26
|
+
"
|
|
27
|
+
:to="!isExternalLink ? nuxtifyConfig.announcement.buttonUrl : void 0"
|
|
28
|
+
:href="isExternalLink ? nuxtifyConfig.announcement.buttonUrl : void 0"
|
|
29
|
+
size="small"
|
|
30
|
+
variant="flat"
|
|
31
|
+
color="secondary"
|
|
32
|
+
>
|
|
33
|
+
{{ nuxtifyConfig.announcement.buttonText }}
|
|
34
|
+
</v-btn>
|
|
35
|
+
</v-system-bar>
|
|
36
|
+
</template>
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useDialog } from "#imports";
|
|
3
|
+
const dialog = useDialog();
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<v-dialog
|
|
8
|
+
v-model="dialog.show"
|
|
9
|
+
width="500"
|
|
10
|
+
>
|
|
11
|
+
<v-card class="pa-2">
|
|
12
|
+
<v-card-title>{{ dialog.title }}</v-card-title>
|
|
13
|
+
|
|
14
|
+
<v-card-text class="ml-n2">
|
|
15
|
+
{{ dialog.message }}
|
|
16
|
+
</v-card-text>
|
|
17
|
+
|
|
18
|
+
<v-card-actions>
|
|
19
|
+
<v-spacer />
|
|
20
|
+
|
|
21
|
+
<v-btn
|
|
22
|
+
color="grey-darken-1"
|
|
23
|
+
@click="dialog.show = false"
|
|
24
|
+
>
|
|
25
|
+
{{ dialog.closeButtonText }}
|
|
26
|
+
</v-btn>
|
|
27
|
+
|
|
28
|
+
<v-btn
|
|
29
|
+
:color="dialog.action.buttonColor || 'secondary'"
|
|
30
|
+
variant="flat"
|
|
31
|
+
@click="dialog.action.function"
|
|
32
|
+
>
|
|
33
|
+
{{ dialog.action.buttonText }}
|
|
34
|
+
</v-btn>
|
|
35
|
+
</v-card-actions>
|
|
36
|
+
</v-card>
|
|
37
|
+
</v-dialog>
|
|
38
|
+
</template>
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="center">
|
|
3
|
+
<div class="sk-chase">
|
|
4
|
+
<div class="sk-chase-dot" />
|
|
5
|
+
<div class="sk-chase-dot" />
|
|
6
|
+
<div class="sk-chase-dot" />
|
|
7
|
+
<div class="sk-chase-dot" />
|
|
8
|
+
<div class="sk-chase-dot" />
|
|
9
|
+
<div class="sk-chase-dot" />
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<style scoped>
|
|
15
|
+
.center{align-items:center;display:flex;height:100vh;justify-content:center}.sk-chase{animation:sk-chase 2.5s linear infinite both;height:40px;position:relative;width:40px}.sk-chase-dot{animation:sk-chase-dot 2s ease-in-out infinite both;height:100%;left:0;position:absolute;top:0;width:100%}.sk-chase-dot:before{animation:sk-chase-dot-before 2s ease-in-out infinite both;background-color:rgb(var(--v-theme-primary));border-radius:100%;content:"";display:block;height:25%;width:25%}.sk-chase-dot:first-child{animation-delay:-1.1s}.sk-chase-dot:nth-child(2){animation-delay:-1s}.sk-chase-dot:nth-child(3){animation-delay:-.9s}.sk-chase-dot:nth-child(4){animation-delay:-.8s}.sk-chase-dot:nth-child(5){animation-delay:-.7s}.sk-chase-dot:nth-child(6){animation-delay:-.6s}.sk-chase-dot:first-child:before{animation-delay:-1.1s}.sk-chase-dot:nth-child(2):before{animation-delay:-1s}.sk-chase-dot:nth-child(3):before{animation-delay:-.9s}.sk-chase-dot:nth-child(4):before{animation-delay:-.8s}.sk-chase-dot:nth-child(5):before{animation-delay:-.7s}.sk-chase-dot:nth-child(6):before{animation-delay:-.6s}@keyframes sk-chase{to{transform:rotate(1turn)}}@keyframes sk-chase-dot{80%,to{transform:rotate(1turn)}}@keyframes sk-chase-dot-before{50%{transform:scale(.4)}0%,to{transform:scale(1)}}
|
|
16
|
+
</style>
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { computed, useAppConfig, useDisplay } from "#imports";
|
|
3
|
+
const props = defineProps({
|
|
4
|
+
dark: {
|
|
5
|
+
type: Boolean,
|
|
6
|
+
default: false
|
|
7
|
+
},
|
|
8
|
+
width: {
|
|
9
|
+
type: Number,
|
|
10
|
+
default: void 0
|
|
11
|
+
}
|
|
12
|
+
});
|
|
13
|
+
const nuxtifyConfig = useAppConfig().nuxtify;
|
|
14
|
+
const { smAndDown } = useDisplay();
|
|
15
|
+
let imageUrl = nuxtifyConfig.brand.logo.lightUrl;
|
|
16
|
+
if (props.dark && nuxtifyConfig.brand.logo.darkUrl) {
|
|
17
|
+
imageUrl = nuxtifyConfig.brand.logo.darkUrl;
|
|
18
|
+
}
|
|
19
|
+
const width = computed(() => {
|
|
20
|
+
if (props.width) {
|
|
21
|
+
return props.width;
|
|
22
|
+
} else {
|
|
23
|
+
return smAndDown.value ? nuxtifyConfig.brand.logo.mobileWidth : nuxtifyConfig.brand.logo.width;
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<template>
|
|
29
|
+
<v-img
|
|
30
|
+
v-if="imageUrl"
|
|
31
|
+
:width
|
|
32
|
+
:src="imageUrl"
|
|
33
|
+
:alt="`${nuxtifyConfig.brand.name} logo`"
|
|
34
|
+
/>
|
|
35
|
+
<span
|
|
36
|
+
v-else
|
|
37
|
+
:class="`text-subtitle-1 text-sm-h6 ${dark ? '' : 'text-primary'}`"
|
|
38
|
+
>
|
|
39
|
+
{{ nuxtifyConfig.brand.name }}
|
|
40
|
+
</span>
|
|
41
|
+
</template>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
2
|
+
dark: {
|
|
3
|
+
type: BooleanConstructor;
|
|
4
|
+
default: boolean;
|
|
5
|
+
};
|
|
6
|
+
width: {
|
|
7
|
+
type: NumberConstructor;
|
|
8
|
+
default: undefined;
|
|
9
|
+
};
|
|
10
|
+
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
11
|
+
dark: {
|
|
12
|
+
type: BooleanConstructor;
|
|
13
|
+
default: boolean;
|
|
14
|
+
};
|
|
15
|
+
width: {
|
|
16
|
+
type: NumberConstructor;
|
|
17
|
+
default: undefined;
|
|
18
|
+
};
|
|
19
|
+
}>> & Readonly<{}>, {
|
|
20
|
+
width: number;
|
|
21
|
+
dark: boolean;
|
|
22
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
23
|
+
export default _default;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useToast } from "#imports";
|
|
3
|
+
const toast = useToast();
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<template>
|
|
7
|
+
<v-snackbar
|
|
8
|
+
v-model="toast.show"
|
|
9
|
+
:timeout="5e3"
|
|
10
|
+
color="info"
|
|
11
|
+
:min-width="0"
|
|
12
|
+
close-on-content-click
|
|
13
|
+
>
|
|
14
|
+
{{ toast.message }}
|
|
15
|
+
</v-snackbar>
|
|
16
|
+
</template>
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
export default _default;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface Dialog {
|
|
2
|
+
show: boolean;
|
|
3
|
+
title: string;
|
|
4
|
+
message: string;
|
|
5
|
+
action: {
|
|
6
|
+
function: (() => Promise<void>) | (() => void) | null;
|
|
7
|
+
buttonText: string;
|
|
8
|
+
buttonColor: string;
|
|
9
|
+
};
|
|
10
|
+
closeButtonText: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const dialogInitialState: Dialog;
|
|
13
|
+
export declare const useDialog: () => import("vue").Ref<Dialog, Dialog>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useState } from "#imports";
|
|
2
|
+
export const dialogInitialState = {
|
|
3
|
+
show: false,
|
|
4
|
+
title: "",
|
|
5
|
+
message: "",
|
|
6
|
+
action: {
|
|
7
|
+
function: null,
|
|
8
|
+
buttonText: "Confirm",
|
|
9
|
+
buttonColor: ""
|
|
10
|
+
},
|
|
11
|
+
closeButtonText: "Cancel"
|
|
12
|
+
};
|
|
13
|
+
export const useDialog = () => useState("dialog", () => {
|
|
14
|
+
return dialogInitialState;
|
|
15
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const useDrawer: () => import("vue").Ref<boolean | null, boolean | null>;
|
|
2
|
+
export declare const useErrorMessage: () => import("vue").Ref<string, string>;
|
|
3
|
+
export declare const useToast: () => import("vue").Ref<{
|
|
4
|
+
show: boolean;
|
|
5
|
+
message: string;
|
|
6
|
+
} | {
|
|
7
|
+
show: boolean;
|
|
8
|
+
message: string;
|
|
9
|
+
}, {
|
|
10
|
+
show: boolean;
|
|
11
|
+
message: string;
|
|
12
|
+
} | {
|
|
13
|
+
show: boolean;
|
|
14
|
+
message: string;
|
|
15
|
+
}>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ref, useState } from "#imports";
|
|
2
|
+
export const useDrawer = () => useState("drawer", () => null);
|
|
3
|
+
export const useErrorMessage = () => useState("errorMessage", () => "");
|
|
4
|
+
export const useToast = () => useState(
|
|
5
|
+
"toast",
|
|
6
|
+
() => ref({
|
|
7
|
+
show: false,
|
|
8
|
+
message: ""
|
|
9
|
+
})
|
|
10
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useNuxtifyConfig } from '../../composables/nuxtify.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useNuxtifyConfig } from "../../composables/nuxtify.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { slugify, unslugify } from '../../utils/text.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { slugify, unslugify } from "../../utils/text.js";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const formRules: {
|
|
2
|
+
required: (v: string) => true | "Required";
|
|
3
|
+
requiredArray: <T>(v: Array<T>) => true | "Required";
|
|
4
|
+
validEmail: (v: string) => true | "Must be a valid email address";
|
|
5
|
+
minLength8: (v: string) => true | "Must be at least 8 characters";
|
|
6
|
+
minLength12: (v: string) => true | "Must be at least 12 characters";
|
|
7
|
+
maxLength30: (v: string) => true | "Must not be longer than 30 characters";
|
|
8
|
+
maxLength60: (v: string) => true | "Must not be longer than 60 characters";
|
|
9
|
+
maxLength120: (v: string) => true | "Must not be longer than 120 characters";
|
|
10
|
+
maxLength200: (v: string) => true | "Must not be longer than 200 characters";
|
|
11
|
+
maxLength300: (v: string) => true | "Must not be longer than 300 characters";
|
|
12
|
+
maxLength600: (v: string) => true | "Must not be longer than 600 characters";
|
|
13
|
+
maxLength1200: (v: string) => true | "Must not be longer than 1200 characters";
|
|
14
|
+
isInteger: (v: string) => true | "Must be an integer";
|
|
15
|
+
gt0: (v: string) => true | "Must be greater than 0";
|
|
16
|
+
gte6: (v: string) => true | "Must be greater than or equal to 6";
|
|
17
|
+
lte12: (v: string) => true | "Must be less than or equal to 12";
|
|
18
|
+
lte365: (v: string) => true | "Must be less than or equal to 365";
|
|
19
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const formRules = {
|
|
2
|
+
// Required
|
|
3
|
+
required: (v) => !!v || "Required",
|
|
4
|
+
requiredArray: (v) => !!v.length || "Required",
|
|
5
|
+
// Text
|
|
6
|
+
validEmail: (v) => /.+@.+/.test(v) || "Must be a valid email address",
|
|
7
|
+
// Length
|
|
8
|
+
minLength8: (v) => v ? v.length >= 8 || "Must be at least 8 characters" : true,
|
|
9
|
+
minLength12: (v) => v ? v.length >= 12 || "Must be at least 12 characters" : true,
|
|
10
|
+
maxLength30: (v) => v ? v.length <= 30 || "Must not be longer than 30 characters" : true,
|
|
11
|
+
maxLength60: (v) => v ? v.length <= 60 || "Must not be longer than 60 characters" : true,
|
|
12
|
+
maxLength120: (v) => v ? v.length <= 120 || "Must not be longer than 120 characters" : true,
|
|
13
|
+
maxLength200: (v) => v ? v.length <= 200 || "Must not be longer than 200 characters" : true,
|
|
14
|
+
maxLength300: (v) => v ? v.length <= 300 || "Must not be longer than 300 characters" : true,
|
|
15
|
+
maxLength600: (v) => v ? v.length <= 600 || "Must not be longer than 600 characters" : true,
|
|
16
|
+
maxLength1200: (v) => v ? v.length <= 1200 || "Must not be longer than 1200 characters" : true,
|
|
17
|
+
// Number
|
|
18
|
+
isInteger: (v) => Number.isInteger(+v) || "Must be an integer",
|
|
19
|
+
gt0: (v) => Number.parseFloat(v) > 0 || "Must be greater than 0",
|
|
20
|
+
gte6: (v) => Number.parseFloat(v) >= 6 || "Must be greater than or equal to 6",
|
|
21
|
+
lte12: (v) => Number.parseFloat(v) <= 12 || "Must be less than or equal to 12",
|
|
22
|
+
lte365: (v) => Number.parseFloat(v) <= 365 || "Must be less than or equal to 365"
|
|
23
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function blobToDataURL(blob) {
|
|
2
|
+
return new Promise((resolve, reject) => {
|
|
3
|
+
const reader = new FileReader();
|
|
4
|
+
reader.onload = (_e) => resolve(reader.result);
|
|
5
|
+
reader.onerror = (_e) => reject(reader.error);
|
|
6
|
+
reader.onabort = (_e) => reject(new Error("Read aborted"));
|
|
7
|
+
reader.readAsDataURL(blob);
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
export function filenameToUrl(filename, timestamped = false) {
|
|
11
|
+
const filenameClean = encodeURIComponent(
|
|
12
|
+
filename.trim().replace(/[^a-z0-9.-]/gi, "-").replace(/-{2,}/g, "-").replace(/\.{2,}/g, ".").replace(/-\./g, ".").replace(/-$/g, "").replace(/^-/g, "").slice(0, 500)
|
|
13
|
+
// limit to the first 500 characters
|
|
14
|
+
);
|
|
15
|
+
if (timestamped) {
|
|
16
|
+
return `${Date.now()}-${filenameClean}`;
|
|
17
|
+
}
|
|
18
|
+
return filenameClean;
|
|
19
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function toPercentage(val, decimals = 0) {
|
|
2
|
+
const percentage = (val * 100).toFixed(decimals);
|
|
3
|
+
return `${percentage}%`;
|
|
4
|
+
}
|
|
5
|
+
export function roundToFixed(val, positions = 2) {
|
|
6
|
+
let text = 0;
|
|
7
|
+
if (typeof val === "string") {
|
|
8
|
+
text = +Number.parseFloat(val).toFixed(positions);
|
|
9
|
+
} else if (typeof val === "number") {
|
|
10
|
+
text = +val.toFixed(positions);
|
|
11
|
+
}
|
|
12
|
+
return text;
|
|
13
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare const titleCase: (text: string, skipShortWords?: boolean) => string;
|
|
2
|
+
export declare function capitalizeFirstLetter(text: string): string;
|
|
3
|
+
export declare function fullName(firstName: string, lastName: string): string;
|
|
4
|
+
export declare function parseFullName(fullName: string | undefined | null): {
|
|
5
|
+
firstName: string;
|
|
6
|
+
lastName: string;
|
|
7
|
+
};
|
|
8
|
+
export declare const honoraryName: (name: string, honorificSuffix?: string) => string;
|
|
9
|
+
export declare function getPronouns(gender: string): {
|
|
10
|
+
single: string;
|
|
11
|
+
plural: string;
|
|
12
|
+
possessive: string;
|
|
13
|
+
possessivePlural: string;
|
|
14
|
+
};
|
|
15
|
+
export declare const formatPhone: (input: string, separator?: string) => string;
|
|
16
|
+
export declare function formatDate(date: string, locale?: string): string;
|
|
17
|
+
export declare function formatDateTime(date: string, locale?: string): string;
|
|
18
|
+
export declare function booleanToText(bool: boolean): "Yes" | "No";
|
|
19
|
+
export declare const truncate: (text: string, maxLength?: number, ellipses?: boolean) => string;
|
|
20
|
+
export declare const slugify: (text: string) => string;
|
|
21
|
+
export declare const unslugify: (text: string) => string;
|
|
22
|
+
export declare function pluralize(value: number, units: string, showValue?: boolean): string;
|
|
23
|
+
export declare const getLanguageName: (languageCode: string, displayLanguage?: string) => string | undefined;
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
export const titleCase = (text, skipShortWords = true) => {
|
|
2
|
+
const shortWords = ["and", "an", "the", "a", "but", "for", "at", "by", "to"];
|
|
3
|
+
const words = text.split(" ");
|
|
4
|
+
const titleWords = [];
|
|
5
|
+
for (const [i] of words.entries()) {
|
|
6
|
+
if (skipShortWords && shortWords.includes(words[i])) {
|
|
7
|
+
if (i === 0) {
|
|
8
|
+
titleWords.push(words[i].charAt(0).toUpperCase() + words[i].slice(1));
|
|
9
|
+
} else {
|
|
10
|
+
titleWords.push(words[i]);
|
|
11
|
+
}
|
|
12
|
+
} else {
|
|
13
|
+
titleWords.push(words[i].charAt(0).toUpperCase() + words[i].slice(1));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return titleWords.join(" ");
|
|
17
|
+
};
|
|
18
|
+
export function capitalizeFirstLetter(text) {
|
|
19
|
+
if (!text) {
|
|
20
|
+
return "";
|
|
21
|
+
}
|
|
22
|
+
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
23
|
+
}
|
|
24
|
+
export function fullName(firstName, lastName) {
|
|
25
|
+
let name = "";
|
|
26
|
+
if (firstName && lastName) {
|
|
27
|
+
name = `${firstName} ${lastName}`;
|
|
28
|
+
} else if (firstName) {
|
|
29
|
+
name = firstName;
|
|
30
|
+
} else if (lastName) {
|
|
31
|
+
name = lastName;
|
|
32
|
+
}
|
|
33
|
+
return name;
|
|
34
|
+
}
|
|
35
|
+
export function parseFullName(fullName2) {
|
|
36
|
+
let firstName = "";
|
|
37
|
+
let lastName = "";
|
|
38
|
+
if (fullName2) {
|
|
39
|
+
const nameSplit = fullName2.split(" ");
|
|
40
|
+
firstName = nameSplit[0];
|
|
41
|
+
if (nameSplit.length > 1) {
|
|
42
|
+
lastName = nameSplit.slice(1).join(" ");
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return { firstName, lastName };
|
|
46
|
+
}
|
|
47
|
+
export const honoraryName = (name, honorificSuffix = "") => {
|
|
48
|
+
return honorificSuffix ? `${name}, ${honorificSuffix}` : name;
|
|
49
|
+
};
|
|
50
|
+
export function getPronouns(gender) {
|
|
51
|
+
if (gender === "male") {
|
|
52
|
+
return {
|
|
53
|
+
single: "he",
|
|
54
|
+
plural: "he's",
|
|
55
|
+
possessive: "his",
|
|
56
|
+
possessivePlural: "his"
|
|
57
|
+
};
|
|
58
|
+
} else if (gender === "female") {
|
|
59
|
+
return {
|
|
60
|
+
single: "she",
|
|
61
|
+
plural: "she's",
|
|
62
|
+
possessive: "her",
|
|
63
|
+
possessivePlural: "her's"
|
|
64
|
+
};
|
|
65
|
+
} else {
|
|
66
|
+
return {
|
|
67
|
+
single: "they",
|
|
68
|
+
plural: "they're",
|
|
69
|
+
possessive: "their",
|
|
70
|
+
possessivePlural: "theirs"
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
export const formatPhone = (input, separator = "-") => {
|
|
75
|
+
let phone = input;
|
|
76
|
+
if (phone.slice(0, 2) === "+1") {
|
|
77
|
+
phone = phone.slice(2);
|
|
78
|
+
}
|
|
79
|
+
if (phone.length === 10) {
|
|
80
|
+
phone = phone.replace(
|
|
81
|
+
/(\d{3})(\d{3})(\d{4})/,
|
|
82
|
+
`$1${separator}$2${separator}$3`
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
return phone;
|
|
86
|
+
};
|
|
87
|
+
export function formatDate(date, locale = "en-us") {
|
|
88
|
+
return new Date(date).toLocaleDateString(locale, {
|
|
89
|
+
year: "numeric",
|
|
90
|
+
month: "long",
|
|
91
|
+
day: "numeric"
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
export function formatDateTime(date, locale = "en-us") {
|
|
95
|
+
return new Date(date).toLocaleString(locale, {
|
|
96
|
+
year: "numeric",
|
|
97
|
+
month: "long",
|
|
98
|
+
day: "numeric",
|
|
99
|
+
hour: "numeric",
|
|
100
|
+
minute: "numeric"
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
export function booleanToText(bool) {
|
|
104
|
+
return bool ? "Yes" : "No";
|
|
105
|
+
}
|
|
106
|
+
export const truncate = (text, maxLength = 80, ellipses = true) => {
|
|
107
|
+
if (text.length > maxLength) {
|
|
108
|
+
let trimmedString = text.substring(0, maxLength + 1);
|
|
109
|
+
trimmedString = trimmedString.substring(
|
|
110
|
+
0,
|
|
111
|
+
Math.min(trimmedString.length, trimmedString.lastIndexOf(" "))
|
|
112
|
+
);
|
|
113
|
+
return `${trimmedString}${ellipses ? "..." : ""}`;
|
|
114
|
+
}
|
|
115
|
+
return text;
|
|
116
|
+
};
|
|
117
|
+
export const slugify = (text) => {
|
|
118
|
+
return text.normalize("NFKD").toLowerCase().trim().replace(/[^a-z0-9\s_-]/g, "").replace(/[\s_]+/g, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "");
|
|
119
|
+
};
|
|
120
|
+
export const unslugify = (text) => {
|
|
121
|
+
return text.replace(/-/g, " ");
|
|
122
|
+
};
|
|
123
|
+
export function pluralize(value, units, showValue = true) {
|
|
124
|
+
let text = "";
|
|
125
|
+
let unitsPlural = units;
|
|
126
|
+
if (unitsPlural.slice(-1) === "y") {
|
|
127
|
+
unitsPlural = unitsPlural.slice(0, -1) + "ies";
|
|
128
|
+
} else {
|
|
129
|
+
unitsPlural = units + "s";
|
|
130
|
+
}
|
|
131
|
+
if (showValue) {
|
|
132
|
+
if (value === 1) {
|
|
133
|
+
text = `${value} ${units}`;
|
|
134
|
+
} else {
|
|
135
|
+
text = `${value} ${unitsPlural}`;
|
|
136
|
+
}
|
|
137
|
+
} else if (!value || value === 1) {
|
|
138
|
+
text = `${units}`;
|
|
139
|
+
} else {
|
|
140
|
+
text = `${unitsPlural}`;
|
|
141
|
+
}
|
|
142
|
+
return text;
|
|
143
|
+
}
|
|
144
|
+
export const getLanguageName = (languageCode, displayLanguage = "en") => {
|
|
145
|
+
try {
|
|
146
|
+
const languageNames = new Intl.DisplayNames([displayLanguage], {
|
|
147
|
+
type: "language"
|
|
148
|
+
});
|
|
149
|
+
return languageNames.of(languageCode);
|
|
150
|
+
} catch (error) {
|
|
151
|
+
console.error(
|
|
152
|
+
`Error getting language name for code '${languageCode}' with locale '${displayLanguage}':`,
|
|
153
|
+
error
|
|
154
|
+
);
|
|
155
|
+
return languageCode;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
2
|
+
export function daysSince(targetDate) {
|
|
3
|
+
const currentDate = /* @__PURE__ */ new Date();
|
|
4
|
+
const timeDifference = currentDate.getTime() - targetDate.getTime();
|
|
5
|
+
const daysDifference = Math.floor(timeDifference / (1e3 * 60 * 60 * 24));
|
|
6
|
+
return daysDifference;
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const getBaseUrl: (url: string) => string;
|
|
2
|
+
export declare const getUtmParams: (url: string) => {
|
|
3
|
+
utmSource: string | null;
|
|
4
|
+
utmMedium: string | null;
|
|
5
|
+
utmCampaign: string | null;
|
|
6
|
+
utmTerm: string | null;
|
|
7
|
+
utmContent: string | null;
|
|
8
|
+
};
|
|
9
|
+
export declare const isExternalUrl: (url: string, hostname: string) => boolean;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const getBaseUrl = (url) => {
|
|
2
|
+
const urlObject = new URL(url);
|
|
3
|
+
urlObject.search = "";
|
|
4
|
+
urlObject.hash = "";
|
|
5
|
+
return urlObject.href;
|
|
6
|
+
};
|
|
7
|
+
export const getUtmParams = (url) => {
|
|
8
|
+
const urlSearchParams = new URLSearchParams(new URL(url).search);
|
|
9
|
+
return {
|
|
10
|
+
utmSource: urlSearchParams.get("utm_source"),
|
|
11
|
+
utmMedium: urlSearchParams.get("utm_medium"),
|
|
12
|
+
utmCampaign: urlSearchParams.get("utm_campaign"),
|
|
13
|
+
utmTerm: urlSearchParams.get("utm_term"),
|
|
14
|
+
utmContent: urlSearchParams.get("utm_content")
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export const isExternalUrl = (url, hostname) => {
|
|
18
|
+
if (!url) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
if (url.startsWith("/")) {
|
|
22
|
+
return false;
|
|
23
|
+
} else {
|
|
24
|
+
const linkHostname = new URL(url).hostname;
|
|
25
|
+
return linkHostname !== hostname;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function youTubeUrl(url: string): string | null;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function youTubeId(url) {
|
|
2
|
+
const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
|
|
3
|
+
const match = url.match(regExp);
|
|
4
|
+
return match && match[2].length === 11 ? match[2] : null;
|
|
5
|
+
}
|
|
6
|
+
export function youTubeUrl(url) {
|
|
7
|
+
const videoId = youTubeId(url);
|
|
8
|
+
if (videoId) {
|
|
9
|
+
return `https://www.youtube.com/embed/${videoId}`;
|
|
10
|
+
} else {
|
|
11
|
+
return null;
|
|
12
|
+
}
|
|
13
|
+
}
|
package/dist/types.d.mts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nuxtify/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Nuxtify core module powered by Nuxt and Vuetify.",
|
|
5
|
+
"homepage": "https://nuxtify.dev/",
|
|
6
|
+
"author": "Nuxtify.dev <hello@nuxtify.dev>",
|
|
7
|
+
"funding": "https://github.com/sponsors/davidstackio",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/nuxtify-dev/core"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/nuxtify-dev/core/issues"
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"type": "module",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/types.d.mts",
|
|
20
|
+
"import": "./dist/module.mjs"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"main": "./dist/module.mjs",
|
|
24
|
+
"typesVersions": {
|
|
25
|
+
"*": {
|
|
26
|
+
".": [
|
|
27
|
+
"./dist/types.d.mts"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"prepack": "nuxt-module-build build",
|
|
36
|
+
"dev": "nuxi dev playground",
|
|
37
|
+
"dev:build": "nuxi build playground",
|
|
38
|
+
"dev:prepare": "nuxt-module-build build --stub && nuxt-module-build prepare && nuxi prepare playground",
|
|
39
|
+
"release": "npm run lint && npm run test && npm run prepack && changelogen --release && npm publish && git push --follow-tags",
|
|
40
|
+
"lint": "eslint .",
|
|
41
|
+
"test": "vitest run",
|
|
42
|
+
"test:watch": "vitest watch",
|
|
43
|
+
"test:types": "vue-tsc --noEmit && cd playground && vue-tsc --noEmit"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@mdi/js": "^7.4.47",
|
|
47
|
+
"@nuxt/kit": "^3.17.3",
|
|
48
|
+
"defu": "^6.1.4",
|
|
49
|
+
"vuetify-nuxt-module": "^0.18.6"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@nuxt/devtools": "^2.4.0",
|
|
53
|
+
"@nuxt/eslint": "^1.3.1",
|
|
54
|
+
"@nuxt/eslint-config": "^1.3.1",
|
|
55
|
+
"@nuxt/module-builder": "^1.0.1",
|
|
56
|
+
"@nuxt/schema": "^3.17.3",
|
|
57
|
+
"@nuxt/test-utils": "^3.18.0",
|
|
58
|
+
"@types/node": "^22.15.18",
|
|
59
|
+
"changelogen": "^0.6.1",
|
|
60
|
+
"eslint": "^9.26.0",
|
|
61
|
+
"nuxt": "^3.17.3",
|
|
62
|
+
"typescript": "~5.8.3",
|
|
63
|
+
"vitest": "^3.1.3",
|
|
64
|
+
"vue-tsc": "^2.2.10"
|
|
65
|
+
}
|
|
66
|
+
}
|