ecopages 0.2.0-alpha.29 → 0.2.0-alpha.30
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/dist/CHANGELOG.md +15 -0
- package/dist/README.md +91 -0
- package/dist/bin/cli.js +224 -0
- package/dist/bin/launch-plan.js +96 -0
- package/dist/css/view-transitions.css +217 -0
- package/dist/package.json +42 -0
- package/package.json +2 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `ecopages` are documented here.
|
|
4
|
+
|
|
5
|
+
> **Note:** Changelog tracking begins at version `0.2.0`. Changes prior to this release are not recorded here but are available in the git history.
|
|
6
|
+
|
|
7
|
+
## [UNRELEASED] — TBD
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
- Localized the Node CLI `tsx` runtime dependency so `ecopages` no longer requires a globally installed `tsx` binary.
|
|
12
|
+
|
|
13
|
+
### Refactoring
|
|
14
|
+
|
|
15
|
+
- Simplified CLI runtime startup and removed the thin-host bootstrap path; runtime selection now follows explicit `--runtime` overrides, package-manager hints, and Bun availability.
|
package/dist/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# ecopages
|
|
2
|
+
|
|
3
|
+
The official CLI for the Ecopages framework.
|
|
4
|
+
|
|
5
|
+
It provides scaffolding and development commands to streamline your workflow. It prefers Bun when available, falls back to Node otherwise, and automatically detects your `eco.config.ts`.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
Initialize a new project from the default template:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bunx ecopages init my-app
|
|
13
|
+
cd my-app
|
|
14
|
+
bun install
|
|
15
|
+
bun dev
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Commands
|
|
19
|
+
|
|
20
|
+
| Command | Description | Equivalent (Bun) |
|
|
21
|
+
| :--------------------------- | :----------------------------------------- | :------------------------------ |
|
|
22
|
+
| `ecopages init <dir>` | Scaffolds a new project | N/A |
|
|
23
|
+
| `ecopages dev [entry]` | Starts the dev server | `bun run [entry] --dev` |
|
|
24
|
+
| `ecopages dev:watch [entry]` | Dev server + hard restarts on file changes | `bun --watch run [entry] --dev` |
|
|
25
|
+
| `ecopages dev:hot [entry]` | Dev server + HMR (no hard restarts) | `bun --hot run [entry] --dev` |
|
|
26
|
+
| `ecopages build [entry]` | Creates a production build | `bun run [entry] --build` |
|
|
27
|
+
| `ecopages start [entry]` | Starts the production server | `bun run [entry]` |
|
|
28
|
+
| `ecopages preview [entry]` | Previews the production build locally | `bun run [entry] --preview` |
|
|
29
|
+
|
|
30
|
+
> [!NOTE]
|
|
31
|
+
> `[entry]` defaults to `app.ts` if not provided.
|
|
32
|
+
|
|
33
|
+
## Environment & Runtime Options
|
|
34
|
+
|
|
35
|
+
Server and build commands accept the following options. They automatically map to the equivalent environment variables for the underlying process:
|
|
36
|
+
|
|
37
|
+
| Option | Env Var | Description |
|
|
38
|
+
| :------------------------- | :---------------------- | :---------------------------------- |
|
|
39
|
+
| `-p, --port <port>` | `ECOPAGES_PORT` | Server port (default 3000) |
|
|
40
|
+
| `-n, --hostname <host>` | `ECOPAGES_HOSTNAME` | Server hostname |
|
|
41
|
+
| `-b, --base-url <url>` | `ECOPAGES_BASE_URL` | Base URL string |
|
|
42
|
+
| `-d, --debug` | `ECOPAGES_LOGGER_DEBUG` | Enables debug-level logging |
|
|
43
|
+
| `-r, --react-fast-refresh` | | Enables React Fast Refresh |
|
|
44
|
+
| `--runtime <runtime>` | | Force execution via `bun` or `node` |
|
|
45
|
+
|
|
46
|
+
### Runtime Detection
|
|
47
|
+
|
|
48
|
+
The CLI prefers Bun when the package manager already indicates Bun, when the `Bun` global is available, or when you force it with `--runtime bun`. Otherwise it falls back to Node.
|
|
49
|
+
|
|
50
|
+
You can explicitly force the engine using the `--runtime` flag:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
ecopages build --runtime bun
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Example Usage
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# Debug dev server on custom port
|
|
60
|
+
ecopages dev --port 8080 --debug
|
|
61
|
+
|
|
62
|
+
# Dev server with React Fast Refresh enabled
|
|
63
|
+
ecopages dev -r
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Ecosystem & Plugins
|
|
67
|
+
|
|
68
|
+
Ecopages relies on a modular architecture. Core logic and framework integrations are published as `@ecopages/*` packages on [npm](https://www.npmjs.com/org/ecopages).
|
|
69
|
+
|
|
70
|
+
### Official Packages
|
|
71
|
+
|
|
72
|
+
| Package | Description |
|
|
73
|
+
| :---------------------------- | :----------------------------------------- |
|
|
74
|
+
| `@ecopages/browser-router` | Client-side navigation & view transitions. |
|
|
75
|
+
| `@ecopages/codemod` | AST migrations for codebase upgrades. |
|
|
76
|
+
| `@ecopages/core` | The foundational SSG engine. |
|
|
77
|
+
| `@ecopages/ecopages-jsx` | Ecopages-owned JSX routes and hydration. |
|
|
78
|
+
| `@ecopages/file-system` | Runtime-agnostic file system utilities. |
|
|
79
|
+
| `@ecopages/image-processor` | Asset pipeline for responsive images. |
|
|
80
|
+
| `@ecopages/kitajs` | Integration for KitaJS. |
|
|
81
|
+
| `@ecopages/lit` | Integration for Lit SSR/Islands. |
|
|
82
|
+
| `@ecopages/mdx` | Integration for standalone MDX routes. |
|
|
83
|
+
| `@ecopages/postcss-processor` | CSS processing pipeline using PostCSS. |
|
|
84
|
+
| `@ecopages/react` | Integration for React 19 SSR/Islands. |
|
|
85
|
+
| `@ecopages/react-router` | SPA routing for React. |
|
|
86
|
+
|
|
87
|
+
Explore all packages at [npmjs.com/org/ecopages](https://www.npmjs.com/org/ecopages).
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
MIT
|
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { defineCommand, runMain } from "citty";
|
|
3
|
+
import { downloadTemplate } from "giget";
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { Logger } from "@ecopages/logger";
|
|
8
|
+
import { createLaunchPlan, launchPlanRequiresExistingEntryFile } from "./launch-plan.js";
|
|
9
|
+
const logger = new Logger("[ecopages:cli]", { debug: process.env.ECOPAGES_LOGGER_DEBUG === "true" });
|
|
10
|
+
const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
11
|
+
function runLaunchPlan(launchPlan) {
|
|
12
|
+
if (Object.keys(launchPlan.envOverrides).length > 0) {
|
|
13
|
+
logger.debug(`Environment overrides: ${JSON.stringify(launchPlan.envOverrides)}`);
|
|
14
|
+
}
|
|
15
|
+
logger.debug(`Runtime: ${launchPlan.runtime}`);
|
|
16
|
+
logger.debug(`Running: ${launchPlan.command} ${launchPlan.commandArgs.join(" ")}`);
|
|
17
|
+
const child = spawn(launchPlan.command, launchPlan.commandArgs, {
|
|
18
|
+
stdio: "inherit",
|
|
19
|
+
env: launchPlan.env
|
|
20
|
+
});
|
|
21
|
+
child.on("error", (error) => {
|
|
22
|
+
if (error && error.code === "ENOENT") {
|
|
23
|
+
const hint = launchPlan.runtime === "bun" ? "Install Bun from https://bun.sh to continue." : "Reinstall ecopages and its dependencies so the packaged tsx runtime is available for Node.js launches.";
|
|
24
|
+
logger.error(`Command not found: ${launchPlan.command}. ${hint}`);
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
logger.error(`Failed to run command: ${error.message}`);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
});
|
|
30
|
+
child.on("exit", (code) => {
|
|
31
|
+
process.exit(code || 0);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async function runEntryCommand(args, options = {}, entryFile = "app.ts") {
|
|
35
|
+
let launchPlan;
|
|
36
|
+
try {
|
|
37
|
+
launchPlan = await createLaunchPlan(args, options, entryFile);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
40
|
+
logger.error(message);
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
if (launchPlanRequiresExistingEntryFile(launchPlan) && !existsSync(entryFile)) {
|
|
44
|
+
logger.error(`Error: Entry file "${entryFile}" not found in the current directory.`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
runLaunchPlan(launchPlan);
|
|
48
|
+
}
|
|
49
|
+
const serverArgs = {
|
|
50
|
+
entry: {
|
|
51
|
+
type: "positional",
|
|
52
|
+
description: "Entry file",
|
|
53
|
+
default: "app.ts"
|
|
54
|
+
},
|
|
55
|
+
port: {
|
|
56
|
+
type: "string",
|
|
57
|
+
alias: ["p"],
|
|
58
|
+
description: "Override ECOPAGES_PORT"
|
|
59
|
+
},
|
|
60
|
+
hostname: {
|
|
61
|
+
type: "string",
|
|
62
|
+
alias: ["n"],
|
|
63
|
+
description: "Override ECOPAGES_HOSTNAME"
|
|
64
|
+
},
|
|
65
|
+
"base-url": {
|
|
66
|
+
type: "string",
|
|
67
|
+
alias: ["b"],
|
|
68
|
+
description: "Override ECOPAGES_BASE_URL"
|
|
69
|
+
},
|
|
70
|
+
debug: {
|
|
71
|
+
type: "boolean",
|
|
72
|
+
alias: ["d"],
|
|
73
|
+
description: "Enable debug logging (ECOPAGES_LOGGER_DEBUG=true)"
|
|
74
|
+
},
|
|
75
|
+
"react-fast-refresh": {
|
|
76
|
+
type: "boolean",
|
|
77
|
+
alias: ["r"],
|
|
78
|
+
description: "Enable React Fast Refresh for HMR"
|
|
79
|
+
},
|
|
80
|
+
runtime: {
|
|
81
|
+
type: "string",
|
|
82
|
+
description: "Force a specific runtime (bun or node)"
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const initCommand = defineCommand({
|
|
86
|
+
meta: {
|
|
87
|
+
name: "init",
|
|
88
|
+
description: "Initialize a new project from a template"
|
|
89
|
+
},
|
|
90
|
+
args: {
|
|
91
|
+
dir: {
|
|
92
|
+
type: "positional",
|
|
93
|
+
description: "Target directory name",
|
|
94
|
+
required: true
|
|
95
|
+
},
|
|
96
|
+
template: {
|
|
97
|
+
type: "string",
|
|
98
|
+
description: "Template name from ecopages/examples/",
|
|
99
|
+
default: "starter-jsx"
|
|
100
|
+
},
|
|
101
|
+
repo: {
|
|
102
|
+
type: "string",
|
|
103
|
+
description: "GitHub repo (user/repo)",
|
|
104
|
+
default: "ecopages/ecopages"
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
async run({ args }) {
|
|
108
|
+
const { dir, template, repo } = args;
|
|
109
|
+
if (existsSync(dir)) {
|
|
110
|
+
logger.error(`Target directory already exists: ${dir}`);
|
|
111
|
+
process.exit(1);
|
|
112
|
+
}
|
|
113
|
+
logger.info(`Creating target directory '${dir}'...`);
|
|
114
|
+
try {
|
|
115
|
+
await downloadTemplate(`github:${repo}/examples/${template}`, {
|
|
116
|
+
dir,
|
|
117
|
+
force: true
|
|
118
|
+
});
|
|
119
|
+
const pkgPath = join(dir, "package.json");
|
|
120
|
+
if (existsSync(pkgPath)) {
|
|
121
|
+
const projectPkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
|
|
122
|
+
projectPkg.name = dir;
|
|
123
|
+
writeFileSync(pkgPath, JSON.stringify(projectPkg, null, 2) + "\n");
|
|
124
|
+
logger.info(`Renamed project to '${dir}'`);
|
|
125
|
+
}
|
|
126
|
+
logger.info("Project initialized! Run `bun install && bun dev` to start.");
|
|
127
|
+
} catch (err) {
|
|
128
|
+
logger.error(`Failed to fetch template: ${err.message}`);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
const devCommand = defineCommand({
|
|
134
|
+
meta: {
|
|
135
|
+
name: "dev",
|
|
136
|
+
description: "Start the development server"
|
|
137
|
+
},
|
|
138
|
+
args: serverArgs,
|
|
139
|
+
async run({ args }) {
|
|
140
|
+
await runEntryCommand(["--dev"], { ...args, nodeEnv: "development" }, args.entry);
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
const devWatchCommand = defineCommand({
|
|
144
|
+
meta: {
|
|
145
|
+
name: "dev:watch",
|
|
146
|
+
description: "Start the development server with watch mode (restarts on file changes)"
|
|
147
|
+
},
|
|
148
|
+
args: serverArgs,
|
|
149
|
+
async run({ args }) {
|
|
150
|
+
await runEntryCommand(["--dev"], { ...args, watch: true, nodeEnv: "development" }, args.entry);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
const devHotCommand = defineCommand({
|
|
154
|
+
meta: {
|
|
155
|
+
name: "dev:hot",
|
|
156
|
+
description: "Start the development server with hot reload (HMR without restart)"
|
|
157
|
+
},
|
|
158
|
+
args: serverArgs,
|
|
159
|
+
async run({ args }) {
|
|
160
|
+
await runEntryCommand(["--dev"], { ...args, hot: true, nodeEnv: "development" }, args.entry);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
const buildCommand = defineCommand({
|
|
164
|
+
meta: {
|
|
165
|
+
name: "build",
|
|
166
|
+
description: "Build the project for production"
|
|
167
|
+
},
|
|
168
|
+
args: {
|
|
169
|
+
entry: {
|
|
170
|
+
type: "positional",
|
|
171
|
+
description: "Entry file",
|
|
172
|
+
default: "app.ts"
|
|
173
|
+
},
|
|
174
|
+
runtime: {
|
|
175
|
+
type: "string",
|
|
176
|
+
description: "Force a specific runtime (bun or node)"
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
async run({ args }) {
|
|
180
|
+
await runEntryCommand(["--build"], { nodeEnv: "production", ...args }, args.entry);
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
const startCommand = defineCommand({
|
|
184
|
+
meta: {
|
|
185
|
+
name: "start",
|
|
186
|
+
description: "Start the production server"
|
|
187
|
+
},
|
|
188
|
+
args: serverArgs,
|
|
189
|
+
async run({ args }) {
|
|
190
|
+
await runEntryCommand([], { ...args, nodeEnv: "production" }, args.entry);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
const previewCommand = defineCommand({
|
|
194
|
+
meta: {
|
|
195
|
+
name: "preview",
|
|
196
|
+
description: "Preview the production build"
|
|
197
|
+
},
|
|
198
|
+
args: serverArgs,
|
|
199
|
+
async run({ args }) {
|
|
200
|
+
await runEntryCommand(["--preview"], { ...args, nodeEnv: "production" }, args.entry);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
const mainCommand = defineCommand({
|
|
204
|
+
meta: {
|
|
205
|
+
name: "ecopages",
|
|
206
|
+
version: pkg.version,
|
|
207
|
+
description: "Ecopages CLI utilities"
|
|
208
|
+
},
|
|
209
|
+
subCommands: {
|
|
210
|
+
init: initCommand,
|
|
211
|
+
dev: devCommand,
|
|
212
|
+
"dev:watch": devWatchCommand,
|
|
213
|
+
"dev:hot": devHotCommand,
|
|
214
|
+
build: buildCommand,
|
|
215
|
+
start: startCommand,
|
|
216
|
+
preview: previewCommand
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
if (!process.env.VITEST) {
|
|
220
|
+
runMain(mainCommand);
|
|
221
|
+
}
|
|
222
|
+
export {
|
|
223
|
+
mainCommand
|
|
224
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
const require2 = createRequire(import.meta.url);
|
|
4
|
+
function buildEnvOverrides(options) {
|
|
5
|
+
const env = {};
|
|
6
|
+
if (options.port) env.ECOPAGES_PORT = String(options.port);
|
|
7
|
+
if (options.hostname) env.ECOPAGES_HOSTNAME = options.hostname;
|
|
8
|
+
if (options.baseUrl) env.ECOPAGES_BASE_URL = options.baseUrl;
|
|
9
|
+
if (options.debug) env.ECOPAGES_LOGGER_DEBUG = "true";
|
|
10
|
+
if (options.nodeEnv) env.NODE_ENV = options.nodeEnv;
|
|
11
|
+
return env;
|
|
12
|
+
}
|
|
13
|
+
function detectRuntime(options = {}) {
|
|
14
|
+
if (options.runtime === "bun" || options.runtime === "node") {
|
|
15
|
+
return options.runtime;
|
|
16
|
+
}
|
|
17
|
+
const userAgent = process.env.npm_config_user_agent || "";
|
|
18
|
+
if (userAgent.startsWith("bun/")) {
|
|
19
|
+
return "bun";
|
|
20
|
+
}
|
|
21
|
+
if (typeof Bun !== "undefined") {
|
|
22
|
+
return "bun";
|
|
23
|
+
}
|
|
24
|
+
return "node";
|
|
25
|
+
}
|
|
26
|
+
function buildBunArgs(args, options, entryFile, hasConfig) {
|
|
27
|
+
const bunArgs = [];
|
|
28
|
+
if (options.watch) bunArgs.push("--watch");
|
|
29
|
+
if (options.hot) bunArgs.push("--hot");
|
|
30
|
+
bunArgs.push("run");
|
|
31
|
+
if (hasConfig) {
|
|
32
|
+
bunArgs.push("--preload", "./eco.config.js");
|
|
33
|
+
}
|
|
34
|
+
bunArgs.push(entryFile, ...args);
|
|
35
|
+
if (options.reactFastRefresh) {
|
|
36
|
+
bunArgs.push("--react-fast-refresh");
|
|
37
|
+
}
|
|
38
|
+
return bunArgs;
|
|
39
|
+
}
|
|
40
|
+
function buildNodeArgs(args, options, entryFile, hasConfig) {
|
|
41
|
+
const nodeArgs = [];
|
|
42
|
+
if (hasConfig) {
|
|
43
|
+
nodeArgs.push("--import", "./eco.config.js");
|
|
44
|
+
}
|
|
45
|
+
nodeArgs.push(entryFile, ...args);
|
|
46
|
+
if (options.reactFastRefresh) {
|
|
47
|
+
nodeArgs.push("--react-fast-refresh");
|
|
48
|
+
}
|
|
49
|
+
return nodeArgs;
|
|
50
|
+
}
|
|
51
|
+
function resolveTsxCliPath() {
|
|
52
|
+
try {
|
|
53
|
+
return require2.resolve("tsx/cli");
|
|
54
|
+
} catch {
|
|
55
|
+
throw new Error(
|
|
56
|
+
"Unable to resolve the packaged tsx runtime required for Node.js launches. Reinstall ecopages and its dependencies, or use the Bun runtime instead."
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
async function createLaunchPlan(args, options = {}, entryFile = "app.ts") {
|
|
61
|
+
const hasConfig = existsSync("eco.config.ts");
|
|
62
|
+
const envOverrides = buildEnvOverrides(options);
|
|
63
|
+
const runtime = detectRuntime(options);
|
|
64
|
+
const env = { ...process.env, ...envOverrides };
|
|
65
|
+
if (runtime === "node") {
|
|
66
|
+
const tsxCliPath = resolveTsxCliPath();
|
|
67
|
+
return {
|
|
68
|
+
runtime,
|
|
69
|
+
executionStrategy: "direct-runtime",
|
|
70
|
+
command: process.execPath,
|
|
71
|
+
commandArgs: [tsxCliPath, ...buildNodeArgs(args, options, entryFile, hasConfig)],
|
|
72
|
+
envOverrides,
|
|
73
|
+
env
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
runtime,
|
|
78
|
+
executionStrategy: "direct-runtime",
|
|
79
|
+
command: "bun",
|
|
80
|
+
commandArgs: buildBunArgs(args, options, entryFile, hasConfig),
|
|
81
|
+
envOverrides,
|
|
82
|
+
env
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function launchPlanRequiresExistingEntryFile(launchPlan) {
|
|
86
|
+
return launchPlan.executionStrategy !== "config-only-bootstrap";
|
|
87
|
+
}
|
|
88
|
+
export {
|
|
89
|
+
buildBunArgs,
|
|
90
|
+
buildEnvOverrides,
|
|
91
|
+
buildNodeArgs,
|
|
92
|
+
createLaunchPlan,
|
|
93
|
+
detectRuntime,
|
|
94
|
+
launchPlanRequiresExistingEntryFile,
|
|
95
|
+
resolveTsxCliPath
|
|
96
|
+
};
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default View Transition CSS for EcoPages
|
|
3
|
+
*
|
|
4
|
+
* Import this file in your CSS:
|
|
5
|
+
* @import 'ecopages/css/view-transitions.css';
|
|
6
|
+
*
|
|
7
|
+
* Works with both @ecopages/browser-router and @ecopages/react-router.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/* Disable root animation to prevent full page flash during transitions */
|
|
11
|
+
::view-transition-old(root),
|
|
12
|
+
::view-transition-new(root) {
|
|
13
|
+
animation: none;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Shared element transitions animate position/size smoothly */
|
|
17
|
+
::view-transition-group(*) {
|
|
18
|
+
animation-duration: 180ms;
|
|
19
|
+
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/* Prevent transitioning elements from affecting layout of non-transitioning elements */
|
|
23
|
+
::view-transition-image-pair(*) {
|
|
24
|
+
isolation: isolate;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/* Respect reduced motion preference */
|
|
28
|
+
@media (prefers-reduced-motion: reduce) {
|
|
29
|
+
::view-transition-group(*),
|
|
30
|
+
::view-transition-old(*),
|
|
31
|
+
::view-transition-new(*) {
|
|
32
|
+
animation: none !important;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@keyframes eco-fade-out {
|
|
37
|
+
from {
|
|
38
|
+
opacity: 1;
|
|
39
|
+
}
|
|
40
|
+
to {
|
|
41
|
+
opacity: 0;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@keyframes eco-fade-in {
|
|
46
|
+
from {
|
|
47
|
+
opacity: 0;
|
|
48
|
+
}
|
|
49
|
+
to {
|
|
50
|
+
opacity: 1;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Slide transition for elements with view-transition-name: eco-slide */
|
|
55
|
+
::view-transition-image-pair(eco-slide) {
|
|
56
|
+
isolation: isolate;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
::view-transition-old(eco-slide),
|
|
60
|
+
::view-transition-new(eco-slide) {
|
|
61
|
+
animation-duration: 180ms;
|
|
62
|
+
animation-timing-function: ease-out;
|
|
63
|
+
mix-blend-mode: normal;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
::view-transition-old(eco-slide) {
|
|
67
|
+
animation-name: eco-slide-out;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
::view-transition-new(eco-slide) {
|
|
71
|
+
animation-name: eco-slide-in;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
@keyframes eco-slide-out {
|
|
75
|
+
from {
|
|
76
|
+
opacity: 1;
|
|
77
|
+
transform: translateX(0);
|
|
78
|
+
}
|
|
79
|
+
to {
|
|
80
|
+
opacity: 0;
|
|
81
|
+
transform: translateX(-30px);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@keyframes eco-slide-in {
|
|
86
|
+
from {
|
|
87
|
+
opacity: 0;
|
|
88
|
+
transform: translateX(30px);
|
|
89
|
+
}
|
|
90
|
+
to {
|
|
91
|
+
opacity: 1;
|
|
92
|
+
transform: translateX(0);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/* Persistent elements should not animate */
|
|
97
|
+
[data-eco-persist] {
|
|
98
|
+
view-transition-name: none;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* Declarative transition attributes */
|
|
102
|
+
[data-eco-transition='slide'] {
|
|
103
|
+
view-transition-name: eco-slide;
|
|
104
|
+
}
|
|
105
|
+
[data-eco-transition='fade'] {
|
|
106
|
+
view-transition-name: eco-fade;
|
|
107
|
+
}
|
|
108
|
+
[data-eco-transition='zoom'] {
|
|
109
|
+
view-transition-name: eco-zoom;
|
|
110
|
+
}
|
|
111
|
+
[data-eco-transition='slide-up'] {
|
|
112
|
+
view-transition-name: eco-slide-up;
|
|
113
|
+
}
|
|
114
|
+
[data-eco-transition='slide-down'] {
|
|
115
|
+
view-transition-name: eco-slide-down;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* FADE */
|
|
119
|
+
::view-transition-old(eco-fade) {
|
|
120
|
+
animation: eco-fade-out 180ms ease-out both;
|
|
121
|
+
}
|
|
122
|
+
::view-transition-new(eco-fade) {
|
|
123
|
+
animation: eco-fade-in 180ms ease-out both;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* ZOOM */
|
|
127
|
+
::view-transition-image-pair(eco-zoom) {
|
|
128
|
+
isolation: isolate;
|
|
129
|
+
}
|
|
130
|
+
::view-transition-old(eco-zoom) {
|
|
131
|
+
animation: eco-zoom-out 180ms ease-in both;
|
|
132
|
+
}
|
|
133
|
+
::view-transition-new(eco-zoom) {
|
|
134
|
+
animation: eco-zoom-in 180ms ease-out both;
|
|
135
|
+
}
|
|
136
|
+
@keyframes eco-zoom-out {
|
|
137
|
+
from {
|
|
138
|
+
opacity: 1;
|
|
139
|
+
transform: scale(1);
|
|
140
|
+
}
|
|
141
|
+
to {
|
|
142
|
+
opacity: 0;
|
|
143
|
+
transform: scale(0.9);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
@keyframes eco-zoom-in {
|
|
147
|
+
from {
|
|
148
|
+
opacity: 0;
|
|
149
|
+
transform: scale(0.9);
|
|
150
|
+
}
|
|
151
|
+
to {
|
|
152
|
+
opacity: 1;
|
|
153
|
+
transform: scale(1);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* SLIDE UP */
|
|
158
|
+
::view-transition-image-pair(eco-slide-up) {
|
|
159
|
+
isolation: isolate;
|
|
160
|
+
}
|
|
161
|
+
::view-transition-old(eco-slide-up) {
|
|
162
|
+
animation: eco-slide-up-out 180ms ease-in both;
|
|
163
|
+
}
|
|
164
|
+
::view-transition-new(eco-slide-up) {
|
|
165
|
+
animation: eco-slide-up-in 180ms ease-out both;
|
|
166
|
+
}
|
|
167
|
+
@keyframes eco-slide-up-out {
|
|
168
|
+
from {
|
|
169
|
+
opacity: 1;
|
|
170
|
+
transform: translateY(0);
|
|
171
|
+
}
|
|
172
|
+
to {
|
|
173
|
+
opacity: 0;
|
|
174
|
+
transform: translateY(-30px);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
@keyframes eco-slide-up-in {
|
|
178
|
+
from {
|
|
179
|
+
opacity: 0;
|
|
180
|
+
transform: translateY(30px);
|
|
181
|
+
}
|
|
182
|
+
to {
|
|
183
|
+
opacity: 1;
|
|
184
|
+
transform: translateY(0);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/* SLIDE DOWN */
|
|
189
|
+
::view-transition-image-pair(eco-slide-down) {
|
|
190
|
+
isolation: isolate;
|
|
191
|
+
}
|
|
192
|
+
::view-transition-old(eco-slide-down) {
|
|
193
|
+
animation: eco-slide-down-out 180ms ease-in both;
|
|
194
|
+
}
|
|
195
|
+
::view-transition-new(eco-slide-down) {
|
|
196
|
+
animation: eco-slide-down-in 180ms ease-out both;
|
|
197
|
+
}
|
|
198
|
+
@keyframes eco-slide-down-out {
|
|
199
|
+
from {
|
|
200
|
+
opacity: 1;
|
|
201
|
+
transform: translateY(0);
|
|
202
|
+
}
|
|
203
|
+
to {
|
|
204
|
+
opacity: 0;
|
|
205
|
+
transform: translateY(30px);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
@keyframes eco-slide-down-in {
|
|
209
|
+
from {
|
|
210
|
+
opacity: 0;
|
|
211
|
+
transform: translateY(-30px);
|
|
212
|
+
}
|
|
213
|
+
to {
|
|
214
|
+
opacity: 1;
|
|
215
|
+
transform: translateY(0);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ecopages",
|
|
3
|
+
"version": "0.2.0-alpha.30",
|
|
4
|
+
"description": "CLI utilities for Ecopages",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Ecopages Team",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/ecopages/ecopages.git",
|
|
11
|
+
"directory": "packages/ecopages"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/ecopages/ecopages#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/ecopages/ecopages/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"ecopages",
|
|
19
|
+
"bun",
|
|
20
|
+
"web-framework",
|
|
21
|
+
"ssr",
|
|
22
|
+
"static-site-generator",
|
|
23
|
+
"react",
|
|
24
|
+
"kitajs",
|
|
25
|
+
"lit",
|
|
26
|
+
"mdx"
|
|
27
|
+
],
|
|
28
|
+
"bin": {
|
|
29
|
+
"ecopages": "bin/cli.js"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@ecopages/core": "0.2.0-alpha.30",
|
|
33
|
+
"@ecopages/logger": "^0.2.2",
|
|
34
|
+
"citty": "^0.1.6",
|
|
35
|
+
"giget": "^2.0.0",
|
|
36
|
+
"tsx": "^4.21.0"
|
|
37
|
+
},
|
|
38
|
+
"peerDependencies": {
|
|
39
|
+
"bun-types": "*",
|
|
40
|
+
"typescript": "^5"
|
|
41
|
+
}
|
|
42
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ecopages",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.30",
|
|
4
4
|
"description": "CLI utilities for Ecopages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"files": [
|
|
32
32
|
"bin/",
|
|
33
33
|
"css/",
|
|
34
|
+
"dist/",
|
|
34
35
|
"README.md"
|
|
35
36
|
],
|
|
36
37
|
"dependencies": {
|