nuxt-ignis 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/.gitattributes +2 -0
- package/.github/dependabot.yml +16 -0
- package/.vscode/settings.json +9 -0
- package/LICENSE +21 -0
- package/README.md +90 -0
- package/app.config.ts +3 -0
- package/app.vue +52 -0
- package/assets/css/open-props.css +20 -0
- package/assets/css/tailwind.css +49 -0
- package/assets/lang/en.json +25 -0
- package/components/AppFeature.vue +62 -0
- package/components/CurrentTime.vue +30 -0
- package/composables/useTranslation.ts +48 -0
- package/eslint.config.mjs +40 -0
- package/features.ts +110 -0
- package/formkit.config.ts +11 -0
- package/i18n.config.ts +12 -0
- package/nuxt.config.ts +53 -0
- package/package.json +43 -0
- package/pages/index.vue +51 -0
- package/pages/second.vue +27 -0
- package/public/favicon.ico +0 -0
- package/public/nuxt-ignis.png +0 -0
- package/public/unsplash.jpg +0 -0
- package/tailwind.config.ts +28 -0
- package/tsconfig.json +7 -0
- package/utils/consola.ts +92 -0
- package/utils/ignis-types.ts +21 -0
package/.gitattributes
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
2
|
+
# https://github.blog/2023-08-24-a-faster-way-to-manage-version-updates-with-dependabot/
|
|
3
|
+
|
|
4
|
+
version: 2
|
|
5
|
+
updates:
|
|
6
|
+
- package-ecosystem: "npm"
|
|
7
|
+
directory: "/"
|
|
8
|
+
schedule:
|
|
9
|
+
interval: "monthly"
|
|
10
|
+
time: "05:10"
|
|
11
|
+
commit-message:
|
|
12
|
+
prefix: "npm"
|
|
13
|
+
groups:
|
|
14
|
+
all:
|
|
15
|
+
patterns:
|
|
16
|
+
- "*"
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Alois Sečkár
|
|
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,90 @@
|
|
|
1
|
+
# Nuxt Ignis
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
This is a template starter for Nuxt web applicatons. It is being build as the setup I'd currently use to start with a new "real world" [Nuxt](https://nuxt.com/) webapp. It will improve and grow together with my skills. I also try to include **WHAT** and **WHY** comments based on my knowledge about the framework and used libraries.
|
|
6
|
+
|
|
7
|
+
## How to use
|
|
8
|
+
|
|
9
|
+
### As standalone template
|
|
10
|
+
1. Do a `git checkout` from https://github.com/AloisSeckar/nuxt-ignis.git
|
|
11
|
+
2. Open in IDE and run `pnpm install` in terminal
|
|
12
|
+
3. Configure modules via `.env` properties
|
|
13
|
+
4. Start dev server with `pnpm dev` command
|
|
14
|
+
5. Visit `localhost:3000` in browser
|
|
15
|
+
|
|
16
|
+
You are ready to build your next awesome project in Nuxt.
|
|
17
|
+
|
|
18
|
+
### As a layer
|
|
19
|
+
Aside from being "forked", `nuxt-ignis` is also available as a NPM package that can be referenced as a single-import dependency with all the features incomming.
|
|
20
|
+
|
|
21
|
+
More info comming soon...
|
|
22
|
+
|
|
23
|
+
## Overview
|
|
24
|
+
|
|
25
|
+
**Fundamentals**
|
|
26
|
+
- [`pnpm`](https://pnpm.io/) based project
|
|
27
|
+
- [Nuxt](https://nuxt.com/) application framework built atop [Vue.js](https://vuejs.org/)
|
|
28
|
+
- Available as a template or standalone package
|
|
29
|
+
|
|
30
|
+
**Built-in features**
|
|
31
|
+
- linting for maintaining coding standards and improving code quality via [`@nuxt/eslint`](https://nuxt.com/modules/eslint)
|
|
32
|
+
- zero-config OWASP security patterns for Nuxt via [`nuxt-security`](https://nuxt-security.vercel.app/)
|
|
33
|
+
- de-facto standard state management library for Vue apps via [`@pinia/nuxt`](https://pinia.vuejs.org/ssr/nuxt.html)
|
|
34
|
+
- integration with utility functions library for Vue apps via [`@vueuse/nuxt`](https://vueuse.org/nuxt/README.html)
|
|
35
|
+
- handful tools for working with images via [`@nuxt/image`](https://image.nuxt.com/)
|
|
36
|
+
- SSR-friendly component for rendering dynamic date/time via [`nuxt-time`](https://nuxt.com/modules/time)
|
|
37
|
+
|
|
38
|
+
**Configurable features**
|
|
39
|
+
- UI (pick 0-1)
|
|
40
|
+
- **Nuxt UI** - UI component and CSS library via [`@nuxt/ui`](https://ui.nuxt.com/)
|
|
41
|
+
- **Tailwind CSS** - CSS library (included in Nuxt UI) via [`@nuxtjs/tailwindcss`](https://tailwindcss.nuxtjs.org/)
|
|
42
|
+
- Database (pick 0-1)
|
|
43
|
+
- **Neon** - serverless PostgreSQL database via [`nuxt-neon`](https://github.com/AloisSeckar/nuxt-neon/)
|
|
44
|
+
- **Supabase** - serverless PostgreSQL database via [`@nuxtjs/supabase`](https://supabase.nuxtjs.org/)
|
|
45
|
+
- Other (opt-in)
|
|
46
|
+
- **I18N** - translations and internalization made easy via [`@nuxtjs/i18n`](hhttps://i18n.nuxtjs.org/)
|
|
47
|
+
- **FormKit** - for handling input forms via [`@formkit/nuxt`](https://nuxt.com/modules/formkit)
|
|
48
|
+
- **Content** - for working with website content in `.md` or `.json` via [`@nuxt/content`](https://content.nuxt.com/)
|
|
49
|
+
- **Open Props** - extra CSS styles via [Open Props](https://open-props.style/)
|
|
50
|
+
|
|
51
|
+
## Configuration
|
|
52
|
+
It is possible to select which Nuxt modules will be activated in your project. All dependencies are being downloaded into local `node_modules`, but Nuxt build process will ensure only relevant packages will be bundled for production.
|
|
53
|
+
|
|
54
|
+
### UI preset
|
|
55
|
+
It is possible to pick from three options:
|
|
56
|
+
- `nuxt-ui` - full https://ui.nuxt.com/ via `@nuxt/ui` connector module **[RECOMMENDED]**
|
|
57
|
+
- `tailwind` - only https://tailwindcss.com/ via `@nuxtjs/tailwindcss` connector module
|
|
58
|
+
- `off` - no UI library preset **[DEFAULT]**
|
|
59
|
+
|
|
60
|
+
Set the value via `NUXT_PUBLIC_IGNIS_PRESET_UI` env variable.
|
|
61
|
+
|
|
62
|
+
Value other than `off` will override Optional modules setting.
|
|
63
|
+
|
|
64
|
+
### Database preset
|
|
65
|
+
It is possible to pick from three options:
|
|
66
|
+
- `neon` - https://neon.tech/ via `nuxt-neon` connector module **[RECOMMENDED]**
|
|
67
|
+
- `supabase` - https://supabase.com/ via `@nuxtjs/supabase` connector module
|
|
68
|
+
- `off` - no database module preset **[DEFAULT]**
|
|
69
|
+
|
|
70
|
+
Set the value via `NUXT_PUBLIC_IGNIS_DB_PRESET` env variable.
|
|
71
|
+
|
|
72
|
+
Value other than `off` will override Optional modules setting.
|
|
73
|
+
|
|
74
|
+
### Optional modules
|
|
75
|
+
Currently, following modules are opinionated:
|
|
76
|
+
- `@nuxt/ui` - set `NUXT_PUBLIC_IGNIS_UI` to `true | false`
|
|
77
|
+
- `@nuxtjs/tailwindcss` - set `NUXT_PUBLIC_IGNIS_TAILWIND` to `true | false` (ignored if `NUXT_PUBLIC_IGNIS_UI=true`)
|
|
78
|
+
- `nuxt-neon` - set `NUXT_PUBLIC_IGNIS_NEON` to `true | false`
|
|
79
|
+
- `@nuxtjs/supabase` - set `NUXT_PUBLIC_IGNIS_SUPABASE` to `true | false`
|
|
80
|
+
- `@nuxtjs/i18n` - set `NUXT_PUBLIC_IGNIS_I18N` to `true | false`
|
|
81
|
+
- `@formkit/nuxt` - set `NUXT_PUBLIC_IGNIS_FORMKIT` to `true | false`
|
|
82
|
+
- `@nuxt/content` - set `NUXT_PUBLIC_IGNIS_CONTENT` to `true | false`
|
|
83
|
+
|
|
84
|
+
Default values are **false** (not included) for all optional modules.
|
|
85
|
+
|
|
86
|
+
### Optional features
|
|
87
|
+
Currently, following extra features (not using separate Nuxt Modules) are opinionated:
|
|
88
|
+
- `Open Props CSS` - set `NUXT_PUBLIC_IGNIS_OPENPROPS` to `true | false`
|
|
89
|
+
|
|
90
|
+
Default values are **false** (not included) for all optional features.
|
package/app.config.ts
ADDED
package/app.vue
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="p-3">
|
|
3
|
+
<div class="ignis-header">
|
|
4
|
+
<img src="/nuxt-ignis.png" class="ignis-logo" :title :alt>
|
|
5
|
+
<h1 class="my-4 text-4xl text-amber-400 font-bold">
|
|
6
|
+
{{ useT("title") }}
|
|
7
|
+
</h1>
|
|
8
|
+
<img src="/nuxt-ignis.png" class="ignis-logo" :title :alt>
|
|
9
|
+
</div>
|
|
10
|
+
<div>{{ useT("subtitle") }}</div>
|
|
11
|
+
<NuxtPage />
|
|
12
|
+
<CurrentTime />
|
|
13
|
+
<div class="link text-xs">
|
|
14
|
+
<NuxtLink to="https://github.com/AloisSeckar/nuxt-ignis">
|
|
15
|
+
https://github.com/AloisSeckar/nuxt-ignis
|
|
16
|
+
</NuxtLink>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
19
|
+
</template>
|
|
20
|
+
|
|
21
|
+
<script setup lang="ts">
|
|
22
|
+
useHead({
|
|
23
|
+
title: useAppConfig().textTitle,
|
|
24
|
+
htmlAttrs: {
|
|
25
|
+
lang: 'en',
|
|
26
|
+
},
|
|
27
|
+
bodyAttrs: {
|
|
28
|
+
class: 'bg-slate-900 m-auto text-center text-white'
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
initConsola()
|
|
32
|
+
log.info('Nuxt Ignis was here!')
|
|
33
|
+
const title = useT('title')
|
|
34
|
+
const alt = title
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<style scoped>
|
|
38
|
+
.ignis-header {
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: row;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
margin-bottom: 10px;
|
|
43
|
+
}
|
|
44
|
+
.ignis-logo {
|
|
45
|
+
display: inline;
|
|
46
|
+
width: 64px;
|
|
47
|
+
height: 64px;
|
|
48
|
+
}
|
|
49
|
+
.ignis-title {
|
|
50
|
+
margin-top: 15px;
|
|
51
|
+
}
|
|
52
|
+
</style>
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This will import Open Props CSS styles
|
|
3
|
+
https://open-props.style/
|
|
4
|
+
|
|
5
|
+
NUXT_PUBLIC_IGNIS_OPENPROPS=true is required to use this feature
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
@import "open-props/normalize";
|
|
9
|
+
@import "open-props/buttons";
|
|
10
|
+
|
|
11
|
+
/* demo class - used in AppFeature component instance */
|
|
12
|
+
.openprops-feature {
|
|
13
|
+
|
|
14
|
+
/* https://open-props.style/#gradients */
|
|
15
|
+
background: var(--gradient-18);
|
|
16
|
+
|
|
17
|
+
/* https://open-props.style/#colors */
|
|
18
|
+
color: var(--gray-12);
|
|
19
|
+
|
|
20
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This file is auto-imported when using Tailwind CSS
|
|
3
|
+
|
|
4
|
+
Use @apply if you don't want to define style for each element separately
|
|
5
|
+
|
|
6
|
+
Read more at:
|
|
7
|
+
https://tailwindcss.com/docs/reusing-styles#extracting-classes-with-apply
|
|
8
|
+
https://tailwindcss.com/docs/functions-and-directives#apply
|
|
9
|
+
|
|
10
|
+
Use correct @layer to keep your Tailwind CSS organized:
|
|
11
|
+
https://bloggie.io/@kinopyo/organize-your-css-in-the-tailwind-style-with-layer-directive
|
|
12
|
+
|
|
13
|
+
And most importantly: THINK TWICE before using this approach!
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
@tailwind base;
|
|
17
|
+
@tailwind components;
|
|
18
|
+
@tailwind utilities;
|
|
19
|
+
|
|
20
|
+
@layer base {
|
|
21
|
+
|
|
22
|
+
/*
|
|
23
|
+
Tailwind CSS classes might be auto-applied to all respective elements like this.
|
|
24
|
+
However, I recommend NOT to use it like that, because this obsfucates code logic
|
|
25
|
+
and makes maintaing harder (even you should soon forgot styles are defined here)
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/* NOTE: For setting "body" tag attributes, it is better to use useHead() composable - @see `app.vue`*/
|
|
29
|
+
/*
|
|
30
|
+
body {
|
|
31
|
+
@apply bg-slate-900;
|
|
32
|
+
}
|
|
33
|
+
*/
|
|
34
|
+
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@layer components {
|
|
38
|
+
|
|
39
|
+
/*
|
|
40
|
+
Following classes are available to use throughout the app as shorthands.
|
|
41
|
+
Although still discouraged by Tailwind CSS authors, this usage makes more
|
|
42
|
+
sense, because the class name is visible and trackable in SFC templates.
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
.link {
|
|
46
|
+
@apply my-2 text-amber-400 hover:text-amber-200;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title" : "Nuxt Ignis",
|
|
3
|
+
"subtitle" : "A ready-to-use setup for your next application in Nuxt",
|
|
4
|
+
"page2" : "This is a second page of the application",
|
|
5
|
+
"image" : "Image by Unsplash displayed with Nuxt Image",
|
|
6
|
+
"goto1" : "Go back to index",
|
|
7
|
+
"goto2" : "Go to 2nd page",
|
|
8
|
+
"features" : {
|
|
9
|
+
"nuxt" : "Nuxt application framework atop Vue.js",
|
|
10
|
+
"security" : "Nuxt Security module helping with OWASP patterns",
|
|
11
|
+
"image" : "NuxtImage to optimize use of images",
|
|
12
|
+
"pinia" : "Pinia for state management",
|
|
13
|
+
"vueuse" : "VueUse utils available",
|
|
14
|
+
"i18n" : "I18n for translations",
|
|
15
|
+
"consola" : "Logging with unjs/consola",
|
|
16
|
+
"ui" : "Nuxt UI as UI components library",
|
|
17
|
+
"tailwind" : "Tailwind CSS for styling",
|
|
18
|
+
"icon" : "Icon module for displaying icons",
|
|
19
|
+
"supabase" : "Supabase for auth and DB services",
|
|
20
|
+
"neon" : "Neon for DB services",
|
|
21
|
+
"formkit" : "FormKit for input forms",
|
|
22
|
+
"content" : "Nuxt Content for creating and editing content",
|
|
23
|
+
"openprops" : "Additional CSS by Open Props"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
https://nuxt.com/docs/guide/directory-structure/components
|
|
3
|
+
|
|
4
|
+
Example of a reusable Nuxt component.
|
|
5
|
+
|
|
6
|
+
Any valid .vue file inside `/components` directory is auto-imported everywhere by Nuxt
|
|
7
|
+
=> no need for explicit imports.
|
|
8
|
+
|
|
9
|
+
Modern Vue.js Composition API syntax is used for setup.
|
|
10
|
+
https://vuejs.org/api/sfc-script-setup.html
|
|
11
|
+
|
|
12
|
+
For usage go to `/pages/index.vue`
|
|
13
|
+
|
|
14
|
+
{{ text }}
|
|
15
|
+
- "double mustache" syntax is used to display JS expression inside HTML template
|
|
16
|
+
- notice you can call props directly in template section
|
|
17
|
+
|
|
18
|
+
Icon
|
|
19
|
+
- icons are provided by "nuxt-icon" module
|
|
20
|
+
- module is auto-imported via "@nuxt/ui"
|
|
21
|
+
- NUXT_PUBLIC_IGNIS_UI=nuxt-ui is required to use this feature
|
|
22
|
+
-->
|
|
23
|
+
|
|
24
|
+
<template>
|
|
25
|
+
<div class="m-1 px-2 py-1 border border-amber-300 font-bold text-lg text-feature hover:bg-slate-700">
|
|
26
|
+
{{ text }}
|
|
27
|
+
<div v-if="showIcon" style="display: inline;">
|
|
28
|
+
<Icon name="ic:sharp-add-reaction" style="color: yellow" />
|
|
29
|
+
</div>
|
|
30
|
+
</div>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<script setup lang="ts">
|
|
34
|
+
/**
|
|
35
|
+
* Macro `defineProps()` comes from Vue.js API
|
|
36
|
+
* (https://vuejs.org/api/sfc-script-setup.html#defineprops-defineemits).
|
|
37
|
+
* This is how to pass variables inside components in Vue.
|
|
38
|
+
*
|
|
39
|
+
* `required` - value has to be provided, otherwise an error will occur
|
|
40
|
+
*
|
|
41
|
+
* `default` - will have this value, unless overwritten by caller
|
|
42
|
+
*/
|
|
43
|
+
const props = defineProps({
|
|
44
|
+
text: { type: String, required: true },
|
|
45
|
+
optionalText: { type: String, default: 'default' },
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* `Icon` component can only be used if `@nuxt/ui` module is activated.
|
|
50
|
+
*/
|
|
51
|
+
const showIcon = useRuntimeConfig().public.ignis.ui === 'nuxt-ui'
|
|
52
|
+
|
|
53
|
+
// In setup section, you have to adress properties like this.
|
|
54
|
+
// You cannot reach them directly like in template.
|
|
55
|
+
|
|
56
|
+
// Note special inline `eslint` flag because normally you shouldn't use build-in console directly
|
|
57
|
+
// @see https://eslint.org/docs/latest/rules/no-console
|
|
58
|
+
|
|
59
|
+
/* eslint "no-console" : "off" */
|
|
60
|
+
log.debug(props.text)
|
|
61
|
+
log.debug(props.optionalText)
|
|
62
|
+
</script>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
The `NuxtTime` component of `nuxt-time` module is a way how to deal with SSR in Nuxt.
|
|
3
|
+
Because page on the server is rendered miliseconds before being re-rendered on client,
|
|
4
|
+
wild "hydration error mismatch" may appear from a difference between displayed times.
|
|
5
|
+
|
|
6
|
+
This special component gracefully deals with the issue:
|
|
7
|
+
https://github.com/nuxt/nuxt/discussions/23278#discussioncomment-7607298
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div>
|
|
12
|
+
Current time by
|
|
13
|
+
<span class="link">
|
|
14
|
+
<NuxtLink to="https://github.com/danielroe/nuxt-time">Nuxt Time</NuxtLink>
|
|
15
|
+
</span>:
|
|
16
|
+
<NuxtTime
|
|
17
|
+
:datetime="currentDate"
|
|
18
|
+
year="numeric"
|
|
19
|
+
month="2-digit"
|
|
20
|
+
day="2-digit"
|
|
21
|
+
hour="2-digit"
|
|
22
|
+
minute="2-digit"
|
|
23
|
+
second="2-digit"
|
|
24
|
+
/>
|
|
25
|
+
</div>
|
|
26
|
+
</template>
|
|
27
|
+
|
|
28
|
+
<script setup lang="ts">
|
|
29
|
+
const currentDate = useNow()
|
|
30
|
+
</script>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import lang from '@/assets/lang/en.json'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* An adapter above `t` function from `i18n` module.
|
|
5
|
+
*
|
|
6
|
+
* This function is basically a shorthand for obtaining `i18n` translation in scripts.
|
|
7
|
+
* In templates `$t` function is available, but in scripts we normally have to
|
|
8
|
+
* access the `t` function via the instance of `$i18n` living inside current Nuxt App.
|
|
9
|
+
*
|
|
10
|
+
* Since $i18n is an optional dependency in Nuxt Ignis setup, this also gracefully handles
|
|
11
|
+
* cases when user turns the module off while still using the translations in the code.
|
|
12
|
+
*
|
|
13
|
+
* @param key identifier of text that should be displayed
|
|
14
|
+
* @returns translated text from i18n sources
|
|
15
|
+
*/
|
|
16
|
+
export function useT(key: string): string {
|
|
17
|
+
if (useRuntimeConfig().public.ignis.i18n) {
|
|
18
|
+
// i18n available => just use it
|
|
19
|
+
// @ts-ignore (in case i18n is turned off, type of $i18n cannot be infered)
|
|
20
|
+
return useNuxtApp().$i18n.t(key)
|
|
21
|
+
} else {
|
|
22
|
+
// backdoor for Nuxt Ignis to display values on demo index page
|
|
23
|
+
const backdoorValue = searchLang(key)
|
|
24
|
+
if (backdoorValue) {
|
|
25
|
+
return backdoorValue as string
|
|
26
|
+
}
|
|
27
|
+
// for other custom values a warning will be produced and a placeholder will be returned
|
|
28
|
+
log.warn('@nuxtjs/i18n turned off, translations are not available (set NUXT_PUBLIC_IGNIS_I18N=true)')
|
|
29
|
+
return "Translation not available"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** AI-generated helper to search a value for given key in JSON lang file. */
|
|
34
|
+
function searchLang(key: string): unknown {
|
|
35
|
+
const keys = key.split(".")
|
|
36
|
+
|
|
37
|
+
let current = lang
|
|
38
|
+
for (const key of keys) {
|
|
39
|
+
if (current && key in current) {
|
|
40
|
+
// @ts-expect-error TODO this should be fixed
|
|
41
|
+
current = current[key]
|
|
42
|
+
} else {
|
|
43
|
+
return undefined
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return current
|
|
48
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import withNuxt from './.nuxt/eslint.config.mjs'
|
|
2
|
+
|
|
3
|
+
// config is being passed as an array of separate objects
|
|
4
|
+
// as suggested here: https://github.com/nuxt/eslint/discussions/413
|
|
5
|
+
|
|
6
|
+
export default withNuxt([
|
|
7
|
+
|
|
8
|
+
// files to be processed (JS/TS + Vue components)
|
|
9
|
+
{ files: ['**/*.js', '**/*.ts', '**/*.vue'] },
|
|
10
|
+
|
|
11
|
+
// `rules` section can follow, where you can change default eslint behaviour if needed
|
|
12
|
+
// you can adjust or even turn off some rules if you cannot or don't want to satisfy them
|
|
13
|
+
{
|
|
14
|
+
rules: {
|
|
15
|
+
// the default for this rule is "1", but I find it too restrictive
|
|
16
|
+
// https://eslint.vuejs.org/rules/max-attributes-per-line.html
|
|
17
|
+
'vue/max-attributes-per-line': ['error', {
|
|
18
|
+
singleline: {
|
|
19
|
+
max: 4,
|
|
20
|
+
},
|
|
21
|
+
multiline: {
|
|
22
|
+
max: 3,
|
|
23
|
+
},
|
|
24
|
+
}],
|
|
25
|
+
// the default rule forces newline after "else"
|
|
26
|
+
// I prefer using "} else {" on single row
|
|
27
|
+
'vue/html-closing-bracket-newline': [
|
|
28
|
+
'error',
|
|
29
|
+
{
|
|
30
|
+
multiline: 'never',
|
|
31
|
+
selfClosingTag: {
|
|
32
|
+
multiline: 'never',
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
'@stylistic/brace-style': 'off',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
])
|
package/features.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { defu } from 'defu'
|
|
2
|
+
import OpenProps from 'open-props'
|
|
3
|
+
import { log } from './utils/consola'
|
|
4
|
+
|
|
5
|
+
export function setFeatures() {
|
|
6
|
+
// list of optional extra features
|
|
7
|
+
const extras = [] as string[]
|
|
8
|
+
|
|
9
|
+
// object for optional config that will be merged with global Nuxt config
|
|
10
|
+
// declared in nuxt.config.ts
|
|
11
|
+
let nuxtConfig = {
|
|
12
|
+
modules: [] as string[],
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// 1. default modules (mandatory)
|
|
16
|
+
nuxtConfig.modules.push(
|
|
17
|
+
'nuxt-time',
|
|
18
|
+
'nuxt-security',
|
|
19
|
+
'@nuxt/eslint',
|
|
20
|
+
'@nuxt/image',
|
|
21
|
+
'@pinia/nuxt',
|
|
22
|
+
'@vueuse/nuxt',
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
// 2. optional modules
|
|
26
|
+
|
|
27
|
+
// ui
|
|
28
|
+
const uiPreset = process.env.NUXT_PUBLIC_IGNIS_PRESET_UI
|
|
29
|
+
if (uiPreset === 'nuxt-ui' || (!uiPreset && process.env.NUXT_PUBLIC_IGNIS_UI === 'true')) {
|
|
30
|
+
nuxtConfig.modules.push('@nuxt/ui')
|
|
31
|
+
} else {
|
|
32
|
+
// remove @nuxt/ui-specific components from resolution if module is not used
|
|
33
|
+
nuxtConfig = defu({
|
|
34
|
+
vue: {
|
|
35
|
+
compilerOptions: {
|
|
36
|
+
isCustomElement: (tag: string) => tag === 'Icon',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
}, nuxtConfig)
|
|
40
|
+
|
|
41
|
+
// evaluate separate Tailwind CSS module
|
|
42
|
+
if (uiPreset === 'tailwind' || (!uiPreset && process.env.NUXT_PUBLIC_IGNIS_TAILWIND === 'true')) {
|
|
43
|
+
nuxtConfig.modules.push('@nuxtjs/tailwindcss')
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// database
|
|
48
|
+
const dbPreset = process.env.NUXT_PUBLIC_IGNIS_PRESET_DB
|
|
49
|
+
if (dbPreset === 'neon' || (!dbPreset && process.env.NUXT_PUBLIC_IGNIS_NEON === 'true')) {
|
|
50
|
+
// module definition
|
|
51
|
+
nuxtConfig.modules.push('nuxt-neon')
|
|
52
|
+
} else if (dbPreset === 'supabase' || (!dbPreset && process.env.NUXT_PUBLIC_IGNIS_SUPABASE === 'true')) {
|
|
53
|
+
// module definition
|
|
54
|
+
nuxtConfig.modules.push('@nuxtjs/supabase')
|
|
55
|
+
// module-specific config key
|
|
56
|
+
nuxtConfig = defu({
|
|
57
|
+
supabase: {
|
|
58
|
+
redirect: false, // https://github.com/supabase/supabase/issues/16551#issuecomment-1685300935
|
|
59
|
+
},
|
|
60
|
+
}, nuxtConfig)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// i18n
|
|
64
|
+
if (process.env.NUXT_PUBLIC_IGNIS_I18N === 'true') {
|
|
65
|
+
// module definition
|
|
66
|
+
nuxtConfig.modules.push('@nuxtjs/i18n')
|
|
67
|
+
// module-specific config key
|
|
68
|
+
nuxtConfig = defu({
|
|
69
|
+
i18n: {
|
|
70
|
+
vueI18n: './i18n.config.ts',
|
|
71
|
+
locales: ['en'],
|
|
72
|
+
defaultLocale: 'en',
|
|
73
|
+
},
|
|
74
|
+
}, nuxtConfig)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// formkit
|
|
78
|
+
if (process.env.NUXT_PUBLIC_IGNIS_FORMKIT === 'true') {
|
|
79
|
+
nuxtConfig.modules.push('@formkit/nuxt')
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// content
|
|
83
|
+
if (process.env.NUXT_PUBLIC_IGNIS_CONTENT === 'true') {
|
|
84
|
+
nuxtConfig.modules.push('@nuxt/content')
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Open Props CSS
|
|
88
|
+
if (process.env.NUXT_PUBLIC_IGNIS_OPENPROPS === 'true') {
|
|
89
|
+
extras.push('Open Props CSS')
|
|
90
|
+
nuxtConfig = defu({
|
|
91
|
+
// import Open Prpops stylesheet
|
|
92
|
+
css: ['~/assets/css/open-props.css'],
|
|
93
|
+
// CSS processor for Open Props
|
|
94
|
+
postcss: {
|
|
95
|
+
plugins: {
|
|
96
|
+
'postcss-jit-props': OpenProps,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
}, nuxtConfig)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let overview = 'Nuxt Ignis will start using following settings:\n'
|
|
103
|
+
overview += 'Modules: ' + nuxtConfig.modules.join(', ') + '\n'
|
|
104
|
+
if (extras.length > 0) {
|
|
105
|
+
overview += 'Extras: ' + extras.join(', ') + '\n'
|
|
106
|
+
}
|
|
107
|
+
log.info(overview)
|
|
108
|
+
|
|
109
|
+
return nuxtConfig
|
|
110
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// https://formkit.com/guides/optimizing-for-production#using-the-nuxt-module
|
|
2
|
+
import { en, de } from '@formkit/i18n'
|
|
3
|
+
import type { DefaultConfigOptions } from '@formkit/vue'
|
|
4
|
+
|
|
5
|
+
const config: DefaultConfigOptions = {
|
|
6
|
+
// example of importing different message translations and set the default one
|
|
7
|
+
locales: { en, de },
|
|
8
|
+
locale: 'en',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default config
|
package/i18n.config.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import en from '@/assets/lang/en.json'
|
|
2
|
+
// create and load more language files if needed
|
|
3
|
+
|
|
4
|
+
export default defineI18nConfig(() => ({
|
|
5
|
+
legacy: false,
|
|
6
|
+
strategy: 'no_prefix',
|
|
7
|
+
locale: 'en',
|
|
8
|
+
defaultLocale: 'en',
|
|
9
|
+
fallbackLocale: 'en',
|
|
10
|
+
messages: { en }, // allowe more language if needed
|
|
11
|
+
warnHtmlMessage: false,
|
|
12
|
+
}))
|
package/nuxt.config.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { defu } from 'defu'
|
|
2
|
+
import { setFeatures } from './features'
|
|
3
|
+
|
|
4
|
+
const ignisFeatures = setFeatures()
|
|
5
|
+
|
|
6
|
+
// https://nuxt.com/docs/guide/directory-structure/nuxt-config
|
|
7
|
+
const nuxtConfig = defu(ignisFeatures, {
|
|
8
|
+
|
|
9
|
+
// https://nuxt.com/docs/api/nuxt-config#compatibilitydate
|
|
10
|
+
compatibilityDate: '2024-12-01',
|
|
11
|
+
|
|
12
|
+
// simple eslint config - see eslint.config.mjs
|
|
13
|
+
eslint: {
|
|
14
|
+
config: {
|
|
15
|
+
stylistic: true,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
// app configuration
|
|
20
|
+
runtimeConfig: {
|
|
21
|
+
// nitro-only secret env-like variables go here
|
|
22
|
+
public: {
|
|
23
|
+
// client-exposed env-like variables go here
|
|
24
|
+
|
|
25
|
+
// features
|
|
26
|
+
// NOTE: due to static-like nature of nuxt.config.ts file
|
|
27
|
+
// actual values MUST BE provided via .env file (or production equivalent)
|
|
28
|
+
ignis: {
|
|
29
|
+
preset: {
|
|
30
|
+
ui: 'off', // nuxt-ui/tailwind/off
|
|
31
|
+
db: 'off', // neon/supabase/off
|
|
32
|
+
},
|
|
33
|
+
// individual modules
|
|
34
|
+
ui: false, // true/false
|
|
35
|
+
tailwind: false, // true/false (ignored, if ui=true)
|
|
36
|
+
neon: false, // true/false
|
|
37
|
+
supabase: false, // true/false
|
|
38
|
+
i18n: false, // true/false
|
|
39
|
+
formkit: false, // true/false
|
|
40
|
+
content: false, // true/false
|
|
41
|
+
openprops: false, // true/false
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
// logging
|
|
45
|
+
logLevel: 'info',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
// https://nuxt.com/docs/getting-started/configuration#nuxt-configuration
|
|
51
|
+
// @ts-expect-error unknown object type
|
|
52
|
+
// TODO elaborate correct type for "nuxtConfig" object
|
|
53
|
+
export default defineNuxtConfig(nuxtConfig)
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nuxt-ignis",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Enhanced and customizable Nuxt application starter pack",
|
|
5
|
+
"repository": "github:AloisSeckar/nuxt-ignis",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"analyze": "nuxt analyze",
|
|
10
|
+
"eslint": "eslint .",
|
|
11
|
+
"build": "nuxt build",
|
|
12
|
+
"dev": "nuxt dev",
|
|
13
|
+
"generate": "nuxt generate",
|
|
14
|
+
"preview": "nuxt preview",
|
|
15
|
+
"start": "nuxt start"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@formkit/nuxt": "1.6.9",
|
|
19
|
+
"@nuxt/content": "2.13.4",
|
|
20
|
+
"@nuxt/eslint": "0.7.2",
|
|
21
|
+
"@nuxt/image": "1.8.1",
|
|
22
|
+
"@nuxt/ui": "2.19.2",
|
|
23
|
+
"@nuxtjs/i18n": "9.1.0",
|
|
24
|
+
"@nuxtjs/supabase": "1.4.3",
|
|
25
|
+
"@nuxtjs/tailwindcss": "6.12.2",
|
|
26
|
+
"@pinia/nuxt": "0.8.0",
|
|
27
|
+
"@vueuse/core": "12.0.0",
|
|
28
|
+
"@vueuse/nuxt": "12.0.0",
|
|
29
|
+
"consola": "3.2.3",
|
|
30
|
+
"defu": "6.1.4",
|
|
31
|
+
"nuxt": "3.14.1592",
|
|
32
|
+
"nuxt-neon": "0.1.2",
|
|
33
|
+
"nuxt-security": "2.1.5",
|
|
34
|
+
"nuxt-time": "1.0.3",
|
|
35
|
+
"open-props": "1.7.7",
|
|
36
|
+
"pinia": "2.2.8",
|
|
37
|
+
"postcss-jit-props": "1.0.14",
|
|
38
|
+
"typescript": "5.7.2",
|
|
39
|
+
"vue": "latest",
|
|
40
|
+
"vue-router": "latest"
|
|
41
|
+
},
|
|
42
|
+
"packageManager": "pnpm@9.14.4"
|
|
43
|
+
}
|
package/pages/index.vue
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
https://nuxt.com/docs/guide/directory-structure/pages
|
|
3
|
+
|
|
4
|
+
An example of Nuxt page.
|
|
5
|
+
Nuxt automaticaly provides routing and displays this page when user visits root URL or `/index`.
|
|
6
|
+
|
|
7
|
+
AppFeature
|
|
8
|
+
- an example usage of auto-imported Nuxt component declared in `/components` directory
|
|
9
|
+
- the text is (usually) being loaded localized via nuxtjs/i18n module
|
|
10
|
+
- features are being displayed conditionally according to current setting
|
|
11
|
+
|
|
12
|
+
NuxtLink
|
|
13
|
+
- special component for improved handling for HTML links (<a> tags)
|
|
14
|
+
-->
|
|
15
|
+
|
|
16
|
+
<template>
|
|
17
|
+
<div>
|
|
18
|
+
<div class="m-auto my-4 w-3/5 flex flex-col">
|
|
19
|
+
<AppFeature :text="useT('features.nuxt')" />
|
|
20
|
+
<AppFeature :text="useT('features.security')" />
|
|
21
|
+
<AppFeature :text="useT('features.image')" />
|
|
22
|
+
<AppFeature :text="useT('features.pinia')" />
|
|
23
|
+
<AppFeature :text="useT('features.vueuse')" />
|
|
24
|
+
<AppFeature :text="useT('features.consola')" />
|
|
25
|
+
<AppFeature v-if="ui === 'nuxt-ui'" :text="useT('features.ui')" />
|
|
26
|
+
<AppFeature v-if="ui !== 'off'" :text="useT('features.tailwind')" />
|
|
27
|
+
<AppFeature v-if="ui === 'nuxt-ui'" :text="useT('features.icon')" />
|
|
28
|
+
<AppFeature v-if="db === 'supabase'" :text="useT('features.supabase')" />
|
|
29
|
+
<AppFeature v-if="db === 'neon'" :text="useT('features.neon')" />
|
|
30
|
+
<AppFeature v-if="i18n" :text="useT('features.i18n')" />
|
|
31
|
+
<AppFeature v-if="formkit" :text="useT('features.formkit')" />
|
|
32
|
+
<AppFeature v-if="content" :text="useT('features.content')" />
|
|
33
|
+
<AppFeature v-if="openprops" class="openprops-feature" :text="useT('features.openprops')" />
|
|
34
|
+
</div>
|
|
35
|
+
<div class="link">
|
|
36
|
+
<NuxtLink to="/second">
|
|
37
|
+
{{ useT("goto2") }}
|
|
38
|
+
</NuxtLink>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</template>
|
|
42
|
+
|
|
43
|
+
<script setup lang="ts">
|
|
44
|
+
const setup = useRuntimeConfig().public.ignis
|
|
45
|
+
const ui = setup.ui
|
|
46
|
+
const db = setup.db
|
|
47
|
+
const i18n = setup.i18n
|
|
48
|
+
const formkit = setup.formkit
|
|
49
|
+
const content = setup.content
|
|
50
|
+
const openprops = setup.openprops
|
|
51
|
+
</script>
|
package/pages/second.vue
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
https://nuxt.com/docs/guide/directory-structure/pages
|
|
3
|
+
|
|
4
|
+
This page appears under URL `/second`
|
|
5
|
+
|
|
6
|
+
NuxtImg
|
|
7
|
+
- special component for displaying images with NuxtImage module
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div>
|
|
12
|
+
<div class="m-4">
|
|
13
|
+
{{ useT("page2") }}
|
|
14
|
+
</div>
|
|
15
|
+
<div class="m-4 flex flex-col items-center">
|
|
16
|
+
<NuxtImg src="/unsplash.jpg" width="400" />
|
|
17
|
+
<div class="text-xs">
|
|
18
|
+
{{ useT("image") }}
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
<div class="link">
|
|
22
|
+
<NuxtLink to="/">
|
|
23
|
+
{{ useT("goto1") }}
|
|
24
|
+
</NuxtLink>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
</template>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// https://tailwindcss.com/docs/configuration
|
|
2
|
+
// https://tailwindcss.com/docs/plugins
|
|
3
|
+
|
|
4
|
+
import plugin from 'tailwindcss/plugin'
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
content: [
|
|
8
|
+
'./src/**/*.{html,js,vue}',
|
|
9
|
+
],
|
|
10
|
+
theme: {
|
|
11
|
+
// example of extending Tailwind CSS with custom color
|
|
12
|
+
extend: {
|
|
13
|
+
colors: {
|
|
14
|
+
feature: '#3CB371',
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
plugins: [
|
|
19
|
+
// example how to enable custom color class inside @apply directive
|
|
20
|
+
plugin(function ({ addComponents, theme }) {
|
|
21
|
+
addComponents({
|
|
22
|
+
'.text-feature': {
|
|
23
|
+
color: theme('colors.feature'),
|
|
24
|
+
},
|
|
25
|
+
})
|
|
26
|
+
}),
|
|
27
|
+
],
|
|
28
|
+
}
|
package/tsconfig.json
ADDED
package/utils/consola.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// centralized logging system
|
|
2
|
+
// https://github.com/unjs/consola
|
|
3
|
+
|
|
4
|
+
import type { LogLevel, LogObject } from 'consola/core'
|
|
5
|
+
import { LogLevels, createConsola } from 'consola/core'
|
|
6
|
+
import { consola } from 'consola'
|
|
7
|
+
import { useDateFormat } from '@vueuse/core'
|
|
8
|
+
|
|
9
|
+
// default instance to write into browser's console
|
|
10
|
+
const defaultReporter = consola
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Logging object that is available across the app thanks to Nuxt auto-imports.
|
|
14
|
+
*/
|
|
15
|
+
export const log = createConsola({
|
|
16
|
+
level: LogLevels.debug,
|
|
17
|
+
reporters: [
|
|
18
|
+
{
|
|
19
|
+
log: (logObj) => {
|
|
20
|
+
// enhancing log with more info (i.e. time + relevant stack for warn/error)
|
|
21
|
+
const msg = transformLog(logObj)
|
|
22
|
+
// logs are being written into browser's console
|
|
23
|
+
// `logObj.type` = log level name = corresponing method on the logger (debug, info, warn, error, etc.)
|
|
24
|
+
defaultReporter[logObj.type](msg)
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Initialize logger functions.
|
|
32
|
+
* Called in app.vue's setup.
|
|
33
|
+
*/
|
|
34
|
+
export async function initConsola() {
|
|
35
|
+
// set default log level from config
|
|
36
|
+
const logLevel = useRuntimeConfig().public.logLevel
|
|
37
|
+
log.level = getLogLevel(logLevel)
|
|
38
|
+
defaultReporter.level = log.level
|
|
39
|
+
log.debug(`[consola] log level set to '${logLevel}'`)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Transform text values of logLevel
|
|
44
|
+
* to numeric equivalent used by consola.
|
|
45
|
+
*/
|
|
46
|
+
function getLogLevel(logLevel: string): LogLevel {
|
|
47
|
+
const logLevelString = logLevel.toLocaleLowerCase()
|
|
48
|
+
switch (logLevelString) {
|
|
49
|
+
case 'fatal': return LogLevels.fatal
|
|
50
|
+
case 'error': return LogLevels.error
|
|
51
|
+
case 'warn': return LogLevels.warn
|
|
52
|
+
case 'log': return LogLevels.log
|
|
53
|
+
case 'info': return LogLevels.info
|
|
54
|
+
case 'success': return LogLevels.success
|
|
55
|
+
case 'debug': return LogLevels.debug
|
|
56
|
+
case 'trace': return LogLevels.trace
|
|
57
|
+
case 'silent': return LogLevels.silent
|
|
58
|
+
case 'verbose': return LogLevels.verbose
|
|
59
|
+
default: log.fatal(`Invalid log level ${logLevel}`)
|
|
60
|
+
throw new Error(`Invalid log level ${logLevel}`)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Enhance received log object, which should be logged.
|
|
66
|
+
* Add current date+time and trim irrelevant call-stack for warn/errors.
|
|
67
|
+
* @param logObj Object to be logged
|
|
68
|
+
* @returns Enhanced object to be logged
|
|
69
|
+
*/
|
|
70
|
+
function transformLog(logObj: LogObject): string {
|
|
71
|
+
let logBody = logObj.args[0]
|
|
72
|
+
if (typeof logBody !== 'string') {
|
|
73
|
+
logBody = JSON.stringify(logBody)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const timestamp = useDateFormat(new Date(), 'YYYY-MM-DD HH:mm:ss.SSS').value
|
|
77
|
+
logBody = timestamp + '\n' + logBody
|
|
78
|
+
|
|
79
|
+
if (logObj.level <= LogLevels.warn) {
|
|
80
|
+
const fullStack = new Error(logBody).stack
|
|
81
|
+
const filteredStack = fullStack?.split('\n at ').filter(x => !x.includes('node_modules'))
|
|
82
|
+
const relevantStack = filteredStack?.slice(0, filteredStack.length - 3)
|
|
83
|
+
if (relevantStack?.length && logObj.level <= LogLevels.warn) {
|
|
84
|
+
if (logObj.level === LogLevels.warn) {
|
|
85
|
+
relevantStack[0] = relevantStack[0]!.replace('Error:', 'Warn:')
|
|
86
|
+
}
|
|
87
|
+
logBody = timestamp + '\n' + relevantStack.join('\n\tat ')
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return logBody
|
|
92
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Available variants for UI libraries.
|
|
3
|
+
*
|
|
4
|
+
* `nuxt-ui` - full https://ui.nuxt.com/ via `@nuxt/ui` connector module **[RECOMMENDED]**
|
|
5
|
+
*
|
|
6
|
+
* `tailwind` - only https://tailwindcss.com/ via `@nuxtjs/tailwindcss` connector module
|
|
7
|
+
*
|
|
8
|
+
* `off` - no UI library **[DEFAULT]**
|
|
9
|
+
*/
|
|
10
|
+
export type UIOptions = 'nuxt-ui' | 'tailwind' | 'off'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Available variants for Database connector.
|
|
14
|
+
*
|
|
15
|
+
* `neon` - https://neon.tech/ via `nuxt-neon` connector module **[RECOMMENDED]**
|
|
16
|
+
*
|
|
17
|
+
* `supabase` - https://supabase.com/ via `@nuxtjs/supabase` connector module
|
|
18
|
+
*
|
|
19
|
+
* `off` - no database module **[DEFAULT]**
|
|
20
|
+
*/
|
|
21
|
+
export type DBOptions = 'neon' | 'supabase' | 'off'
|