create-absolutejs 0.8.2 → 0.9.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 +24 -24
- package/README.md +179 -179
- package/dist/data.js +3 -0
- package/dist/generators/configurations/generateDrizzleConfig.js +15 -15
- package/dist/generators/configurations/generatePrettierrc.js +9 -9
- package/dist/generators/configurations/initializeRoot.js +2 -0
- package/dist/generators/db/dockerInitTemplates.js +79 -79
- package/dist/generators/db/generateDatabaseTypes.js +6 -6
- package/dist/generators/db/generateDockerContainer.js +19 -19
- package/dist/generators/db/generateDrizzleSchema.js +17 -17
- package/dist/generators/db/generateSqliteSchema.js +8 -8
- package/dist/generators/db/handlerTemplates.js +259 -259
- package/dist/generators/db/scaffoldDocker.js +1 -1
- package/dist/generators/html/generateHTMLPage.js +60 -60
- package/dist/generators/htmx/generateHTMXPage.js +86 -86
- package/dist/generators/project/generateAbsoluteAuthConfig.js +96 -96
- package/dist/generators/project/generateBuildBlock.d.ts +2 -1
- package/dist/generators/project/generateBuildBlock.js +9 -5
- package/dist/generators/project/generateDBBlock.js +9 -9
- package/dist/generators/project/generateImportsBlock.js +1 -0
- package/dist/generators/project/generateMarkupCSS.js +145 -145
- package/dist/generators/project/generateRoutesBlock.js +36 -36
- package/dist/generators/project/generateServer.d.ts +2 -1
- package/dist/generators/project/generateServer.js +29 -19
- package/dist/generators/project/scaffoldBackend.d.ts +2 -1
- package/dist/generators/project/scaffoldBackend.js +2 -1
- package/dist/generators/react/generateReactComponents.js +95 -95
- package/dist/generators/svelte/generateSveltePage.js +210 -210
- package/dist/generators/vue/generateVuePage.js +261 -261
- package/dist/messages.js +43 -43
- package/dist/scaffold.js +1 -0
- package/dist/templates/README.md +35 -35
- package/dist/templates/assets/svg/google-logo.svg +7 -7
- package/dist/templates/assets/svg/htmx-logo-black.svg +9 -9
- package/dist/templates/assets/svg/htmx-logo-white.svg +9 -9
- package/dist/templates/assets/svg/vue-logo.svg +4 -4
- package/dist/templates/configurations/.prettierignore +3 -3
- package/dist/templates/configurations/.prettierrc.json +9 -9
- package/dist/templates/configurations/drizzle.config.ts +13 -13
- package/dist/templates/configurations/eslint.config.mjs +243 -243
- package/dist/templates/configurations/tsconfig.example.json +98 -98
- package/dist/templates/constants.ts +2 -2
- package/dist/templates/db/docker-compose.db.yml +15 -15
- package/dist/templates/git/gitignore +51 -51
- package/dist/templates/html/scripts/typescript-example.ts +21 -21
- package/dist/templates/react/components/App.tsx +52 -52
- package/dist/templates/react/components/Head.tsx +34 -34
- package/dist/templates/react/components/OAuthLink.tsx +39 -39
- package/dist/templates/react/components/ProfilePicture.tsx +56 -56
- package/dist/templates/styles/colors.ts +11 -11
- package/dist/templates/styles/reset.css +84 -84
- package/dist/templates/svelte/components/Counter.svelte +19 -19
- package/dist/templates/svelte/composables/counter.svelte.ts +14 -14
- package/dist/templates/tailwind/postcss.config.ts +8 -8
- package/dist/templates/tailwind/tailwind.config.ts +7 -7
- package/dist/templates/tailwind/tailwind.css +1 -1
- package/dist/templates/vue/components/CountButton.vue +39 -39
- package/dist/templates/vue/composables/useCount.ts +14 -14
- package/dist/versions.d.ts +1 -1
- package/dist/versions.js +1 -1
- package/package.json +1 -1
|
@@ -1,40 +1,40 @@
|
|
|
1
1
|
import { formatNavLink } from '../../utils/formatNavLink';
|
|
2
2
|
export const generateDropdownComponent = (frontends) => {
|
|
3
3
|
const navLinks = frontends.map(formatNavLink).join('\n\t\t\t');
|
|
4
|
-
return `import { useState } from 'react';
|
|
5
|
-
|
|
6
|
-
export const Dropdown = () => {
|
|
7
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
8
|
-
|
|
9
|
-
return (
|
|
10
|
-
<details
|
|
11
|
-
onPointerEnter={() => setIsOpen(true)}
|
|
12
|
-
onPointerLeave={() => setIsOpen(false)}
|
|
13
|
-
open={isOpen}
|
|
14
|
-
>
|
|
15
|
-
<summary>Pages</summary>
|
|
16
|
-
<nav>
|
|
17
|
-
${navLinks}
|
|
18
|
-
</nav>
|
|
19
|
-
</details>
|
|
20
|
-
);
|
|
21
|
-
};
|
|
4
|
+
return `import { useState } from 'react';
|
|
5
|
+
|
|
6
|
+
export const Dropdown = () => {
|
|
7
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<details
|
|
11
|
+
onPointerEnter={() => setIsOpen(true)}
|
|
12
|
+
onPointerLeave={() => setIsOpen(false)}
|
|
13
|
+
open={isOpen}
|
|
14
|
+
>
|
|
15
|
+
<summary>Pages</summary>
|
|
16
|
+
<nav>
|
|
17
|
+
${navLinks}
|
|
18
|
+
</nav>
|
|
19
|
+
</details>
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
22
|
`;
|
|
23
23
|
};
|
|
24
|
-
export const generateSignInComponent = (absProviders) => `import { useState } from 'react';
|
|
25
|
-
import { OAuthLink } from './OAuthLink';
|
|
26
|
-
|
|
27
|
-
export const SignIn = () => {
|
|
28
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
29
|
-
|
|
30
|
-
return (
|
|
31
|
-
<details
|
|
32
|
-
onPointerEnter={() => setIsOpen(true)}
|
|
33
|
-
onPointerLeave={() => setIsOpen(false)}
|
|
34
|
-
open={isOpen}
|
|
35
|
-
>
|
|
36
|
-
<summary>Sign In</summary>
|
|
37
|
-
<nav>
|
|
24
|
+
export const generateSignInComponent = (absProviders) => `import { useState } from 'react';
|
|
25
|
+
import { OAuthLink } from './OAuthLink';
|
|
26
|
+
|
|
27
|
+
export const SignIn = () => {
|
|
28
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<details
|
|
32
|
+
onPointerEnter={() => setIsOpen(true)}
|
|
33
|
+
onPointerLeave={() => setIsOpen(false)}
|
|
34
|
+
open={isOpen}
|
|
35
|
+
>
|
|
36
|
+
<summary>Sign In</summary>
|
|
37
|
+
<nav>
|
|
38
38
|
${absProviders && absProviders.length > 0
|
|
39
39
|
? absProviders
|
|
40
40
|
.map((provider) => {
|
|
@@ -44,83 +44,83 @@ export const SignIn = () => {
|
|
|
44
44
|
return `<OAuthLink provider="${provider}" logoUrl="${logoUrl}" name="${name}" mode="in" />`;
|
|
45
45
|
})
|
|
46
46
|
.join('\n\t\t\t')
|
|
47
|
-
: `<p>No OAuth providers configured</p>`}
|
|
48
|
-
</nav>
|
|
49
|
-
</details>
|
|
50
|
-
);
|
|
51
|
-
}
|
|
47
|
+
: `<p>No OAuth providers configured</p>`}
|
|
48
|
+
</nav>
|
|
49
|
+
</details>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
52
|
`;
|
|
53
53
|
export const generateReactExamplePage = (authOption) => {
|
|
54
54
|
const useBlockReturn = authOption === 'abs';
|
|
55
|
-
const propsType = `
|
|
56
|
-
type ReactExampleProps = {
|
|
57
|
-
initialCount: number;
|
|
58
|
-
cssPath: string;
|
|
59
|
-
${authOption === 'abs' ? 'user: User | null;\n\tproviderConfiguration: ProviderConfiguration | undefined;' : ''}
|
|
60
|
-
};
|
|
55
|
+
const propsType = `
|
|
56
|
+
type ReactExampleProps = {
|
|
57
|
+
initialCount: number;
|
|
58
|
+
cssPath: string;
|
|
59
|
+
${authOption === 'abs' ? 'user: User | null;\n\tproviderConfiguration: ProviderConfiguration | undefined;' : ''}
|
|
60
|
+
};
|
|
61
61
|
`;
|
|
62
62
|
const fnSignature = authOption === 'abs'
|
|
63
63
|
? `export const ReactExample = ({ initialCount, cssPath, user, providerConfiguration }: ReactExampleProps) => {`
|
|
64
64
|
: `export const ReactExample = ({ initialCount, cssPath }: ReactExampleProps) => (`;
|
|
65
|
-
const extractProps = ` const userImage =
|
|
66
|
-
user?.metadata && providerConfiguration?.picture
|
|
67
|
-
? extractPropFromIdentity(
|
|
68
|
-
user.metadata,
|
|
69
|
-
providerConfiguration.picture,
|
|
70
|
-
'string'
|
|
71
|
-
)
|
|
72
|
-
: undefined;
|
|
73
|
-
|
|
74
|
-
const givenName =
|
|
75
|
-
user?.metadata && providerConfiguration?.givenName
|
|
76
|
-
? extractPropFromIdentity(
|
|
77
|
-
user.metadata,
|
|
78
|
-
providerConfiguration.givenName,
|
|
79
|
-
'string'
|
|
80
|
-
)
|
|
81
|
-
: undefined;
|
|
82
|
-
|
|
83
|
-
const familyName =
|
|
84
|
-
user?.metadata && providerConfiguration?.familyName
|
|
85
|
-
? extractPropFromIdentity(
|
|
86
|
-
user.metadata,
|
|
87
|
-
providerConfiguration.familyName,
|
|
88
|
-
'string'
|
|
89
|
-
)
|
|
65
|
+
const extractProps = ` const userImage =
|
|
66
|
+
user?.metadata && providerConfiguration?.picture
|
|
67
|
+
? extractPropFromIdentity(
|
|
68
|
+
user.metadata,
|
|
69
|
+
providerConfiguration.picture,
|
|
70
|
+
'string'
|
|
71
|
+
)
|
|
72
|
+
: undefined;
|
|
73
|
+
|
|
74
|
+
const givenName =
|
|
75
|
+
user?.metadata && providerConfiguration?.givenName
|
|
76
|
+
? extractPropFromIdentity(
|
|
77
|
+
user.metadata,
|
|
78
|
+
providerConfiguration.givenName,
|
|
79
|
+
'string'
|
|
80
|
+
)
|
|
81
|
+
: undefined;
|
|
82
|
+
|
|
83
|
+
const familyName =
|
|
84
|
+
user?.metadata && providerConfiguration?.familyName
|
|
85
|
+
? extractPropFromIdentity(
|
|
86
|
+
user.metadata,
|
|
87
|
+
providerConfiguration.familyName,
|
|
88
|
+
'string'
|
|
89
|
+
)
|
|
90
90
|
: undefined;`;
|
|
91
91
|
const userButtonsBlock = authOption === 'abs'
|
|
92
92
|
? `{user ? <ProfilePicture userImage={userImage} givenName={givenName} familyName={familyName} /> : <SignIn />}`
|
|
93
93
|
: ``;
|
|
94
94
|
const rightGroup = authOption === 'abs'
|
|
95
|
-
? `<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
|
96
|
-
<Dropdown />
|
|
97
|
-
${userButtonsBlock}
|
|
95
|
+
? `<div style={{ display: 'flex', alignItems: 'center', gap: '1rem' }}>
|
|
96
|
+
<Dropdown />
|
|
97
|
+
${userButtonsBlock}
|
|
98
98
|
</div>`
|
|
99
99
|
: `<Dropdown />`;
|
|
100
100
|
const closing = authOption === 'abs' ? `};` : `);`;
|
|
101
|
-
return `
|
|
102
|
-
${authOption === 'abs' ? `import { User } from '../../../types/databaseTypes';\nimport { extractPropFromIdentity, ProviderConfiguration } from '@absolutejs/auth';` : ''}
|
|
103
|
-
import { App } from '../components/App';
|
|
104
|
-
import { Dropdown } from '../components/Dropdown';
|
|
105
|
-
import { Head } from '../components/Head';
|
|
106
|
-
${authOption === 'abs' ? `import { ProfilePicture } from '../components/ProfilePicture';\nimport { SignIn } from '../components/SignIn';` : ''}
|
|
107
|
-
|
|
108
|
-
${propsType}
|
|
109
|
-
|
|
110
|
-
${fnSignature}
|
|
111
|
-
${authOption === 'abs' ? extractProps : ''}
|
|
112
|
-
${useBlockReturn ? 'return (' : ''}
|
|
113
|
-
<html>
|
|
114
|
-
<Head cssPath={cssPath} />
|
|
115
|
-
<body>
|
|
116
|
-
<header>
|
|
117
|
-
<a href="/">AbsoluteJS</a>
|
|
118
|
-
${rightGroup}
|
|
119
|
-
</header>
|
|
120
|
-
<App initialCount={initialCount} />
|
|
121
|
-
</body>
|
|
122
|
-
</html>
|
|
123
|
-
${useBlockReturn ? ');' : ''}
|
|
124
|
-
${closing}
|
|
101
|
+
return `
|
|
102
|
+
${authOption === 'abs' ? `import { User } from '../../../types/databaseTypes';\nimport { extractPropFromIdentity, ProviderConfiguration } from '@absolutejs/auth';` : ''}
|
|
103
|
+
import { App } from '../components/App';
|
|
104
|
+
import { Dropdown } from '../components/Dropdown';
|
|
105
|
+
import { Head } from '../components/Head';
|
|
106
|
+
${authOption === 'abs' ? `import { ProfilePicture } from '../components/ProfilePicture';\nimport { SignIn } from '../components/SignIn';` : ''}
|
|
107
|
+
|
|
108
|
+
${propsType}
|
|
109
|
+
|
|
110
|
+
${fnSignature}
|
|
111
|
+
${authOption === 'abs' ? extractProps : ''}
|
|
112
|
+
${useBlockReturn ? 'return (' : ''}
|
|
113
|
+
<html>
|
|
114
|
+
<Head cssPath={cssPath} />
|
|
115
|
+
<body>
|
|
116
|
+
<header>
|
|
117
|
+
<a href="/">AbsoluteJS</a>
|
|
118
|
+
${rightGroup}
|
|
119
|
+
</header>
|
|
120
|
+
<App initialCount={initialCount} />
|
|
121
|
+
</body>
|
|
122
|
+
</html>
|
|
123
|
+
${useBlockReturn ? ');' : ''}
|
|
124
|
+
${closing}
|
|
125
125
|
`;
|
|
126
126
|
};
|
|
@@ -1,215 +1,215 @@
|
|
|
1
1
|
import { formatNavLink } from '../../utils/formatNavLink';
|
|
2
2
|
export const generateSveltePage = (frontends) => {
|
|
3
3
|
const navLinks = frontends.map(formatNavLink).join('\n\t\t\t');
|
|
4
|
-
return `<script lang="ts">
|
|
5
|
-
type SvelteExampleProps = {
|
|
6
|
-
initialCount: number;
|
|
7
|
-
cssPath: string;
|
|
8
|
-
};
|
|
9
|
-
import Counter from '../components/Counter.svelte';
|
|
10
|
-
|
|
11
|
-
let { initialCount, cssPath }: SvelteExampleProps = $props();
|
|
12
|
-
let isOpen = $state(false);
|
|
13
|
-
</script>
|
|
14
|
-
|
|
15
|
-
<svelte:head>
|
|
16
|
-
<meta charset="utf-8" />
|
|
17
|
-
<title>AbsoluteJS + Svelte</title>
|
|
18
|
-
<meta name="description" content="AbsoluteJS Svelte Example" />
|
|
19
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
20
|
-
<link rel="icon" href="/assets/ico/favicon.ico" />
|
|
21
|
-
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
22
|
-
<link
|
|
23
|
-
rel="preconnect"
|
|
24
|
-
href="https://fonts.gstatic.com"
|
|
25
|
-
crossOrigin="anonymous"
|
|
26
|
-
/>
|
|
27
|
-
<link
|
|
28
|
-
href={\`https://fonts.googleapis.com/css2?family=Poppins:wght@100..900&display=swap\`}
|
|
29
|
-
rel="stylesheet"
|
|
30
|
-
/>
|
|
31
|
-
<link rel="stylesheet" href={cssPath} type="text/css" />
|
|
32
|
-
</svelte:head>
|
|
33
|
-
|
|
34
|
-
<header>
|
|
35
|
-
<a href="/">AbsoluteJS</a>
|
|
36
|
-
<details
|
|
37
|
-
open={isOpen}
|
|
38
|
-
onpointerenter={() => (isOpen = true)}
|
|
39
|
-
onpointerleave={() => (isOpen = false)}
|
|
40
|
-
>
|
|
41
|
-
<summary>Pages</summary>
|
|
42
|
-
<nav>
|
|
43
|
-
${navLinks}
|
|
44
|
-
</nav>
|
|
45
|
-
</details>
|
|
46
|
-
</header>
|
|
47
|
-
|
|
48
|
-
<main>
|
|
49
|
-
<nav>
|
|
50
|
-
<a href="https://absolutejs.com" target="_blank">
|
|
51
|
-
<img
|
|
52
|
-
class="logo"
|
|
53
|
-
src="/assets/png/absolutejs-temp.png"
|
|
54
|
-
alt="AbsoluteJS Logo"
|
|
55
|
-
/>
|
|
56
|
-
</a>
|
|
57
|
-
<a href="https://svelte.dev" target="_blank">
|
|
58
|
-
<img
|
|
59
|
-
class="logo svelte"
|
|
60
|
-
src="/assets/svg/svelte-logo.svg"
|
|
61
|
-
alt="Svelte Logo"
|
|
62
|
-
/>
|
|
63
|
-
</a>
|
|
64
|
-
</nav>
|
|
65
|
-
<h1>AbsoluteJS + Svelte</h1>
|
|
66
|
-
<Counter {initialCount} />
|
|
67
|
-
<p>
|
|
68
|
-
Edit <code>example/svelte/pages/SvelteExample.svelte</code> then save and
|
|
69
|
-
refresh to update the page.
|
|
70
|
-
</p>
|
|
71
|
-
<p style="color: #777">( Hot Module Reloading is coming soon )</p>
|
|
72
|
-
<p style="margin-top: 2rem;">
|
|
73
|
-
Explore the other pages to see how AbsoluteJS seamlessly unifies
|
|
74
|
-
multiple frameworks on a single server.
|
|
75
|
-
</p>
|
|
76
|
-
<p style="color: #777; font-size: 1rem; margin-top: 2rem;">
|
|
77
|
-
Click on the AbsoluteJS and Svelte logos to learn more.
|
|
78
|
-
</p>
|
|
79
|
-
</main>
|
|
80
|
-
|
|
81
|
-
<style>
|
|
82
|
-
header {
|
|
83
|
-
align-items: center;
|
|
84
|
-
background-color: #1a1a1a;
|
|
85
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
86
|
-
display: flex;
|
|
87
|
-
justify-content: space-between;
|
|
88
|
-
padding: 2rem;
|
|
89
|
-
text-align: center;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
header a {
|
|
93
|
-
position: relative;
|
|
94
|
-
color: #5fbeeb;
|
|
95
|
-
text-decoration: none;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
header a::after {
|
|
99
|
-
content: '';
|
|
100
|
-
position: absolute;
|
|
101
|
-
left: 0;
|
|
102
|
-
bottom: 0;
|
|
103
|
-
width: 100%;
|
|
104
|
-
height: 2px;
|
|
105
|
-
background: linear-gradient(
|
|
106
|
-
90deg,
|
|
107
|
-
#5fbeeb 0%,
|
|
108
|
-
#35d5a2 50%,
|
|
109
|
-
#ff4b91 100%
|
|
110
|
-
);
|
|
111
|
-
transform: scaleX(0);
|
|
112
|
-
transform-origin: left;
|
|
113
|
-
transition: transform 0.25s ease-in-out;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
header a:hover::after {
|
|
117
|
-
transform: scaleX(1);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
h1 {
|
|
121
|
-
font-size: 2.5rem;
|
|
122
|
-
margin-top: 2rem;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
.logo {
|
|
126
|
-
height: 8rem;
|
|
127
|
-
width: 8rem;
|
|
128
|
-
will-change: filter;
|
|
129
|
-
transition: filter 300ms;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
.logo:hover {
|
|
133
|
-
filter: drop-shadow(0 0 2rem #5fbeeb);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
.logo.svelte:hover {
|
|
137
|
-
filter: drop-shadow(0 0 2rem #ff3e00);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
nav {
|
|
141
|
-
display: flex;
|
|
142
|
-
gap: 4rem;
|
|
143
|
-
justify-content: center;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
header details {
|
|
147
|
-
position: relative;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
header details summary {
|
|
151
|
-
list-style: none;
|
|
152
|
-
appearance: none;
|
|
153
|
-
-webkit-appearance: none;
|
|
154
|
-
cursor: pointer;
|
|
155
|
-
user-select: none;
|
|
156
|
-
color: #5fbeeb;
|
|
157
|
-
font-size: 1.5rem;
|
|
158
|
-
font-weight: 500;
|
|
159
|
-
padding: 0.5rem 1rem;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
header summary::after {
|
|
163
|
-
content: '▼';
|
|
164
|
-
display: inline-block;
|
|
165
|
-
margin-left: 0.5rem;
|
|
166
|
-
font-size: 0.75rem;
|
|
167
|
-
transition: transform 0.3s ease;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
header details[open] summary::after {
|
|
171
|
-
transform: rotate(180deg);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
header details nav {
|
|
175
|
-
position: absolute;
|
|
176
|
-
top: 100%;
|
|
177
|
-
right: -0.5rem;
|
|
178
|
-
display: flex;
|
|
179
|
-
flex-direction: column;
|
|
180
|
-
gap: 0.75rem;
|
|
181
|
-
background: rgba(185, 185, 185, 0.1);
|
|
182
|
-
backdrop-filter: blur(4px);
|
|
183
|
-
border: 1px solid #5fbeeb;
|
|
184
|
-
border-radius: 1rem;
|
|
185
|
-
padding: 1rem 1.5rem;
|
|
186
|
-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
|
|
187
|
-
opacity: 0;
|
|
188
|
-
transform: translateY(-8px);
|
|
189
|
-
pointer-events: none;
|
|
190
|
-
transition:
|
|
191
|
-
opacity 0.3s ease,
|
|
192
|
-
transform 0.3s ease;
|
|
193
|
-
z-index: 1000;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
header details[open] nav {
|
|
197
|
-
opacity: 1;
|
|
198
|
-
transform: translateY(0);
|
|
199
|
-
pointer-events: auto;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
header details nav a {
|
|
203
|
-
font-size: 1.1rem;
|
|
204
|
-
padding: 0.25rem 0;
|
|
205
|
-
white-space: nowrap;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
@media (prefers-color-scheme: light) {
|
|
209
|
-
header {
|
|
210
|
-
background-color: #ffffff;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
</style>
|
|
4
|
+
return `<script lang="ts">
|
|
5
|
+
type SvelteExampleProps = {
|
|
6
|
+
initialCount: number;
|
|
7
|
+
cssPath: string;
|
|
8
|
+
};
|
|
9
|
+
import Counter from '../components/Counter.svelte';
|
|
10
|
+
|
|
11
|
+
let { initialCount, cssPath }: SvelteExampleProps = $props();
|
|
12
|
+
let isOpen = $state(false);
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<svelte:head>
|
|
16
|
+
<meta charset="utf-8" />
|
|
17
|
+
<title>AbsoluteJS + Svelte</title>
|
|
18
|
+
<meta name="description" content="AbsoluteJS Svelte Example" />
|
|
19
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
20
|
+
<link rel="icon" href="/assets/ico/favicon.ico" />
|
|
21
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
22
|
+
<link
|
|
23
|
+
rel="preconnect"
|
|
24
|
+
href="https://fonts.gstatic.com"
|
|
25
|
+
crossOrigin="anonymous"
|
|
26
|
+
/>
|
|
27
|
+
<link
|
|
28
|
+
href={\`https://fonts.googleapis.com/css2?family=Poppins:wght@100..900&display=swap\`}
|
|
29
|
+
rel="stylesheet"
|
|
30
|
+
/>
|
|
31
|
+
<link rel="stylesheet" href={cssPath} type="text/css" />
|
|
32
|
+
</svelte:head>
|
|
33
|
+
|
|
34
|
+
<header>
|
|
35
|
+
<a href="/">AbsoluteJS</a>
|
|
36
|
+
<details
|
|
37
|
+
open={isOpen}
|
|
38
|
+
onpointerenter={() => (isOpen = true)}
|
|
39
|
+
onpointerleave={() => (isOpen = false)}
|
|
40
|
+
>
|
|
41
|
+
<summary>Pages</summary>
|
|
42
|
+
<nav>
|
|
43
|
+
${navLinks}
|
|
44
|
+
</nav>
|
|
45
|
+
</details>
|
|
46
|
+
</header>
|
|
47
|
+
|
|
48
|
+
<main>
|
|
49
|
+
<nav>
|
|
50
|
+
<a href="https://absolutejs.com" target="_blank">
|
|
51
|
+
<img
|
|
52
|
+
class="logo"
|
|
53
|
+
src="/assets/png/absolutejs-temp.png"
|
|
54
|
+
alt="AbsoluteJS Logo"
|
|
55
|
+
/>
|
|
56
|
+
</a>
|
|
57
|
+
<a href="https://svelte.dev" target="_blank">
|
|
58
|
+
<img
|
|
59
|
+
class="logo svelte"
|
|
60
|
+
src="/assets/svg/svelte-logo.svg"
|
|
61
|
+
alt="Svelte Logo"
|
|
62
|
+
/>
|
|
63
|
+
</a>
|
|
64
|
+
</nav>
|
|
65
|
+
<h1>AbsoluteJS + Svelte</h1>
|
|
66
|
+
<Counter {initialCount} />
|
|
67
|
+
<p>
|
|
68
|
+
Edit <code>example/svelte/pages/SvelteExample.svelte</code> then save and
|
|
69
|
+
refresh to update the page.
|
|
70
|
+
</p>
|
|
71
|
+
<p style="color: #777">( Hot Module Reloading is coming soon )</p>
|
|
72
|
+
<p style="margin-top: 2rem;">
|
|
73
|
+
Explore the other pages to see how AbsoluteJS seamlessly unifies
|
|
74
|
+
multiple frameworks on a single server.
|
|
75
|
+
</p>
|
|
76
|
+
<p style="color: #777; font-size: 1rem; margin-top: 2rem;">
|
|
77
|
+
Click on the AbsoluteJS and Svelte logos to learn more.
|
|
78
|
+
</p>
|
|
79
|
+
</main>
|
|
80
|
+
|
|
81
|
+
<style>
|
|
82
|
+
header {
|
|
83
|
+
align-items: center;
|
|
84
|
+
background-color: #1a1a1a;
|
|
85
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
86
|
+
display: flex;
|
|
87
|
+
justify-content: space-between;
|
|
88
|
+
padding: 2rem;
|
|
89
|
+
text-align: center;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
header a {
|
|
93
|
+
position: relative;
|
|
94
|
+
color: #5fbeeb;
|
|
95
|
+
text-decoration: none;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
header a::after {
|
|
99
|
+
content: '';
|
|
100
|
+
position: absolute;
|
|
101
|
+
left: 0;
|
|
102
|
+
bottom: 0;
|
|
103
|
+
width: 100%;
|
|
104
|
+
height: 2px;
|
|
105
|
+
background: linear-gradient(
|
|
106
|
+
90deg,
|
|
107
|
+
#5fbeeb 0%,
|
|
108
|
+
#35d5a2 50%,
|
|
109
|
+
#ff4b91 100%
|
|
110
|
+
);
|
|
111
|
+
transform: scaleX(0);
|
|
112
|
+
transform-origin: left;
|
|
113
|
+
transition: transform 0.25s ease-in-out;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
header a:hover::after {
|
|
117
|
+
transform: scaleX(1);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
h1 {
|
|
121
|
+
font-size: 2.5rem;
|
|
122
|
+
margin-top: 2rem;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.logo {
|
|
126
|
+
height: 8rem;
|
|
127
|
+
width: 8rem;
|
|
128
|
+
will-change: filter;
|
|
129
|
+
transition: filter 300ms;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.logo:hover {
|
|
133
|
+
filter: drop-shadow(0 0 2rem #5fbeeb);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.logo.svelte:hover {
|
|
137
|
+
filter: drop-shadow(0 0 2rem #ff3e00);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
nav {
|
|
141
|
+
display: flex;
|
|
142
|
+
gap: 4rem;
|
|
143
|
+
justify-content: center;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
header details {
|
|
147
|
+
position: relative;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
header details summary {
|
|
151
|
+
list-style: none;
|
|
152
|
+
appearance: none;
|
|
153
|
+
-webkit-appearance: none;
|
|
154
|
+
cursor: pointer;
|
|
155
|
+
user-select: none;
|
|
156
|
+
color: #5fbeeb;
|
|
157
|
+
font-size: 1.5rem;
|
|
158
|
+
font-weight: 500;
|
|
159
|
+
padding: 0.5rem 1rem;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
header summary::after {
|
|
163
|
+
content: '▼';
|
|
164
|
+
display: inline-block;
|
|
165
|
+
margin-left: 0.5rem;
|
|
166
|
+
font-size: 0.75rem;
|
|
167
|
+
transition: transform 0.3s ease;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
header details[open] summary::after {
|
|
171
|
+
transform: rotate(180deg);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
header details nav {
|
|
175
|
+
position: absolute;
|
|
176
|
+
top: 100%;
|
|
177
|
+
right: -0.5rem;
|
|
178
|
+
display: flex;
|
|
179
|
+
flex-direction: column;
|
|
180
|
+
gap: 0.75rem;
|
|
181
|
+
background: rgba(185, 185, 185, 0.1);
|
|
182
|
+
backdrop-filter: blur(4px);
|
|
183
|
+
border: 1px solid #5fbeeb;
|
|
184
|
+
border-radius: 1rem;
|
|
185
|
+
padding: 1rem 1.5rem;
|
|
186
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
|
|
187
|
+
opacity: 0;
|
|
188
|
+
transform: translateY(-8px);
|
|
189
|
+
pointer-events: none;
|
|
190
|
+
transition:
|
|
191
|
+
opacity 0.3s ease,
|
|
192
|
+
transform 0.3s ease;
|
|
193
|
+
z-index: 1000;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
header details[open] nav {
|
|
197
|
+
opacity: 1;
|
|
198
|
+
transform: translateY(0);
|
|
199
|
+
pointer-events: auto;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
header details nav a {
|
|
203
|
+
font-size: 1.1rem;
|
|
204
|
+
padding: 0.25rem 0;
|
|
205
|
+
white-space: nowrap;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
@media (prefers-color-scheme: light) {
|
|
209
|
+
header {
|
|
210
|
+
background-color: #ffffff;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
</style>
|
|
214
214
|
`;
|
|
215
215
|
};
|