mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 12:57:46 +00:00
Compare commits
88 Commits
vercel-plu
...
@vercel/ru
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c76781fac9 | ||
|
|
451e0b0cfb | ||
|
|
cf477d45b2 | ||
|
|
cdd2d69e07 | ||
|
|
43f1f8b257 | ||
|
|
34055e3599 | ||
|
|
26abb0a85a | ||
|
|
a1e337e0dd | ||
|
|
b72ead480f | ||
|
|
77cf68105f | ||
|
|
d800f55dfa | ||
|
|
9dde99f19e | ||
|
|
fae7a083fc | ||
|
|
cbd651d6ee | ||
|
|
6077a706d1 | ||
|
|
cedc82dd9e | ||
|
|
b420006401 | ||
|
|
8ba604e8fc | ||
|
|
fadeee4568 | ||
|
|
2b15ba7f46 | ||
|
|
4cdfd0e58c | ||
|
|
b3ccb5f3ef | ||
|
|
584acc43b7 | ||
|
|
f64be93b94 | ||
|
|
9abd31769e | ||
|
|
09e3b35e74 | ||
|
|
8aa9a0ea05 | ||
|
|
b2d0ed74c6 | ||
|
|
aef936af0f | ||
|
|
501be936c0 | ||
|
|
7eba282af5 | ||
|
|
cf3e4bd726 | ||
|
|
ee5361b00e | ||
|
|
bd929dd5c5 | ||
|
|
4ee064bb61 | ||
|
|
312a2090a6 | ||
|
|
a82f117217 | ||
|
|
e908378486 | ||
|
|
8cda5263eb | ||
|
|
a24fd64bce | ||
|
|
0c515a46d5 | ||
|
|
f19690dc32 | ||
|
|
6b2a1c3866 | ||
|
|
1e54d606d7 | ||
|
|
c4ab0ebe9c | ||
|
|
321f1232a1 | ||
|
|
8a8203e149 | ||
|
|
33527165e7 | ||
|
|
db10383bc8 | ||
|
|
56960e506e | ||
|
|
a17f3a96ec | ||
|
|
9ff86a896c | ||
|
|
6ccb4354f9 | ||
|
|
82ba932447 | ||
|
|
b995618afb | ||
|
|
c897b24417 | ||
|
|
e64b2e1993 | ||
|
|
9358a5469e | ||
|
|
2a24210b7d | ||
|
|
2644a59984 | ||
|
|
4eeb8c298c | ||
|
|
0351f02dff | ||
|
|
0d7fa2f912 | ||
|
|
3b646880e7 | ||
|
|
350a0e5f36 | ||
|
|
5c21d400bd | ||
|
|
04029013a6 | ||
|
|
c65e7fa883 | ||
|
|
27b68be93f | ||
|
|
99fa729966 | ||
|
|
2bb3da80e0 | ||
|
|
b852f34a27 | ||
|
|
ce8e6e3806 | ||
|
|
983946650e | ||
|
|
59e4572e76 | ||
|
|
5c297122cb | ||
|
|
28f3bf9ef6 | ||
|
|
a936e92b8b | ||
|
|
ab1decf79d | ||
|
|
34408a7902 | ||
|
|
dc2d814d0f | ||
|
|
2402db92eb | ||
|
|
a1787c740d | ||
|
|
17fd88e044 | ||
|
|
03a8fbd3a7 | ||
|
|
8d37c1045f | ||
|
|
30c433d248 | ||
|
|
d89a79601c |
@@ -1,7 +1,12 @@
|
||||
node_modules
|
||||
dist
|
||||
examples
|
||||
|
||||
packages/node/src/bridge.ts
|
||||
|
||||
packages/*/test/fixtures
|
||||
|
||||
# cli
|
||||
packages/cli/@types
|
||||
packages/cli/download
|
||||
packages/cli/dist
|
||||
@@ -9,9 +14,24 @@ packages/cli/test/dev/fixtures
|
||||
packages/cli/bin
|
||||
packages/cli/link
|
||||
packages/cli/src/util/dev/templates/*.ts
|
||||
|
||||
# client
|
||||
packages/client/tests/fixtures
|
||||
packages/client/lib
|
||||
packages/node/src/bridge.ts
|
||||
|
||||
# node-bridge
|
||||
packages/node-bridge/bridge.js
|
||||
packages/node-bridge/launcher.js
|
||||
packages/node-bridge/helpers.js
|
||||
packages/node-bridge/source-map-support.js
|
||||
|
||||
# middleware
|
||||
packages/middleware/src/entries.js
|
||||
|
||||
# static-build
|
||||
packages/static-build/test/fixtures
|
||||
packages/static-build/test/build-fixtures
|
||||
packages/static-build/test/cache-fixtures
|
||||
|
||||
# redwood
|
||||
packages/redwood/test/fixtures
|
||||
|
||||
10
.github/CONTRIBUTING.md
vendored
10
.github/CONTRIBUTING.md
vendored
@@ -2,11 +2,11 @@
|
||||
|
||||
When contributing to this repository, please first discuss the change you wish to make via [GitHub Discussions](https://github.com/vercel/vercel/discussions/new) with the owners of this repository before submitting a Pull Request.
|
||||
|
||||
Please read our [code of conduct](CODE_OF_CONDUCT.md) and follow it in all your interactions with the project.
|
||||
Please read our [Code of Conduct](CODE_OF_CONDUCT.md) and follow it in all your interactions with the project.
|
||||
|
||||
## Local development
|
||||
|
||||
This project is configured in a monorepo pattern where one repo contains multiple npm packages. Dependencies are installed and managed with `yarn`, not `npm` CLI.
|
||||
This project is configured in a monorepo, where one repository contains multiple npm packages. Dependencies are installed and managed with `yarn`, not `npm` CLI.
|
||||
|
||||
To get started, execute the following:
|
||||
|
||||
@@ -16,17 +16,17 @@ yarn install
|
||||
yarn bootstrap
|
||||
yarn build
|
||||
yarn lint
|
||||
yarn test
|
||||
yarn test-unit
|
||||
```
|
||||
|
||||
Make sure all the tests pass before making changes.
|
||||
|
||||
## Verifying your change
|
||||
|
||||
Once you are done with your changes (we even suggest doing it along the way ), make sure all the test still run by running
|
||||
Once you are done with your changes (we even suggest doing it along the way), make sure all the test still pass by running:
|
||||
|
||||
```
|
||||
yarn build && yarn test
|
||||
yarn test-unit
|
||||
```
|
||||
|
||||
from the root of the project.
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,5 +27,4 @@ test/lib/deployment/failed-page.txt
|
||||
/public
|
||||
__pycache__
|
||||
.vercel
|
||||
.output
|
||||
.turbo
|
||||
|
||||
@@ -9,7 +9,6 @@ A Runtime is an npm module that implements the following interface:
|
||||
interface Runtime {
|
||||
version: number;
|
||||
build: (options: BuildOptions) => Promise<BuildResult>;
|
||||
analyze?: (options: AnalyzeOptions) => Promise<string>;
|
||||
prepareCache?: (options: PrepareCacheOptions) => Promise<CacheOutputs>;
|
||||
shouldServe?: (options: ShouldServeOptions) => Promise<boolean>;
|
||||
startDevServer?: (
|
||||
@@ -72,26 +71,6 @@ export async function build(options: BuildOptions) {
|
||||
}
|
||||
```
|
||||
|
||||
### `analyze()`
|
||||
|
||||
An **optional** exported function that returns a unique fingerprint used for the
|
||||
purpose of [build
|
||||
de-duplication](https://vercel.com/docs/v2/platform/deployments#deduplication).
|
||||
If the `analyze()` function is not supplied, then a random fingerprint is
|
||||
assigned to each build.
|
||||
|
||||
**Example:**
|
||||
|
||||
```typescript
|
||||
import { AnalyzeOptions } from '@vercel/build-utils';
|
||||
|
||||
export async function analyze(options: AnalyzeOptions) {
|
||||
// Do calculations to generate a fingerprint based off the source code here…
|
||||
|
||||
return 'fingerprint goes here';
|
||||
}
|
||||
```
|
||||
|
||||
### `prepareCache()`
|
||||
|
||||
An **optional** exported function that is executed after [`build()`](#build) is
|
||||
|
||||
36
README.md
36
README.md
@@ -3,13 +3,21 @@
|
||||
<img src="https://assets.vercel.com/image/upload/v1588805858/repositories/vercel/logo.png" height="96">
|
||||
<h3 align="center">Vercel</h3>
|
||||
</a>
|
||||
<p align="center">Develop. Preview. Ship.</p>
|
||||
</p>
|
||||
|
||||
[](https://github.com/vercel/vercel/actions/workflows/test-unit.yml)
|
||||
[](https://github.com/vercel/vercel/discussions)
|
||||
<p align="center">
|
||||
Develop. Preview. Ship.
|
||||
</p>
|
||||
|
||||
## Usage
|
||||
<p align="center">
|
||||
<a href="https://vercel.com/docs"><strong>Documentation</strong></a> ·
|
||||
<a href="https://vercel.com/changelog"><strong>Changelog</strong></a> ·
|
||||
<a href="https://vercel.com/templates"><strong>Templates</strong></a> ·
|
||||
<a href="https://vercel.com/cli"><strong>CLI</strong></a>
|
||||
</p>
|
||||
<br/>
|
||||
|
||||
## Vercel
|
||||
|
||||
Vercel is a platform for **static sites and frontend frameworks**, built to integrate with your headless content, commerce, or database.
|
||||
|
||||
@@ -17,22 +25,16 @@ We provide a **frictionless developer experience** to take care of the hard thin
|
||||
|
||||
We make it easy for frontend teams to **develop, preview, and ship** delightful user experiences, where performance is the default.
|
||||
|
||||
Get started by [Importing a Git Project](https://vercel.com/new) and use `git push` to deploy. Alternatively, you can [install Vercel CLI](https://vercel.com/cli).
|
||||
## Deploy
|
||||
|
||||
Get started by [importing a project](https://vercel.com/new) or using the [Vercel CLI](https://vercel.com/cli). Then, `git push` to deploy.
|
||||
|
||||
## Documentation
|
||||
|
||||
For details on how to use Vercel, check out our [documentation](https://vercel.com/docs).
|
||||
|
||||
## Caught a Bug?
|
||||
## Contributing
|
||||
|
||||
1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device
|
||||
2. Install dependencies with `yarn install`
|
||||
3. Compile the code: `yarn build`
|
||||
4. Link the package to the global module directory: `cd ./packages/cli && yarn link`
|
||||
5. You can start using `vercel` anywhere inside the command line
|
||||
|
||||
As always, you should use `yarn test-unit` to run the tests and see if your changes have broken anything.
|
||||
|
||||
## How to Create a Release
|
||||
|
||||
If you have write access to this repository, you can read more about how to publish a release [here](https://github.com/vercel/vercel/wiki/Creating-a-Release).
|
||||
- [Code of Conduct](https://github.com/vercel/vercel/blob/main/.github/CODE_OF_CONDUCT.md)
|
||||
- [Contributing Guidelines](https://github.com/vercel/vercel/blob/main/.github/CONTRIBUTING.md)
|
||||
- [MIT License](https://github.com/vercel/vercel/blob/main/LICENSE)
|
||||
|
||||
46
api/_lib/script/build.ts
Normal file
46
api/_lib/script/build.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import fs from 'fs/promises';
|
||||
import { join } from 'path';
|
||||
import { getExampleList } from '../examples/example-list';
|
||||
import { mapOldToNew } from '../examples/map-old-to-new';
|
||||
|
||||
const repoRoot = join(__dirname, '..', '..', '..');
|
||||
const pubDir = join(repoRoot, 'public');
|
||||
|
||||
async function main() {
|
||||
console.log(`Building static frontend ${repoRoot}...`);
|
||||
|
||||
await fs.rm(pubDir, { recursive: true, force: true });
|
||||
await fs.mkdir(pubDir);
|
||||
|
||||
const examples = await getExampleList();
|
||||
const pathListAll = join(pubDir, 'list-all.json');
|
||||
await fs.writeFile(pathListAll, JSON.stringify(examples));
|
||||
|
||||
const exampleDirs = await fs.readdir(join(repoRoot, 'examples'), {
|
||||
withFileTypes: true,
|
||||
});
|
||||
|
||||
const existingExamples = exampleDirs
|
||||
.filter(dir => dir.isDirectory())
|
||||
.map(dir => ({
|
||||
name: dir.name,
|
||||
visible: true,
|
||||
suggestions: [],
|
||||
}));
|
||||
|
||||
const oldExamples = Object.keys(mapOldToNew).map(key => ({
|
||||
name: key,
|
||||
visible: false,
|
||||
suggestions: mapOldToNew[key],
|
||||
}));
|
||||
|
||||
const pathList = join(pubDir, 'list.json');
|
||||
await fs.writeFile(
|
||||
pathList,
|
||||
JSON.stringify([...existingExamples, ...oldExamples])
|
||||
);
|
||||
|
||||
console.log('Completed building static frontend.');
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
@@ -1,10 +0,0 @@
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
import { getExampleList } from '../_lib/examples/example-list';
|
||||
import { withApiHandler } from '../_lib/util/with-api-handler';
|
||||
|
||||
export default withApiHandler(async function (
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
) {
|
||||
res.status(200).json(await getExampleList());
|
||||
});
|
||||
@@ -1,27 +0,0 @@
|
||||
import { extract } from '../_lib/examples/extract';
|
||||
import { summary } from '../_lib/examples/summary';
|
||||
import { VercelRequest, VercelResponse } from '@vercel/node';
|
||||
import { mapOldToNew } from '../_lib/examples/map-old-to-new';
|
||||
import { withApiHandler } from '../_lib/util/with-api-handler';
|
||||
|
||||
export default withApiHandler(async function (
|
||||
req: VercelRequest,
|
||||
res: VercelResponse
|
||||
) {
|
||||
await extract('https://github.com/vercel/vercel/archive/main.zip', '/tmp');
|
||||
const exampleList = summary('/tmp/vercel-main/examples');
|
||||
|
||||
const existingExamples = Array.from(exampleList).map(key => ({
|
||||
name: key,
|
||||
visible: true,
|
||||
suggestions: [],
|
||||
}));
|
||||
|
||||
const oldExamples = Object.keys(mapOldToNew).map(key => ({
|
||||
name: key,
|
||||
visible: false,
|
||||
suggestions: mapOldToNew[key],
|
||||
}));
|
||||
|
||||
res.status(200).json([...existingExamples, ...oldExamples]);
|
||||
});
|
||||
50
examples/README.md
vendored
50
examples/README.md
vendored
@@ -1,28 +1,6 @@
|
||||
# Vercel Examples
|
||||
|
||||
This is the public list of examples for **Vercel**.
|
||||
|
||||
All of these ready to deploy examples feature a frontend framework or static site, created with zero configuration using the CLI tools they provide.
|
||||
|
||||
The `+functions` examples feature an `/api` directory as well, highlighting how to use serverless functions on top of a framework, again with zero configuration required.
|
||||
|
||||
## What is Vercel?
|
||||
|
||||
Vercel is a cloud platform for static frontends and serverless functions. It enables developers to host websites and web applications that deploy instantly, scale automatically, and require no supervision.
|
||||
|
||||
## What Does this Repository Contain?
|
||||
|
||||
This repository consists of multiple examples, created for use with the [Vercel](https://vercel.com) platform. In addition to this, it also contains:
|
||||
|
||||
- [Code of Conduct](https://github.com/vercel/vercel/blob/main/.github/CODE_OF_CONDUCT.md) - our Code of Conduct, adapted from the [Contributor Covenant](http://contributor-covenant.org)
|
||||
- [Contributing Guidelines](https://github.com/vercel/vercel/blob/main/.github/CONTRIBUTING.md) - a guide on how to contribute to the examples repository
|
||||
- [License](https://github.com/vercel/vercel/blob/main/LICENSE) - the standard MIT license under which these examples are published
|
||||
|
||||
We recommend familiarizing yourself with the above sections, particularly if you are looking to make a contribution.
|
||||
|
||||
## Deploying Examples
|
||||
|
||||
To get started using any of these examples as your own project, [install Vercel](https://vercel.com/download) and use either of the following commands in your terminal:
|
||||
To get started using any of these examples as your own project, [install Vercel](https://vercel.com/cli) and use either of the following commands in your terminal:
|
||||
|
||||
```sh
|
||||
vercel init # Pick an example in the CLI
|
||||
@@ -30,7 +8,7 @@ vercel init <example> # Create a new project from a specific <example>
|
||||
vercel init <example> <name> # Create a new project from a specific <example> with a different folder <name>
|
||||
```
|
||||
|
||||
Deploying your project takes seconds and can be done with **just a single command**:
|
||||
Deploying your project can be done with **a single command**:
|
||||
|
||||
```sh
|
||||
vercel # Deploy your project with the CLI
|
||||
@@ -38,26 +16,6 @@ vercel # Deploy your project with the CLI
|
||||
|
||||
With the `vercel` command, your project will be built and served by Vercel, providing you with a URL that can be shared immediately.
|
||||
|
||||
## New Examples
|
||||
|
||||
We are continuously improving our examples based on best practices and feedback from the community. As a result, it is possible that example names will change and on occasion deprecated in favor of an improved implementation.
|
||||
|
||||
For example, the previous `nodejs` example showed a static frontend with a Node.js API. This is illustrated in the `svelte` example. Below is a table that lists some of the most popular previous examples and the equivalent replacement:
|
||||
|
||||
| Previous Example | New Example |
|
||||
| ----------------- | ---------------------------------------------------------------------------------------- |
|
||||
| **monorepo** | [gatsby-functions](https://github.com/vercel/vercel/tree/main/examples/gatsby) |
|
||||
| **nodejs** | [svelte-functions](https://github.com/vercel/vercel/tree/main/examples/svelte) |
|
||||
| **nextjs-static** | [nextjs](https://github.com/vercel/vercel/tree/main/examples/nextjs) |
|
||||
| **vanilla-go** | [create-react-app](https://github.com/vercel/vercel/tree/main/examples/create-react-app) |
|
||||
| **typescript** | [gatsby-functions](https://github.com/vercel/vercel/tree/main/examples/gatsby) |
|
||||
|
||||
## Migrating and Upgrading
|
||||
|
||||
If you have an existing project you would like to deploy with Vercel, we recommend reading our guide on [migrating to Vercel and zero configuration](https://vercel.com/guides/migrate-to-vercel). By combining the guide with this repository, you will quickly be able to understand how to deploy your application.
|
||||
|
||||
If you would like to upgrade a project to take advantage of zero configuration, you may find the [upgrade guide](https://vercel.com/guides/upgrade-to-zero-configuration) useful. The upgrade guide covers how to remove configuration from existing projects along with how to use the `/api` directory.
|
||||
|
||||
## How to Contribute
|
||||
|
||||
Contributing examples should be an enjoyable experience, as such we have created a set of [contributing guidelines](https://github.com/vercel/vercel/blob/main/.github/CONTRIBUTING.md) to help you do so.
|
||||
@@ -74,10 +32,6 @@ An issue can be raised by clicking the 'Issues' tab at the top of the repository
|
||||
|
||||
When submitting an issue, please thoroughly and concisely describe the problem you are experiencing so that we may easily understand and resolve the issue in a timely manner.
|
||||
|
||||
## License
|
||||
|
||||
This repository is an open source project. See the [License](https://github.com/vercel/vercel/blob/main/LICENSE).
|
||||
|
||||
## Get In Touch
|
||||
|
||||
If you have any questions that are not covered by raising an issue then please get in touch with us on [GitHub Discussions](https://github.com/vercel/vercel/discussions). There you will find both members of the community and staff who are happy to help answer questions on anything Vercel related.
|
||||
|
||||
1
examples/angular/.gitignore
vendored
1
examples/angular/.gitignore
vendored
@@ -41,4 +41,3 @@ testem.log
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
.vercel
|
||||
.output
|
||||
|
||||
20
examples/eleventy/LICENSE.md
Normal file
20
examples/eleventy/LICENSE.md
Normal file
@@ -0,0 +1,20 @@
|
||||
MIT License
|
||||
Copyright (c) 2022 Zach Leatherman @zachleat
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,5 +1,19 @@
|
||||
{
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/11ty/eleventy-base-blog.git"
|
||||
},
|
||||
"author": {
|
||||
"name": "Zach Leatherman",
|
||||
"email": "zachleatherman@gmail.com",
|
||||
"url": "https://zachleat.com/"
|
||||
},
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/11ty/eleventy-base-blog/issues"
|
||||
},
|
||||
"homepage": "https://github.com/11ty/eleventy-base-blog#readme",
|
||||
"scripts": {
|
||||
"build": "eleventy",
|
||||
"watch": "eleventy --watch",
|
||||
|
||||
19
examples/hugo/.gitignore
vendored
19
examples/hugo/.gitignore
vendored
@@ -1,2 +1,19 @@
|
||||
# Hugo
|
||||
public
|
||||
.hugo_build.lock
|
||||
|
||||
## OS Files
|
||||
# Windows
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
Desktop.ini
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# Env Variables
|
||||
.env
|
||||
.env.build
|
||||
.env.build
|
||||
|
||||
.vercel
|
||||
@@ -1,4 +1,39 @@
|
||||
baseURL = "http://example.org/"
|
||||
languageCode = "en-us"
|
||||
title = "My New Hugo Site"
|
||||
theme = "ananke"
|
||||
baseURL = "https://hugo-template.vercel.app"
|
||||
title = "Hugo Template"
|
||||
theme = "etch"
|
||||
languageCode = "en-US"
|
||||
enableInlineShortcodes = true
|
||||
pygmentsCodeFences = true
|
||||
pygmentsUseClasses = true
|
||||
ignoreErrors = ["error-missing-instagram-accesstoken"]
|
||||
|
||||
[params]
|
||||
description = "A Hugo template, hosted with Vercel."
|
||||
copyright = "Copyright © 2021 Your Name"
|
||||
dark = "auto"
|
||||
highlight = true
|
||||
|
||||
[menu]
|
||||
[[menu.main]]
|
||||
identifier = "posts"
|
||||
name = "posts"
|
||||
title = "posts"
|
||||
url = "/"
|
||||
weight = 10
|
||||
|
||||
[[menu.main]]
|
||||
identifier = "about"
|
||||
name = "about"
|
||||
title = "about"
|
||||
url = "/about/"
|
||||
weight = 20
|
||||
|
||||
[permalinks]
|
||||
posts = "/:title/"
|
||||
|
||||
[markup.goldmark.renderer]
|
||||
# Allow HTML in Markdown
|
||||
unsafe = true
|
||||
|
||||
[markup.tableOfContents]
|
||||
ordered = true
|
||||
|
||||
5
examples/hugo/content/_index.md
Normal file
5
examples/hugo/content/_index.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: 'Home'
|
||||
---
|
||||
|
||||
This is some info about me.
|
||||
21
examples/hugo/content/about/index.md
Normal file
21
examples/hugo/content/about/index.md
Normal file
@@ -0,0 +1,21 @@
|
||||
+++
|
||||
title = "About"
|
||||
+++
|
||||
|
||||
Written in Go, Hugo is an open source static site generator available under the [Apache Licence 2.0.](https://github.com/gohugoio/hugo/blob/master/LICENSE) Hugo supports TOML, YAML and JSON data file types, Markdown and HTML content files and uses shortcodes to add rich content. Other notable features are taxonomies, multilingual mode, image processing, custom output formats, HTML/CSS/JS minification and support for Sass SCSS workflows.
|
||||
|
||||
Hugo makes use of a variety of open source projects including:
|
||||
|
||||
- https://github.com/yuin/goldmark
|
||||
- https://github.com/alecthomas/chroma
|
||||
- https://github.com/muesli/smartcrop
|
||||
- https://github.com/spf13/cobra
|
||||
- https://github.com/spf13/viper
|
||||
|
||||
Hugo is ideal for blogs, corporate websites, creative portfolios, online magazines, single page applications or even a website with thousands of pages.
|
||||
|
||||
Hugo is for people who want to hand code their own website without worrying about setting up complicated runtimes, dependencies and databases.
|
||||
|
||||
Websites built with Hugo are extremelly fast, secure and can be deployed anywhere including, AWS, GitHub Pages, Heroku, Netlify and any other hosting provider.
|
||||
|
||||
Learn more and contribute on [GitHub](https://github.com/gohugoio).
|
||||
50
examples/hugo/content/posts/emoji-support.md
Normal file
50
examples/hugo/content/posts/emoji-support.md
Normal file
@@ -0,0 +1,50 @@
|
||||
+++
|
||||
author = "Hugo Authors"
|
||||
title = "Emoji Support"
|
||||
date = "2019-03-05"
|
||||
description = "Guide to emoji usage in Hugo"
|
||||
tags = [
|
||||
"emoji",
|
||||
]
|
||||
+++
|
||||
|
||||
Emoji can be enabled in a Hugo project in a number of ways.
|
||||
|
||||
<!--more-->
|
||||
|
||||
The [`emojify`](https://gohugo.io/functions/emojify/) function can be called directly in templates or [Inline Shortcodes](https://gohugo.io/templates/shortcode-templates/#inline-shortcodes).
|
||||
|
||||
To enable emoji globally, set `enableEmoji` to `true` in your site’s [configuration](https://gohugo.io/getting-started/configuration/) and then you can type emoji shorthand codes directly in content files; e.g.
|
||||
|
||||
<p><span class="nowrap"><span class="emojify">🙈</span> <code>:see_no_evil:</code></span> <span class="nowrap"><span class="emojify">🙉</span> <code>:hear_no_evil:</code></span> <span class="nowrap"><span class="emojify">🙊</span> <code>:speak_no_evil:</code></span></p>
|
||||
<br>
|
||||
|
||||
The [Emoji cheat sheet](http://www.emoji-cheat-sheet.com/) is a useful reference for emoji shorthand codes.
|
||||
|
||||
---
|
||||
|
||||
**N.B.** The above steps enable Unicode Standard emoji characters and sequences in Hugo, however the rendering of these glyphs depends on the browser and the platform. To style the emoji you can either use a third party emoji font or a font stack; e.g.
|
||||
|
||||
{{< highlight html >}}
|
||||
.emoji {
|
||||
font-family: Apple Color Emoji,Segoe UI Emoji,NotoColorEmoji,Segoe UI Symbol,Android Emoji,EmojiSymbols;
|
||||
}
|
||||
{{< /highlight >}}
|
||||
|
||||
{{< css.inline >}}
|
||||
|
||||
<style>
|
||||
.emojify {
|
||||
font-family: Apple Color Emoji,Segoe UI Emoji,NotoColorEmoji,Segoe UI Symbol,Android Emoji,EmojiSymbols;
|
||||
font-size: 2rem;
|
||||
vertical-align: middle;
|
||||
}
|
||||
@media screen and (max-width:650px) {
|
||||
.nowrap {
|
||||
display: block;
|
||||
margin: 25px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
{{< /css.inline >}}
|
||||
155
examples/hugo/content/posts/markdown-syntax.md
Normal file
155
examples/hugo/content/posts/markdown-syntax.md
Normal file
@@ -0,0 +1,155 @@
|
||||
+++
|
||||
author = "Hugo Authors"
|
||||
title = "Markdown Syntax Guide"
|
||||
date = "2019-03-11"
|
||||
description = "Sample article showcasing basic Markdown syntax and formatting for HTML elements."
|
||||
tags = [
|
||||
"markdown",
|
||||
"css",
|
||||
"html",
|
||||
"themes",
|
||||
]
|
||||
categories = [
|
||||
"themes",
|
||||
"syntax",
|
||||
]
|
||||
series = ["Themes Guide"]
|
||||
aliases = ["migrate-from-jekyl"]
|
||||
+++
|
||||
|
||||
This article offers a sample of basic Markdown syntax that can be used in Hugo content files, also it shows whether basic HTML elements are decorated with CSS in a Hugo theme.
|
||||
|
||||
<!--more-->
|
||||
|
||||
## Headings
|
||||
|
||||
The following HTML `<h1>`—`<h6>` elements represent six levels of section headings. `<h1>` is the highest section level while `<h6>` is the lowest.
|
||||
|
||||
# H1
|
||||
|
||||
## H2
|
||||
|
||||
### H3
|
||||
|
||||
#### H4
|
||||
|
||||
##### H5
|
||||
|
||||
###### H6
|
||||
|
||||
## Paragraph
|
||||
|
||||
Xerum, quo qui aut unt expliquam qui dolut labo. Aque venitatiusda cum, voluptionse latur sitiae dolessi aut parist aut dollo enim qui voluptate ma dolestendit peritin re plis aut quas inctum laceat est volestemque commosa as cus endigna tectur, offic to cor sequas etum rerum idem sintibus eiur? Quianimin porecus evelectur, cum que nis nust voloribus ratem aut omnimi, sitatur? Quiatem. Nam, omnis sum am facea corem alique molestrunt et eos evelece arcillit ut aut eos eos nus, sin conecerem erum fuga. Ri oditatquam, ad quibus unda veliamenimin cusam et facea ipsamus es exerum sitate dolores editium rerore eost, temped molorro ratiae volorro te reribus dolorer sperchicium faceata tiustia prat.
|
||||
|
||||
Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sapicia is sinveli squiatum, core et que aut hariosam ex eat.
|
||||
|
||||
## Blockquotes
|
||||
|
||||
The blockquote element represents content that is quoted from another source, optionally with a citation which must be within a `footer` or `cite` element, and optionally with in-line changes such as annotations and abbreviations.
|
||||
|
||||
#### Blockquote without attribution
|
||||
|
||||
> Tiam, ad mint andaepu dandae nostion secatur sequo quae.
|
||||
> **Note** that you can use _Markdown syntax_ within a blockquote.
|
||||
|
||||
#### Blockquote with attribution
|
||||
|
||||
> Don't communicate by sharing memory, share memory by communicating.</p>
|
||||
> — <cite>Rob Pike[^1]</cite>
|
||||
|
||||
[^1]: The above quote is excerpted from Rob Pike's [talk](https://www.youtube.com/watch?v=PAAkCSZUG1c) during Gopherfest, November 18, 2015.
|
||||
|
||||
## Tables
|
||||
|
||||
Tables aren't part of the core Markdown spec, but Hugo supports supports them out-of-the-box.
|
||||
|
||||
| Name | Age |
|
||||
| ----- | --- |
|
||||
| Bob | 27 |
|
||||
| Alice | 23 |
|
||||
|
||||
#### Inline Markdown within tables
|
||||
|
||||
| Inline | Markdown | In | Table |
|
||||
| ------------------------ | -------------------------- | ----------------------------------- | ------ |
|
||||
| _italics_ | **bold** | ~~strikethrough~~ | `code` |
|
||||
|
||||
## Code Blocks
|
||||
|
||||
#### Code block with backticks
|
||||
|
||||
```
|
||||
html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Example HTML5 Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Test</p>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
#### Code block indented with four spaces
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Example HTML5 Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Test</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
#### Code block with Hugo's internal highlight shortcode
|
||||
|
||||
{{< highlight html >}}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Example HTML5 Document</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>Test</p>
|
||||
</body>
|
||||
</html>
|
||||
{{< /highlight >}}
|
||||
|
||||
## List Types
|
||||
|
||||
#### Ordered List
|
||||
|
||||
1. First item
|
||||
2. Second item
|
||||
3. Third item
|
||||
|
||||
#### Unordered List
|
||||
|
||||
- List item
|
||||
- Another item
|
||||
- And another item
|
||||
|
||||
#### Nested list
|
||||
|
||||
- Item
|
||||
|
||||
1. First Sub-item
|
||||
2. Second Sub-item
|
||||
|
||||
## Other Elements — abbr, sub, sup, kbd, mark
|
||||
|
||||
<abbr title="Graphics Interchange Format">GIF</abbr> is a bitmap image format.
|
||||
|
||||
H<sub>2</sub>O
|
||||
|
||||
X<sup>n</sup> + Y<sup>n</sup> = Z<sup>n</sup>
|
||||
|
||||
Press <kbd><kbd>CTRL</kbd>+<kbd>ALT</kbd>+<kbd>Delete</kbd></kbd> to end the session.
|
||||
|
||||
Most <mark>salamanders</mark> are nocturnal, and hunt for insects, worms, and other small creatures.
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
title: 'My First Post'
|
||||
date: 2019-07-18T17:18:05+01:00
|
||||
draft: false
|
||||
---
|
||||
|
||||
# Hugo on Vercel
|
||||
60
examples/hugo/content/posts/placeholder-text.md
Normal file
60
examples/hugo/content/posts/placeholder-text.md
Normal file
@@ -0,0 +1,60 @@
|
||||
+++
|
||||
author = "Hugo Authors"
|
||||
title = "Placeholder Text"
|
||||
date = "2019-03-09"
|
||||
description = "Lorem Ipsum Dolor Si Amet"
|
||||
tags = [
|
||||
"markdown",
|
||||
"text",
|
||||
]
|
||||
+++
|
||||
|
||||
Lorem est tota propiore conpellat pectoribus de
|
||||
pectora summo. <!--more-->Redit teque digerit hominumque toris verebor lumina non cervice
|
||||
subde tollit usus habet Arctonque, furores quas nec ferunt. Quoque montibus nunc
|
||||
caluere tempus inhospita parcite confusaque translucet patri vestro qui optatis
|
||||
lumine cognoscere flos nubis! Fronde ipsamque patulos Dryopen deorum.
|
||||
|
||||
1. Exierant elisi ambit vivere dedere
|
||||
2. Duce pollice
|
||||
3. Eris modo
|
||||
4. Spargitque ferrea quos palude
|
||||
|
||||
Rursus nulli murmur; hastile inridet ut ab gravi sententia! Nomine potitus
|
||||
silentia flumen, sustinet placuit petis in dilapsa erat sunt. Atria
|
||||
tractus malis.
|
||||
|
||||
1. Comas hunc haec pietate fetum procerum dixit
|
||||
2. Post torum vates letum Tiresia
|
||||
3. Flumen querellas
|
||||
4. Arcanaque montibus omnes
|
||||
5. Quidem et
|
||||
|
||||
# Vagus elidunt
|
||||
|
||||
<svg class="canon" xmlns="http://www.w3.org/2000/svg" overflow="visible" viewBox="0 0 496 373" height="373" width="496"><g fill="none"><path stroke="#000" stroke-width=".75" d="M.599 372.348L495.263 1.206M.312.633l494.95 370.853M.312 372.633L247.643.92M248.502.92l246.76 370.566M330.828 123.869V1.134M330.396 1.134L165.104 124.515"></path><path stroke="#ED1C24" stroke-width=".75" d="M275.73 41.616h166.224v249.05H275.73zM54.478 41.616h166.225v249.052H54.478z"></path><path stroke="#000" stroke-width=".75" d="M.479.375h495v372h-495zM247.979.875v372"></path><ellipse cx="498.729" cy="177.625" rx=".75" ry="1.25"></ellipse><ellipse cx="247.229" cy="377.375" rx=".75" ry="1.25"></ellipse></g></svg>
|
||||
|
||||
[The Van de Graaf Canon](https://en.wikipedia.org/wiki/Canons_of_page_construction#Van_de_Graaf_canon)
|
||||
|
||||
## Mane refeci capiebant unda mulcebat
|
||||
|
||||
Victa caducifer, malo vulnere contra
|
||||
dicere aurato, ludit regale, voca! Retorsit colit est profanae esse virescere
|
||||
furit nec; iaculi matertera et visa est, viribus. Divesque creatis, tecta novat collumque vulnus est, parvas. **Faces illo pepulere** tempus adest. Tendit flamma, ab opes virum sustinet, sidus sequendo urbis.
|
||||
|
||||
Iubar proles corpore raptos vero auctor imperium; sed et huic: manus caeli
|
||||
Lelegas tu lux. Verbis obstitit intus oblectamina fixis linguisque ausus sperare
|
||||
Echionides cornuaque tenent clausit possit. Omnia putatur. Praeteritae refert
|
||||
ausus; ferebant e primus lora nutat, vici quae mea ipse. Et iter nil spectatae
|
||||
vulnus haerentia iuste et exercebat, sui et.
|
||||
|
||||
Eurytus Hector, materna ipsumque ut Politen, nec, nate, ignari, vernum cohaesit sequitur. Vel **mitis temploque** vocatus, inque alis, _oculos nomen_ non silvis corpore coniunx ne displicet illa. Crescunt non unus, vidit visa quantum inmiti flumina mortis facto sic: undique a alios vincula sunt iactata abdita! Suspenderat ego fuit tendit: luna, ante urbem
|
||||
Propoetides **parte**.
|
||||
|
||||
{{< css.inline >}}
|
||||
|
||||
<style>
|
||||
.canon { background: white; width: 100%; height: auto;}
|
||||
</style>
|
||||
|
||||
{{< /css.inline >}}
|
||||
42
examples/hugo/content/posts/rich-content.md
Normal file
42
examples/hugo/content/posts/rich-content.md
Normal file
@@ -0,0 +1,42 @@
|
||||
+++
|
||||
author = "Hugo Authors"
|
||||
title = "Rich Content"
|
||||
date = "2019-03-10"
|
||||
description = "A brief description of Hugo Shortcodes"
|
||||
tags = [
|
||||
"shortcodes",
|
||||
"privacy",
|
||||
]
|
||||
+++
|
||||
|
||||
Hugo ships with several [Built-in Shortcodes](https://gohugo.io/content-management/shortcodes/#use-hugo-s-built-in-shortcodes) for rich content, along with a [Privacy Config](https://gohugo.io/about/hugo-and-gdpr/) and a set of Simple Shortcodes that enable static and no-JS versions of various social media embeds.
|
||||
|
||||
## <!--more-->
|
||||
|
||||
## Instagram Simple Shortcode
|
||||
|
||||
{{< instagram_simple BGvuInzyFAe hidecaption >}}
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
## YouTube Privacy Enhanced Shortcode
|
||||
|
||||
{{< youtube ZJthWmvUzzc >}}
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
## Twitter Simple Shortcode
|
||||
|
||||
{{< twitter_simple 1085870671291310081 >}}
|
||||
|
||||
<br>
|
||||
|
||||
---
|
||||
|
||||
## Vimeo Simple Shortcode
|
||||
|
||||
{{< vimeo_simple 48912912 >}}
|
||||
@@ -1,17 +0,0 @@
|
||||
[more]
|
||||
other = "Ещё"
|
||||
|
||||
[allTitle]
|
||||
other = "Все {{.Title }}"
|
||||
|
||||
[recentTitle]
|
||||
other = "Недавние {{.Title }}"
|
||||
|
||||
[readMore]
|
||||
other = "читать дальше"
|
||||
|
||||
[whatsInThis]
|
||||
other = "Содержание {{ .Type }}"
|
||||
|
||||
[related]
|
||||
other = "Схожие"
|
||||
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
!function(n){function t(e){if(r[e])return r[e].exports;var o=r[e]={i:e,l:!1,exports:{}};return n[e].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var r={};t.m=n,t.c=r,t.i=function(n){return n},t.d=function(n,r,e){t.o(n,r)||Object.defineProperty(n,r,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var r=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(r,"a",r),r},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=1)}([function(n,t){},function(n,t,r){"use strict";var e=r(0);!function(n){n&&n.__esModule}(e)}]);
|
||||
1
examples/hugo/themes/etch/.gitignore
vendored
Normal file
1
examples/hugo/themes/etch/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.DS_Store
|
||||
20
examples/hugo/themes/etch/LICENSE
Normal file
20
examples/hugo/themes/etch/LICENSE
Normal file
@@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2020 Lukas Joswiak
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
33
examples/hugo/themes/etch/README.md
Normal file
33
examples/hugo/themes/etch/README.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Etch
|
||||
|
||||
Etch is a simple, responsive theme for [Hugo](https://gohugo.io) with a focus on writing. A live demo is available at https://lukasjoswiak.github.io/etch/.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/LukasJoswiak/etch/master/images/screenshot_small.png" alt="screenshot" width="545px">
|
||||
|
||||
## Features:
|
||||
|
||||
- Homepage with list of posts.
|
||||
- Support for pages.
|
||||
- Responsive design for optimized mobile experience.
|
||||
- Syntax highlighting with customizable theme.
|
||||
- Dark theme which automatically adjusts based on users' setting ([example](https://github.com/LukasJoswiak/etch/wiki/Dark-mode)).
|
||||
- No external dependencies, no JavaScript, no web fonts.
|
||||
- Internationalization friendly: use default English translations or create your own
|
||||
|
||||
## Installation
|
||||
|
||||
To install `etch`, download the repository into the `themes` folder in the root of your site.
|
||||
|
||||
```
|
||||
$ git submodule add https://github.com/LukasJoswiak/etch.git themes/etch
|
||||
```
|
||||
|
||||
Then, use the theme to generate your site.
|
||||
|
||||
```
|
||||
$ hugo server -t etch
|
||||
```
|
||||
|
||||
Use the [sample configuration](https://github.com/LukasJoswiak/etch/wiki/Configuration#sample-configuration) as a starting point. See the [configuration](https://github.com/LukasJoswiak/etch/wiki/Configuration) page for more info.
|
||||
|
||||
Read the [wiki](https://github.com/LukasJoswiak/etch/wiki) to learn about more options.
|
||||
2
examples/hugo/themes/etch/archetypes/default.md
Normal file
2
examples/hugo/themes/etch/archetypes/default.md
Normal file
@@ -0,0 +1,2 @@
|
||||
+++
|
||||
+++
|
||||
53
examples/hugo/themes/etch/assets/css/dark.css
Normal file
53
examples/hugo/themes/etch/assets/css/dark.css
Normal file
@@ -0,0 +1,53 @@
|
||||
{{ if not (eq .Site.Params.dark "on") -}}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
{{ end -}}
|
||||
html {
|
||||
scrollbar-color: #6c6c6c #2e2e2e;
|
||||
}
|
||||
|
||||
body {
|
||||
color: #ebebeb;
|
||||
background: #121212;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
header#banner a {
|
||||
color: #e0e0e0;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
header#banner nav ul li a {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
main#content a {
|
||||
color: #00b1ed;
|
||||
}
|
||||
|
||||
main#content p {
|
||||
color: #f5f5f5;
|
||||
}
|
||||
|
||||
main#content hr {
|
||||
background: #5c5c5c;
|
||||
}
|
||||
|
||||
main#content #toc h4 {
|
||||
color: #d4d4d4;
|
||||
}
|
||||
|
||||
main#content ul#posts small {
|
||||
color: #a7a7a7;
|
||||
}
|
||||
|
||||
main#content ul#posts li a:hover {
|
||||
color: #21c7ff;
|
||||
}
|
||||
|
||||
main#content header#post-header div {
|
||||
color: #a7a7a7;
|
||||
}
|
||||
{{- if not (eq .Site.Params.dark "on") -}}
|
||||
}
|
||||
{{- end -}}
|
||||
281
examples/hugo/themes/etch/assets/css/main.css
Normal file
281
examples/hugo/themes/etch/assets/css/main.css
Normal file
@@ -0,0 +1,281 @@
|
||||
*, *:before, *:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
font-size: 62.5%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 16px;
|
||||
font-size: 1.6rem;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
color: #313a3d;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
padding: 0 16px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
header#banner {
|
||||
margin: 25px 0;
|
||||
}
|
||||
|
||||
header#banner a {
|
||||
color: #313a3d;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
header#banner a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
header#banner h2 {
|
||||
display: inline;
|
||||
font-size: 21px;
|
||||
font-size: 2.1rem;
|
||||
margin: 0 8px 0 0;
|
||||
}
|
||||
|
||||
header#banner nav {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
header#banner nav ul {
|
||||
list-style-type: none;
|
||||
font-size: 1.05em;
|
||||
text-transform: lowercase;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
header#banner nav ul li {
|
||||
display: inline;
|
||||
margin: 0 3px;
|
||||
}
|
||||
|
||||
header#banner nav ul li a {
|
||||
color: #454545;
|
||||
}
|
||||
|
||||
main#content a {
|
||||
color: #007dfa;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
main#content a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
main#content h1,
|
||||
main#content h2,
|
||||
main#content h3,
|
||||
main#content h4,
|
||||
main#content h5,
|
||||
main#content h6 {
|
||||
margin-bottom: 0;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
main#content h3 {
|
||||
font-size: 19px;
|
||||
font-size: 1.9rem;
|
||||
}
|
||||
|
||||
main#content h1 + p,
|
||||
main#content h2 + p,
|
||||
main#content h3 + p,
|
||||
main#content h4 + p,
|
||||
main#content h5 + p,
|
||||
main#content h6 + p {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
main#content p {
|
||||
color: #394548;
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
main#content hr {
|
||||
height: 1px;
|
||||
border: 0;
|
||||
background: #d8d8d8;
|
||||
}
|
||||
|
||||
main#content abbr {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
/* index.html styles */
|
||||
main#content ul#posts {
|
||||
list-style-type: none;
|
||||
font-size: 16px;
|
||||
font-size: 1.6rem;
|
||||
margin-top: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
main#content ul#posts li {
|
||||
margin: 5px 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
main#content ul#posts small {
|
||||
font-size: 0.8em;
|
||||
color: #767676;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
main#content ul#posts li a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
main#content ul#posts li a:hover {
|
||||
color: #369aff;
|
||||
}
|
||||
|
||||
main#content ul#posts li a:hover small {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
/* single.html styles */
|
||||
main#content header#post-header h1 {
|
||||
display: block;
|
||||
font-size: 23px;
|
||||
font-size: 2.3rem;
|
||||
font-weight: 600;
|
||||
line-height: 1.15;
|
||||
}
|
||||
|
||||
main#content header#post-header > div {
|
||||
display: block;
|
||||
font-size: 0.85em;
|
||||
color: #767676;
|
||||
}
|
||||
|
||||
main#content #toc {
|
||||
border: 1px solid #b1b1b1;
|
||||
border-radius: 1px;
|
||||
line-height: 26px;
|
||||
margin: 16px 0;
|
||||
padding: 9px 14px;
|
||||
}
|
||||
|
||||
main#content #toc h4 {
|
||||
font-size: 1.06em;
|
||||
color: #3d3d3d;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
main#content #toc nav#TableOfContents {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
main#content #toc nav#TableOfContents > ul, main#content #toc nav#TableOfContents > ol {
|
||||
margin-left: -40px;
|
||||
}
|
||||
|
||||
main#content #toc ul, main#content #toc ol {
|
||||
font-size: 0.98em;
|
||||
margin: 0;
|
||||
padding: 0 0 0 40px;
|
||||
}
|
||||
|
||||
main#content #toc ul {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
main#content #toc ol {
|
||||
counter-reset: item;
|
||||
}
|
||||
|
||||
main#content #toc ol li {
|
||||
display: block;
|
||||
}
|
||||
|
||||
main#content #toc ol li:before {
|
||||
content: counters(item, ".") ". ";
|
||||
counter-increment: item;
|
||||
}
|
||||
|
||||
main#content img {
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
main#content figure {
|
||||
margin: 16px 0;
|
||||
}
|
||||
|
||||
main#content figure img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
main#content figure figcaption {
|
||||
font-size: 0.92em;
|
||||
font-style: italic;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
margin-top: 6px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
main#content figure figcaption h4 {
|
||||
font-style: normal;
|
||||
display: inline;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
main#content figure figcaption p {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
main#content blockquote {
|
||||
font-style: italic;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 50px;
|
||||
padding-left: 15px;
|
||||
border-left: 3px solid #ccc;
|
||||
}
|
||||
|
||||
main#content code,
|
||||
main#content pre {
|
||||
font-family: 'Menlo', monospace;
|
||||
}
|
||||
|
||||
main#content code {
|
||||
font-size: 0.96em;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
main#content pre {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
font-size: 14px;
|
||||
font-size: 1.4rem;
|
||||
white-space: pre;
|
||||
margin: 20px 0;
|
||||
padding: 1.5rem 1.5rem;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
main#content pre code {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
main#content section.footnotes {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
footer#footer {
|
||||
font-size: 14px;
|
||||
font-size: 1.4rem;
|
||||
font-weight: 400;
|
||||
color: #b3b3b3;
|
||||
margin: 40px 0;
|
||||
}
|
||||
52
examples/hugo/themes/etch/assets/css/min770px.css
Normal file
52
examples/hugo/themes/etch/assets/css/min770px.css
Normal file
@@ -0,0 +1,52 @@
|
||||
@media (min-width: 770px) {
|
||||
body {
|
||||
width: 600px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
main#content hr {
|
||||
width: 108%;
|
||||
margin-left: -3.8%;
|
||||
}
|
||||
|
||||
/* index.html styles */
|
||||
header#banner h2 {
|
||||
font-size: 25px;
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
main#content h3 {
|
||||
font-size: 20px;
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
main#content ul#posts {
|
||||
font-size: 18px;
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
/* single.html styles */
|
||||
main#content header#post-header h1 {
|
||||
font-size: 24px;
|
||||
font-size: 2.4rem;
|
||||
}
|
||||
|
||||
main#content img {
|
||||
max-width: 108%;
|
||||
margin-left: -3.8%;
|
||||
}
|
||||
|
||||
main#content figure {
|
||||
margin-left: -3.8%;
|
||||
}
|
||||
|
||||
main#content figure img {
|
||||
max-width: 108%;
|
||||
}
|
||||
|
||||
main#content pre {
|
||||
width: 108%;
|
||||
margin-left: -3.8%;
|
||||
padding: 1.5rem 2.2rem;
|
||||
}
|
||||
}
|
||||
59
examples/hugo/themes/etch/assets/css/syntax.css
Normal file
59
examples/hugo/themes/etch/assets/css/syntax.css
Normal file
@@ -0,0 +1,59 @@
|
||||
/* Background */ .chroma { color: #f8f8f2; background-color: #272822 }
|
||||
/* Error */ .chroma .err { color: #960050; background-color: #1e0010 }
|
||||
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
|
||||
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; }
|
||||
/* LineHighlight */ .chroma .hl { display: block; width: 100%;background-color: #ffffcc }
|
||||
/* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
|
||||
/* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
|
||||
/* Keyword */ .chroma .k { color: #66d9ef }
|
||||
/* KeywordConstant */ .chroma .kc { color: #66d9ef }
|
||||
/* KeywordDeclaration */ .chroma .kd { color: #66d9ef }
|
||||
/* KeywordNamespace */ .chroma .kn { color: #f92672 }
|
||||
/* KeywordPseudo */ .chroma .kp { color: #66d9ef }
|
||||
/* KeywordReserved */ .chroma .kr { color: #66d9ef }
|
||||
/* KeywordType */ .chroma .kt { color: #66d9ef }
|
||||
/* NameAttribute */ .chroma .na { color: #a6e22e }
|
||||
/* NameClass */ .chroma .nc { color: #a6e22e }
|
||||
/* NameConstant */ .chroma .no { color: #66d9ef }
|
||||
/* NameDecorator */ .chroma .nd { color: #a6e22e }
|
||||
/* NameException */ .chroma .ne { color: #a6e22e }
|
||||
/* NameFunction */ .chroma .nf { color: #a6e22e }
|
||||
/* NameOther */ .chroma .nx { color: #a6e22e }
|
||||
/* NameTag */ .chroma .nt { color: #f92672 }
|
||||
/* Literal */ .chroma .l { color: #ae81ff }
|
||||
/* LiteralDate */ .chroma .ld { color: #e6db74 }
|
||||
/* LiteralString */ .chroma .s { color: #e6db74 }
|
||||
/* LiteralStringAffix */ .chroma .sa { color: #e6db74 }
|
||||
/* LiteralStringBacktick */ .chroma .sb { color: #e6db74 }
|
||||
/* LiteralStringChar */ .chroma .sc { color: #e6db74 }
|
||||
/* LiteralStringDelimiter */ .chroma .dl { color: #e6db74 }
|
||||
/* LiteralStringDoc */ .chroma .sd { color: #e6db74 }
|
||||
/* LiteralStringDouble */ .chroma .s2 { color: #e6db74 }
|
||||
/* LiteralStringEscape */ .chroma .se { color: #ae81ff }
|
||||
/* LiteralStringHeredoc */ .chroma .sh { color: #e6db74 }
|
||||
/* LiteralStringInterpol */ .chroma .si { color: #e6db74 }
|
||||
/* LiteralStringOther */ .chroma .sx { color: #e6db74 }
|
||||
/* LiteralStringRegex */ .chroma .sr { color: #e6db74 }
|
||||
/* LiteralStringSingle */ .chroma .s1 { color: #e6db74 }
|
||||
/* LiteralStringSymbol */ .chroma .ss { color: #e6db74 }
|
||||
/* LiteralNumber */ .chroma .m { color: #ae81ff }
|
||||
/* LiteralNumberBin */ .chroma .mb { color: #ae81ff }
|
||||
/* LiteralNumberFloat */ .chroma .mf { color: #ae81ff }
|
||||
/* LiteralNumberHex */ .chroma .mh { color: #ae81ff }
|
||||
/* LiteralNumberInteger */ .chroma .mi { color: #ae81ff }
|
||||
/* LiteralNumberIntegerLong */ .chroma .il { color: #ae81ff }
|
||||
/* LiteralNumberOct */ .chroma .mo { color: #ae81ff }
|
||||
/* Operator */ .chroma .o { color: #f92672 }
|
||||
/* OperatorWord */ .chroma .ow { color: #f92672 }
|
||||
/* Comment */ .chroma .c { color: #75715e }
|
||||
/* CommentHashbang */ .chroma .ch { color: #75715e }
|
||||
/* CommentMultiline */ .chroma .cm { color: #75715e }
|
||||
/* CommentSingle */ .chroma .c1 { color: #75715e }
|
||||
/* CommentSpecial */ .chroma .cs { color: #75715e }
|
||||
/* CommentPreproc */ .chroma .cp { color: #75715e }
|
||||
/* CommentPreprocFile */ .chroma .cpf { color: #75715e }
|
||||
/* GenericDeleted */ .chroma .gd { color: #f92672 }
|
||||
/* GenericEmph */ .chroma .ge { font-style: italic }
|
||||
/* GenericInserted */ .chroma .gi { color: #a6e22e }
|
||||
/* GenericStrong */ .chroma .gs { font-weight: bold }
|
||||
/* GenericSubheading */ .chroma .gu { color: #75715e }
|
||||
19
examples/hugo/themes/etch/i18n/en.toml
Normal file
19
examples/hugo/themes/etch/i18n/en.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
# Learn how to use Date format (date, created, updated)
|
||||
# -> https://gohugo.io/functions/dateformat/
|
||||
|
||||
[posts]
|
||||
|
||||
[posts.title]
|
||||
other = "Posts"
|
||||
|
||||
[posts.date]
|
||||
other = "Jan 2, 2006"
|
||||
|
||||
|
||||
[post]
|
||||
|
||||
[post.created]
|
||||
other = "January 2, 2006"
|
||||
|
||||
[post.updated]
|
||||
other = "Updated January 2, 2006"
|
||||
BIN
examples/hugo/themes/etch/images/screenshot.png
Normal file
BIN
examples/hugo/themes/etch/images/screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 62 KiB |
BIN
examples/hugo/themes/etch/images/screenshot_dark.png
Normal file
BIN
examples/hugo/themes/etch/images/screenshot_dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
BIN
examples/hugo/themes/etch/images/screenshot_small.png
Normal file
BIN
examples/hugo/themes/etch/images/screenshot_small.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
BIN
examples/hugo/themes/etch/images/tn.png
Normal file
BIN
examples/hugo/themes/etch/images/tn.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
BIN
examples/hugo/themes/etch/images/tn_dark.png
Normal file
BIN
examples/hugo/themes/etch/images/tn_dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
0
examples/hugo/themes/etch/layouts/404.html
Normal file
0
examples/hugo/themes/etch/layouts/404.html
Normal file
11
examples/hugo/themes/etch/layouts/_default/baseof.html
Normal file
11
examples/hugo/themes/etch/layouts/_default/baseof.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
{{- partial "head.html" . -}}
|
||||
<body>
|
||||
{{- partial "header.html" . -}}
|
||||
<main id="content">
|
||||
{{- block "main" . }}{{- end }}
|
||||
</main>
|
||||
{{- partial "footer.html" . -}}
|
||||
</body>
|
||||
</html>
|
||||
6
examples/hugo/themes/etch/layouts/_default/li.html
Normal file
6
examples/hugo/themes/etch/layouts/_default/li.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<li>
|
||||
<a href="{{ .Permalink }}">
|
||||
{{ .Title }}
|
||||
<small><time>{{ .Date | time.Format (i18n "posts.date") }}</time></small>
|
||||
</a>
|
||||
</li>
|
||||
3
examples/hugo/themes/etch/layouts/_default/list.html
Normal file
3
examples/hugo/themes/etch/layouts/_default/list.html
Normal file
@@ -0,0 +1,3 @@
|
||||
{{ define "main" }}
|
||||
{{- partial "posts.html" . -}}
|
||||
{{ end }}
|
||||
41
examples/hugo/themes/etch/layouts/_default/rss.xml
Normal file
41
examples/hugo/themes/etch/layouts/_default/rss.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
{{- $pctx := . -}}
|
||||
{{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}}
|
||||
{{- $pages := slice -}}
|
||||
{{- if or $.IsHome $.IsSection -}}
|
||||
{{- $pages = $pctx.RegularPages -}}
|
||||
{{- else -}}
|
||||
{{- $pages = $pctx.Pages -}}
|
||||
{{- end -}}
|
||||
{{- $limit := .Site.Config.Services.RSS.Limit -}}
|
||||
{{- if ge $limit 1 -}}
|
||||
{{- $pages = $pages | first $limit -}}
|
||||
{{- end -}}
|
||||
{{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
|
||||
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
|
||||
<channel>
|
||||
<title>{{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}{{ end }}</title>
|
||||
<link>{{ .Permalink }}</link>
|
||||
<description>Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }}</description>
|
||||
<generator>Hugo -- gohugo.io</generator>{{ with .Site.LanguageCode }}
|
||||
<language>{{.}}</language>{{end}}{{ with .Site.Author.email }}
|
||||
<managingEditor>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</managingEditor>{{end}}{{ with .Site.Author.email }}
|
||||
<webMaster>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</webMaster>{{end}}{{ with .Site.Copyright }}
|
||||
<copyright>{{.}}</copyright>{{end}}{{ if not .Date.IsZero }}
|
||||
<lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
|
||||
{{ with .OutputFormats.Get "RSS" }}
|
||||
{{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }}
|
||||
{{ end }}
|
||||
{{ range where .Site.Pages "Kind" "page" }}
|
||||
{{ if or (eq .Section "posts") (eq .Section "post") }}
|
||||
<item>
|
||||
<title>{{ .Title }}</title>
|
||||
<link>{{ .Permalink }}</link>
|
||||
<pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
|
||||
{{ with .Site.Author.email }}<author>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</author>{{end}}
|
||||
<guid>{{ .Permalink }}</guid>
|
||||
<description>{{ .Content | html }}</description>
|
||||
</item>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</channel>
|
||||
</rss>
|
||||
17
examples/hugo/themes/etch/layouts/_default/single.html
Normal file
17
examples/hugo/themes/etch/layouts/_default/single.html
Normal file
@@ -0,0 +1,17 @@
|
||||
{{ define "main" }}
|
||||
<article>
|
||||
<header id="post-header">
|
||||
<h1>{{ .Title }}</h1>
|
||||
<div>
|
||||
{{- if isset .Params "date" -}}
|
||||
{{ if eq .Lastmod .Date }}
|
||||
<time>{{ .Date | time.Format (i18n "post.created") }}</time>
|
||||
{{ else }}
|
||||
<time>{{ .Lastmod | time.Format (i18n "post.updated") }}</time>
|
||||
{{ end }}
|
||||
{{- end -}}
|
||||
</div>
|
||||
</header>
|
||||
{{- .Content -}}
|
||||
</article>
|
||||
{{ end }}
|
||||
8
examples/hugo/themes/etch/layouts/_default/taxonomy.html
Normal file
8
examples/hugo/themes/etch/layouts/_default/taxonomy.html
Normal file
@@ -0,0 +1,8 @@
|
||||
{{ define "main" }}
|
||||
<h3>{{ .Title }}</h3>
|
||||
<ul id="posts">
|
||||
{{- range .Pages }}
|
||||
{{ .Render "li" }}
|
||||
{{- end }}
|
||||
</ul>
|
||||
{{ end }}
|
||||
4
examples/hugo/themes/etch/layouts/index.html
Normal file
4
examples/hugo/themes/etch/layouts/index.html
Normal file
@@ -0,0 +1,4 @@
|
||||
{{ define "main" }}
|
||||
{{ .Content }}
|
||||
{{- partial "posts.html" . -}}
|
||||
{{ end }}
|
||||
3
examples/hugo/themes/etch/layouts/partials/footer.html
Normal file
3
examples/hugo/themes/etch/layouts/partials/footer.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<footer id="footer">
|
||||
{{ .Site.Params.copyright }}
|
||||
</footer>
|
||||
31
examples/hugo/themes/etch/layouts/partials/head.html
Normal file
31
examples/hugo/themes/etch/layouts/partials/head.html
Normal file
@@ -0,0 +1,31 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{{ with .Site.Params.description -}}
|
||||
<meta name="description" content="{{ . }}">
|
||||
{{ end }}
|
||||
{{ printf `<link rel="shortcut icon" href="%s">` ("favicon.ico" | absURL) | safeHTML }}
|
||||
{{ with .OutputFormats.Get "rss" -}}
|
||||
{{ printf `<link rel="%s" type="%s" href="%s" title="%s">` .Rel .MediaType.Type .Permalink $.Site.Title | safeHTML }}
|
||||
{{ end -}}
|
||||
|
||||
{{ $resources := slice -}}
|
||||
|
||||
{{ $resources = $resources | append (resources.Get "css/main.css") -}}
|
||||
|
||||
{{ $resources = $resources | append (resources.Get "css/min770px.css") -}}
|
||||
|
||||
{{ $dark := .Site.Params.dark | default "auto" -}}
|
||||
{{ if not (eq $dark "off") -}}
|
||||
{{ $resources = $resources | append (resources.Get "css/dark.css" | resources.ExecuteAsTemplate "dark.css" .) -}}
|
||||
{{ end -}}
|
||||
|
||||
{{ if .Site.Params.highlight -}}
|
||||
{{ $resources = $resources | append (resources.Get "css/syntax.css") -}}
|
||||
{{ end -}}
|
||||
|
||||
{{ $css := $resources | resources.Concat "css/style.css" | minify }}
|
||||
{{ printf `<link rel="stylesheet" href="%s">` $css.RelPermalink | safeHTML }}
|
||||
|
||||
<title>{{ .Title }}</title>
|
||||
</head>
|
||||
12
examples/hugo/themes/etch/layouts/partials/header.html
Normal file
12
examples/hugo/themes/etch/layouts/partials/header.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<header id="banner">
|
||||
<h2><a href="{{ .Site.BaseURL }}">{{ .Site.Title }}</a></h2>
|
||||
<nav>
|
||||
<ul>
|
||||
{{ range .Site.Menus.main.ByWeight -}}
|
||||
<li>
|
||||
{{ .Pre }}<a href="{{ .URL }}" title="{{ .Title }}">{{- .Name -}}</a>{{ .Post }}
|
||||
</li>
|
||||
{{- end }}
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
6
examples/hugo/themes/etch/layouts/partials/posts.html
Normal file
6
examples/hugo/themes/etch/layouts/partials/posts.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<h3>{{ i18n "posts.title" }}</h3>
|
||||
<ul id="posts">
|
||||
{{- range where site.RegularPages "Type" "in" site.Params.mainSections }}
|
||||
{{ .Render "li" }}
|
||||
{{- end }}
|
||||
</ul>
|
||||
4
examples/hugo/themes/etch/layouts/shortcodes/toc.html
Normal file
4
examples/hugo/themes/etch/layouts/shortcodes/toc.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<aside id="toc">
|
||||
<h4>Table of Contents</h4>
|
||||
{{ .Page.TableOfContents }}
|
||||
</aside>
|
||||
13
examples/hugo/themes/etch/theme.toml
Normal file
13
examples/hugo/themes/etch/theme.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
name = "Etch"
|
||||
license = "MIT"
|
||||
licenselink = "https://github.com/LukasJoswiak/etch/blob/master/LICENSE"
|
||||
description = "Lightweight Hugo theme with a focus on content"
|
||||
homepage = "https://github.com/LukasJoswiak/etch"
|
||||
demosite = "https://lukasjoswiak.github.io/etch/"
|
||||
tags = ["simple", "minimal", "clean", "fast", "blog", "responsive", "dark mode", "privacy"]
|
||||
features = ["fast", "blog", "syntax highlighting", "dark mode"]
|
||||
min_version = "0.41"
|
||||
|
||||
[author]
|
||||
name = "Lukas Joswiak"
|
||||
homepage = "https://lukasjoswiak.com"
|
||||
1
examples/nextjs/.gitignore
vendored
1
examples/nextjs/.gitignore
vendored
@@ -23,6 +23,7 @@
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
module.exports = {
|
||||
/** @type {import('next').NextConfig} */
|
||||
const nextConfig = {
|
||||
reactStrictMode: true,
|
||||
}
|
||||
|
||||
module.exports = nextConfig
|
||||
|
||||
6477
examples/nextjs/package-lock.json
generated
6477
examples/nextjs/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -7,12 +7,12 @@
|
||||
"lint": "next lint"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "^12.0.8",
|
||||
"next": "12.1.0",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"eslint": "8.7.0",
|
||||
"eslint-config-next": "^12.0.8"
|
||||
"eslint": "8.9.0",
|
||||
"eslint-config-next": "12.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export default function Home() {
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://github.com/vercel/next.js/tree/master/examples"
|
||||
href="https://github.com/vercel/next.js/tree/canary/examples"
|
||||
className={styles.card}
|
||||
>
|
||||
<h2>Examples →</h2>
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
padding: 0 0.5rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
.main {
|
||||
padding: 5rem 0;
|
||||
min-height: 100vh;
|
||||
padding: 4rem 0;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -18,10 +13,10 @@
|
||||
}
|
||||
|
||||
.footer {
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
border-top: 1px solid #eaeaea;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
padding: 2rem 0;
|
||||
border-top: 1px solid #eaeaea;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -56,6 +51,7 @@
|
||||
}
|
||||
|
||||
.description {
|
||||
margin: 4rem 0;
|
||||
line-height: 1.5;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
@@ -75,7 +71,6 @@
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
max-width: 800px;
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.card {
|
||||
@@ -87,7 +82,7 @@
|
||||
border: 1px solid #eaeaea;
|
||||
border-radius: 10px;
|
||||
transition: color 0.15s ease, border-color 0.15s ease;
|
||||
width: 45%;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.card:hover,
|
||||
|
||||
1633
examples/nextjs/yarn.lock
Normal file
1633
examples/nextjs/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
1
examples/remix/.gitignore
vendored
1
examples/remix/.gitignore
vendored
@@ -2,7 +2,6 @@ node_modules
|
||||
|
||||
.cache
|
||||
.vercel
|
||||
.output
|
||||
|
||||
public/build
|
||||
api/_build
|
||||
|
||||
@@ -31,7 +31,7 @@ export default function Index() {
|
||||
<p>
|
||||
Wait a sec...<em>its children</em>? To understand what we mean by
|
||||
this,{" "}
|
||||
<a href="https://remix.run/tutorial/4-nested-routes-params">
|
||||
<a href="https://remix.run/docs/en/v1/guides/routing">
|
||||
read all about nested routes in the docs
|
||||
</a>
|
||||
.
|
||||
|
||||
3
examples/sanity/.env.template
Normal file
3
examples/sanity/.env.template
Normal file
@@ -0,0 +1,3 @@
|
||||
# Run `vercel env pull` to generate a .env file from your Vercel project
|
||||
SANITY_STUDIO_API_PROJECT_ID=
|
||||
SANITY_STUDIO_API_DATASET=
|
||||
12
examples/sanity/.npmignore
Normal file
12
examples/sanity/.npmignore
Normal file
@@ -0,0 +1,12 @@
|
||||
# Logs
|
||||
/logs
|
||||
*.log
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
/coverage
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
|
||||
# Compiled sanity studio
|
||||
/dist
|
||||
29
examples/sanity/README.md
Normal file
29
examples/sanity/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Sanity Blogging Content Studio
|
||||
|
||||
Congratulations, you have now installed Sanity Studio, an open source real-time content editing environment connected to the Sanity backend.
|
||||
|
||||
Now you can do the following things:
|
||||
|
||||
- [Read “getting started” in the docs](https://www.sanity.io/docs/introduction/getting-started?utm_source=readme)
|
||||
- Check out the example frontend: [React/Next.js](https://github.com/sanity-io/tutorial-sanity-blog-react-next)
|
||||
- [Read the blog post about this template](https://www.sanity.io/blog/build-your-own-blog-with-sanity-and-next-js?utm_source=readme)
|
||||
- [Join the community Slack](https://slack.sanity.io/?utm_source=readme)
|
||||
- [Extend and build plugins](https://www.sanity.io/docs/content-studio/extending?utm_source=readme)
|
||||
|
||||
## Develop locally
|
||||
|
||||
Install dependencies:
|
||||
|
||||
```sh
|
||||
npx @sanity/cli install
|
||||
```
|
||||
|
||||
Pull down environment variables from your Vercel project (requires the [Vercel CLI](https://vercel.com/cli)):
|
||||
|
||||
```sh
|
||||
vercel env pull
|
||||
```
|
||||
|
||||
|
||||
|
||||
You can also run `npx @sanity/init` in this repo and agree to reconfigure it. You'll then be able to select from existing projects. The CLI will update `sanity.json` with the project ID and dataset name.
|
||||
7
examples/sanity/config/.checksums
Normal file
7
examples/sanity/config/.checksums
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"#": "Used by Sanity to keep track of configuration file checksums, do not delete or modify!",
|
||||
"@sanity/default-layout": "bb034f391ba508a6ca8cd971967cbedeb131c4d19b17b28a0895f32db5d568ea",
|
||||
"@sanity/default-login": "6fb6d3800aa71346e1b84d95bbcaa287879456f2922372bb0294e30b968cd37f",
|
||||
"@sanity/form-builder": "b38478227ba5e22c91981da4b53436df22e48ff25238a55a973ed620be5068aa",
|
||||
"@sanity/data-aspects": "d199e2c199b3e26cd28b68dc84d7fc01c9186bf5089580f2e2446994d36b3cb6"
|
||||
}
|
||||
3
examples/sanity/config/@sanity/data-aspects.json
Normal file
3
examples/sanity/config/@sanity/data-aspects.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"listOptions": {}
|
||||
}
|
||||
6
examples/sanity/config/@sanity/default-layout.json
Normal file
6
examples/sanity/config/@sanity/default-layout.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"toolSwitcher": {
|
||||
"order": [],
|
||||
"hidden": []
|
||||
}
|
||||
}
|
||||
7
examples/sanity/config/@sanity/default-login.json
Normal file
7
examples/sanity/config/@sanity/default-login.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"providers": {
|
||||
"mode": "append",
|
||||
"redirectOnSingle": false,
|
||||
"entries": []
|
||||
}
|
||||
}
|
||||
5
examples/sanity/config/@sanity/form-builder.json
Normal file
5
examples/sanity/config/@sanity/form-builder.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"images": {
|
||||
"directUploads": true
|
||||
}
|
||||
}
|
||||
30
examples/sanity/package.json
Normal file
30
examples/sanity/package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "verceltemplateblogstudio",
|
||||
"private": true,
|
||||
"version": "1.0.0",
|
||||
"description": "This is the public list of examples for **Vercel**",
|
||||
"main": "package.json",
|
||||
"author": "Knut Melvær <knut@sanity.io>",
|
||||
"license": "UNLICENSED",
|
||||
"scripts": {
|
||||
"start": "sanity start",
|
||||
"build": "sanity build"
|
||||
},
|
||||
"keywords": [
|
||||
"sanity"
|
||||
],
|
||||
"dependencies": {
|
||||
"@sanity/core": "^2.26",
|
||||
"@sanity/default-layout": "^2.26",
|
||||
"@sanity/default-login": "^2.26",
|
||||
"@sanity/desk-tool": "^2.26",
|
||||
"@sanity/vision": "^2.26",
|
||||
"prop-types": "^15.7",
|
||||
"react": "^17.0",
|
||||
"react-dom": "^17.0",
|
||||
"styled-components": "^5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sanity/cli": "^2.26"
|
||||
}
|
||||
}
|
||||
1
examples/sanity/plugins/.gitkeep
Normal file
1
examples/sanity/plugins/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
User-specific packages can be placed here
|
||||
29
examples/sanity/sanity.json
Normal file
29
examples/sanity/sanity.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"root": true,
|
||||
"project": {
|
||||
"name": "vercel-template-blog-studio"
|
||||
},
|
||||
"api": {
|
||||
"projectId": "YOUR_PROJECT_ID",
|
||||
"dataset": "YOUR_DATASET_NAME"
|
||||
},
|
||||
"plugins": [
|
||||
"@sanity/base",
|
||||
"@sanity/default-layout",
|
||||
"@sanity/default-login",
|
||||
"@sanity/desk-tool"
|
||||
],
|
||||
"env": {
|
||||
"development": {
|
||||
"plugins": [
|
||||
"@sanity/vision"
|
||||
]
|
||||
}
|
||||
},
|
||||
"parts": [
|
||||
{
|
||||
"name": "part:@sanity/base/schema",
|
||||
"path": "./schemas/schema"
|
||||
}
|
||||
]
|
||||
}
|
||||
48
examples/sanity/schemas/author.js
Normal file
48
examples/sanity/schemas/author.js
Normal file
@@ -0,0 +1,48 @@
|
||||
export default {
|
||||
name: 'author',
|
||||
title: 'Author',
|
||||
type: 'document',
|
||||
fields: [
|
||||
{
|
||||
name: 'name',
|
||||
title: 'Name',
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: 'slug',
|
||||
title: 'Slug',
|
||||
type: 'slug',
|
||||
options: {
|
||||
source: 'name',
|
||||
maxLength: 96,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'image',
|
||||
title: 'Image',
|
||||
type: 'image',
|
||||
options: {
|
||||
hotspot: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'bio',
|
||||
title: 'Bio',
|
||||
type: 'array',
|
||||
of: [
|
||||
{
|
||||
title: 'Block',
|
||||
type: 'block',
|
||||
styles: [{title: 'Normal', value: 'normal'}],
|
||||
lists: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
preview: {
|
||||
select: {
|
||||
title: 'name',
|
||||
media: 'image',
|
||||
},
|
||||
},
|
||||
}
|
||||
65
examples/sanity/schemas/blockContent.js
Normal file
65
examples/sanity/schemas/blockContent.js
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* This is the schema definition for the rich text fields used for
|
||||
* for this blog studio. When you import it in schemas.js it can be
|
||||
* reused in other parts of the studio with:
|
||||
* {
|
||||
* name: 'someName',
|
||||
* title: 'Some title',
|
||||
* type: 'blockContent'
|
||||
* }
|
||||
*/
|
||||
export default {
|
||||
title: 'Block Content',
|
||||
name: 'blockContent',
|
||||
type: 'array',
|
||||
of: [
|
||||
{
|
||||
title: 'Block',
|
||||
type: 'block',
|
||||
// Styles let you set what your user can mark up blocks with. These
|
||||
// correspond with HTML tags, but you can set any title or value
|
||||
// you want and decide how you want to deal with it where you want to
|
||||
// use your content.
|
||||
styles: [
|
||||
{title: 'Normal', value: 'normal'},
|
||||
{title: 'H1', value: 'h1'},
|
||||
{title: 'H2', value: 'h2'},
|
||||
{title: 'H3', value: 'h3'},
|
||||
{title: 'H4', value: 'h4'},
|
||||
{title: 'Quote', value: 'blockquote'},
|
||||
],
|
||||
lists: [{title: 'Bullet', value: 'bullet'}],
|
||||
// Marks let you mark up inline text in the block editor.
|
||||
marks: {
|
||||
// Decorators usually describe a single property – e.g. a typographic
|
||||
// preference or highlighting by editors.
|
||||
decorators: [
|
||||
{title: 'Strong', value: 'strong'},
|
||||
{title: 'Emphasis', value: 'em'},
|
||||
],
|
||||
// Annotations can be any object structure – e.g. a link or a footnote.
|
||||
annotations: [
|
||||
{
|
||||
title: 'URL',
|
||||
name: 'link',
|
||||
type: 'object',
|
||||
fields: [
|
||||
{
|
||||
title: 'URL',
|
||||
name: 'href',
|
||||
type: 'url',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
// You can add additional types here. Note that you can't use
|
||||
// primitive types such as 'string' and 'number' in the same array
|
||||
// as a block type.
|
||||
{
|
||||
type: 'image',
|
||||
options: {hotspot: true},
|
||||
},
|
||||
],
|
||||
}
|
||||
17
examples/sanity/schemas/category.js
Normal file
17
examples/sanity/schemas/category.js
Normal file
@@ -0,0 +1,17 @@
|
||||
export default {
|
||||
name: 'category',
|
||||
title: 'Category',
|
||||
type: 'document',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
title: 'Title',
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
title: 'Description',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
}
|
||||
65
examples/sanity/schemas/post.js
Normal file
65
examples/sanity/schemas/post.js
Normal file
@@ -0,0 +1,65 @@
|
||||
export default {
|
||||
name: 'post',
|
||||
title: 'Post',
|
||||
type: 'document',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
title: 'Title',
|
||||
type: 'string',
|
||||
},
|
||||
{
|
||||
name: 'slug',
|
||||
title: 'Slug',
|
||||
type: 'slug',
|
||||
options: {
|
||||
source: 'title',
|
||||
maxLength: 96,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'author',
|
||||
title: 'Author',
|
||||
type: 'reference',
|
||||
to: {type: 'author'},
|
||||
},
|
||||
{
|
||||
name: 'mainImage',
|
||||
title: 'Main image',
|
||||
type: 'image',
|
||||
options: {
|
||||
hotspot: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'categories',
|
||||
title: 'Categories',
|
||||
type: 'array',
|
||||
of: [{type: 'reference', to: {type: 'category'}}],
|
||||
},
|
||||
{
|
||||
name: 'publishedAt',
|
||||
title: 'Published at',
|
||||
type: 'datetime',
|
||||
},
|
||||
{
|
||||
name: 'body',
|
||||
title: 'Body',
|
||||
type: 'blockContent',
|
||||
},
|
||||
],
|
||||
|
||||
preview: {
|
||||
select: {
|
||||
title: 'title',
|
||||
author: 'author.name',
|
||||
media: 'mainImage',
|
||||
},
|
||||
prepare(selection) {
|
||||
const {author} = selection
|
||||
return Object.assign({}, selection, {
|
||||
subtitle: author && `by ${author}`,
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
29
examples/sanity/schemas/schema.js
Normal file
29
examples/sanity/schemas/schema.js
Normal file
@@ -0,0 +1,29 @@
|
||||
// First, we must import the schema creator
|
||||
import createSchema from 'part:@sanity/base/schema-creator'
|
||||
|
||||
// Then import schema types from any plugins that might expose them
|
||||
import schemaTypes from 'all:part:@sanity/base/schema-type'
|
||||
|
||||
// We import object and document schemas
|
||||
import blockContent from './blockContent'
|
||||
import category from './category'
|
||||
import post from './post'
|
||||
import author from './author'
|
||||
|
||||
// Then we give our schema to the builder and provide the result to Sanity
|
||||
export default createSchema({
|
||||
// We name our schema
|
||||
name: 'default',
|
||||
// Then proceed to concatenate our document type
|
||||
// to the ones provided by any plugins that are installed
|
||||
types: schemaTypes.concat([
|
||||
// The following are document types which will appear
|
||||
// in the studio.
|
||||
post,
|
||||
author,
|
||||
category,
|
||||
// When added to this list, object types can be used as
|
||||
// { type: 'typename' } in other document schemas
|
||||
blockContent,
|
||||
]),
|
||||
})
|
||||
1
examples/sanity/static/.gitkeep
Normal file
1
examples/sanity/static/.gitkeep
Normal file
@@ -0,0 +1 @@
|
||||
Files placed here will be served by the Sanity server under the `/static`-prefix
|
||||
BIN
examples/sanity/static/favicon.ico
Normal file
BIN
examples/sanity/static/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
6
examples/sanity/tsconfig.json
Normal file
6
examples/sanity/tsconfig.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
// Note: This config is only used to help editors like VS Code understand/resolve
|
||||
// parts, the actual transpilation is done by babel. Any compiler configuration in
|
||||
// here will be ignored.
|
||||
"include": ["./node_modules/@sanity/base/types/**/*.ts", "./**/*.ts", "./**/*.tsx"]
|
||||
}
|
||||
9911
examples/sanity/yarn.lock
Normal file
9911
examples/sanity/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
1
examples/solidstart/.gitignore
vendored
1
examples/solidstart/.gitignore
vendored
@@ -2,7 +2,6 @@ dist
|
||||
worker
|
||||
.solid
|
||||
.vercel
|
||||
.output
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
|
||||
1
examples/sveltekit/.gitignore
vendored
1
examples/sveltekit/.gitignore
vendored
@@ -7,4 +7,3 @@ node_modules
|
||||
.env.*
|
||||
!.env.example
|
||||
.vercel
|
||||
.output
|
||||
|
||||
670
examples/sveltekit/package-lock.json
generated
670
examples/sveltekit/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "sveltekit",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "svelte-kit dev",
|
||||
"build": "svelte-kit build",
|
||||
@@ -9,7 +11,7 @@
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "next",
|
||||
"@sveltejs/kit": "next",
|
||||
"svelte": "^3.44.0"
|
||||
"svelte": "^3.46.0"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
%svelte.head%
|
||||
</head>
|
||||
<body>
|
||||
<div id="svelte">%svelte.body%</div>
|
||||
<div>%svelte.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
1
examples/sveltekit/src/global.d.ts
vendored
1
examples/sveltekit/src/global.d.ts
vendored
@@ -1 +0,0 @@
|
||||
/// <reference types="@sveltejs/kit" />
|
||||
@@ -1,19 +1,22 @@
|
||||
import cookie from 'cookie';
|
||||
import { v4 as uuid } from '@lukeed/uuid';
|
||||
|
||||
export const handle = async ({ request, resolve }) => {
|
||||
const cookies = cookie.parse(request.headers.cookie || '');
|
||||
request.locals.userid = cookies.userid || uuid();
|
||||
export const handle = async ({ event, resolve }) => {
|
||||
const cookies = cookie.parse(event.request.headers.get('cookie') || '');
|
||||
event.locals.userid = cookies.userid || uuid();
|
||||
|
||||
const response = await resolve(request);
|
||||
const response = await resolve(event);
|
||||
|
||||
if (!cookies.userid) {
|
||||
// if this is the first time the user has visited this app,
|
||||
// set a cookie so that we recognise them when they return
|
||||
response.headers['set-cookie'] = cookie.serialize('userid', request.locals.userid, {
|
||||
path: '/',
|
||||
httpOnly: true
|
||||
});
|
||||
response.headers.set(
|
||||
'set-cookie',
|
||||
cookie.serialize('userid', event.locals.userid, {
|
||||
path: '/',
|
||||
httpOnly: true
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return response;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<div class="counter-viewport">
|
||||
<div class="counter-digits" style="transform: translate(0, {100 * offset}%)">
|
||||
<strong style="top: -100%" aria-hidden="true">{Math.floor($displayed_count + 1)}</strong>
|
||||
<strong class="hidden" aria-hidden="true">{Math.floor($displayed_count + 1)}</strong>
|
||||
<strong>{Math.floor($displayed_count)}</strong>
|
||||
</div>
|
||||
</div>
|
||||
@@ -94,4 +94,9 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
top: -100%;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { invalidate } from '$app/navigation';
|
||||
|
||||
// this action (https://svelte.dev/tutorial/actions) allows us to
|
||||
// progressively enhance a <form> that already works without JS
|
||||
export function enhance(form, { pending, error, result }) {
|
||||
export function enhance(form, { pending, error, result } = {}) {
|
||||
let current_token;
|
||||
|
||||
async function handle_submit(e) {
|
||||
@@ -8,31 +10,35 @@ export function enhance(form, { pending, error, result }) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
const body = new FormData(form);
|
||||
const data = new FormData(form);
|
||||
|
||||
if (pending) pending(body, form);
|
||||
if (pending) pending({ data, form });
|
||||
|
||||
try {
|
||||
const res = await fetch(form.action, {
|
||||
const response = await fetch(form.action, {
|
||||
method: form.method,
|
||||
headers: {
|
||||
accept: 'application/json'
|
||||
},
|
||||
body
|
||||
body: data
|
||||
});
|
||||
|
||||
if (token !== current_token) return;
|
||||
|
||||
if (res.ok) {
|
||||
result(res, form);
|
||||
if (response.ok) {
|
||||
if (result) result({ data, form, response });
|
||||
|
||||
const url = new URL(form.action);
|
||||
url.search = url.hash = '';
|
||||
invalidate(url.href);
|
||||
} else if (error) {
|
||||
error(res, null, form);
|
||||
error({ data, form, error: null, response });
|
||||
} else {
|
||||
console.error(await res.text());
|
||||
console.error(await response.text());
|
||||
}
|
||||
} catch (e) {
|
||||
if (error) {
|
||||
error(null, e, form);
|
||||
error({ data, form, error: e, response: null });
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { api } from './_api';
|
||||
|
||||
// PATCH /todos/:uid.json
|
||||
export const patch = async (request) => {
|
||||
return api(request, `todos/${request.locals.userid}/${request.params.uid}`, {
|
||||
text: request.body.get('text'),
|
||||
done: request.body.has('done') ? !!request.body.get('done') : undefined
|
||||
});
|
||||
};
|
||||
|
||||
// DELETE /todos/:uid.json
|
||||
export const del = async (request) => {
|
||||
return api(request, `todos/${request.locals.userid}/${request.params.uid}`);
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
This module is used by the /todos.json and /todos/[uid].json
|
||||
endpoints to make calls to api.svelte.dev, which stores todos
|
||||
This module is used by the /todos endpoint to
|
||||
make calls to api.svelte.dev, which stores todos
|
||||
for each user. The leading underscore indicates that this is
|
||||
a private module, _not_ an endpoint — visiting /todos/_api
|
||||
will net you a 404 response.
|
||||
@@ -11,35 +11,12 @@
|
||||
|
||||
const base = 'https://api.svelte.dev';
|
||||
|
||||
export async function api(request, resource, data) {
|
||||
// user must have a cookie set
|
||||
if (!request.locals.userid) {
|
||||
return { status: 401 };
|
||||
}
|
||||
|
||||
const res = await fetch(`${base}/${resource}`, {
|
||||
method: request.method,
|
||||
export function api(method, resource, data) {
|
||||
return fetch(`${base}/${resource}`, {
|
||||
method,
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
body: data && JSON.stringify(data)
|
||||
});
|
||||
|
||||
// if the request came from a <form> submission, the browser's default
|
||||
// behaviour is to show the URL corresponding to the form's "action"
|
||||
// attribute. in those cases, we want to redirect them back to the
|
||||
// /todos page, rather than showing the response
|
||||
if (res.ok && request.method !== 'GET' && request.headers.accept !== 'application/json') {
|
||||
return {
|
||||
status: 303,
|
||||
headers: {
|
||||
location: '/todos'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: res.status,
|
||||
body: await res.json()
|
||||
};
|
||||
}
|
||||
|
||||
66
examples/sveltekit/src/routes/todos/index.js
Normal file
66
examples/sveltekit/src/routes/todos/index.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import { api } from './_api';
|
||||
|
||||
export const get = async ({ locals }) => {
|
||||
// locals.userid comes from src/hooks.js
|
||||
const response = await api('get', `todos/${locals.userid}`);
|
||||
|
||||
if (response.status === 404) {
|
||||
// user hasn't created a todo list.
|
||||
// start with an empty array
|
||||
return {
|
||||
body: {
|
||||
todos: []
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (response.status === 200) {
|
||||
return {
|
||||
body: {
|
||||
todos: await response.json()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: response.status
|
||||
};
|
||||
};
|
||||
|
||||
export const post = async ({ request, locals }) => {
|
||||
const form = await request.formData();
|
||||
|
||||
await api('post', `todos/${locals.userid}`, {
|
||||
text: form.get('text')
|
||||
});
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
// If the user has JavaScript disabled, the URL will change to
|
||||
// include the method override unless we redirect back to /todos
|
||||
const redirect = {
|
||||
status: 303,
|
||||
headers: {
|
||||
location: '/todos'
|
||||
}
|
||||
};
|
||||
|
||||
export const patch = async ({ request, locals }) => {
|
||||
const form = await request.formData();
|
||||
|
||||
await api('patch', `todos/${locals.userid}/${form.get('uid')}`, {
|
||||
text: form.has('text') ? form.get('text') : undefined,
|
||||
done: form.has('done') ? !!form.get('done') : undefined
|
||||
});
|
||||
|
||||
return redirect;
|
||||
};
|
||||
|
||||
export const del = async ({ request, locals }) => {
|
||||
const form = await request.formData();
|
||||
|
||||
await api('delete', `todos/${locals.userid}/${form.get('uid')}`);
|
||||
|
||||
return redirect;
|
||||
};
|
||||
@@ -1,28 +0,0 @@
|
||||
import { api } from './_api';
|
||||
|
||||
// GET /todos.json
|
||||
export const get = async (request) => {
|
||||
// request.locals.userid comes from src/hooks.js
|
||||
const response = await api(request, `todos/${request.locals.userid}`);
|
||||
|
||||
if (response.status === 404) {
|
||||
// user hasn't created a todo list.
|
||||
// start with an empty array
|
||||
return { body: [] };
|
||||
}
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
// POST /todos.json
|
||||
export const post = async (request) => {
|
||||
const response = await api(request, `todos/${request.locals.userid}`, {
|
||||
// because index.svelte posts a FormData object,
|
||||
// request.body is _also_ a (readonly) FormData
|
||||
// object, which allows us to get form data
|
||||
// with the `body.get(key)` method
|
||||
text: request.body.get('text')
|
||||
});
|
||||
|
||||
return response;
|
||||
};
|
||||
@@ -1,40 +1,9 @@
|
||||
<script context="module">
|
||||
import { enhance } from '$lib/form';
|
||||
|
||||
// see https://kit.svelte.dev/docs#loading
|
||||
export const load = async ({ fetch }) => {
|
||||
const res = await fetch('/todos.json');
|
||||
|
||||
if (res.ok) {
|
||||
const todos = await res.json();
|
||||
|
||||
return {
|
||||
props: { todos }
|
||||
};
|
||||
}
|
||||
|
||||
const { message } = await res.json();
|
||||
|
||||
return {
|
||||
error: new Error(message)
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { enhance } from '$lib/form';
|
||||
import { scale } from 'svelte/transition';
|
||||
import { flip } from 'svelte/animate';
|
||||
|
||||
export let todos;
|
||||
|
||||
async function patch(res) {
|
||||
const todo = await res.json();
|
||||
|
||||
todos = todos.map((t) => {
|
||||
if (t.uid === todo.uid) return todo;
|
||||
return t;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -46,13 +15,10 @@
|
||||
|
||||
<form
|
||||
class="new"
|
||||
action="/todos.json"
|
||||
action="/todos"
|
||||
method="post"
|
||||
use:enhance={{
|
||||
result: async (res, form) => {
|
||||
const created = await res.json();
|
||||
todos = [...todos, created];
|
||||
|
||||
result: async ({ form }) => {
|
||||
form.reset();
|
||||
}
|
||||
}}
|
||||
@@ -68,41 +34,33 @@
|
||||
animate:flip={{ duration: 200 }}
|
||||
>
|
||||
<form
|
||||
action="/todos/{todo.uid}.json?_method=PATCH"
|
||||
action="/todos?_method=PATCH"
|
||||
method="post"
|
||||
use:enhance={{
|
||||
pending: (data) => {
|
||||
pending: ({ data }) => {
|
||||
todo.done = !!data.get('done');
|
||||
},
|
||||
result: patch
|
||||
}
|
||||
}}
|
||||
>
|
||||
<input type="hidden" name="uid" value={todo.uid} />
|
||||
<input type="hidden" name="done" value={todo.done ? '' : 'true'} />
|
||||
<button class="toggle" aria-label="Mark todo as {todo.done ? 'not done' : 'done'}" />
|
||||
</form>
|
||||
|
||||
<form
|
||||
class="text"
|
||||
action="/todos/{todo.uid}.json?_method=PATCH"
|
||||
method="post"
|
||||
use:enhance={{
|
||||
result: patch
|
||||
}}
|
||||
>
|
||||
<form class="text" action="/todos?_method=PATCH" method="post" use:enhance>
|
||||
<input type="hidden" name="uid" value={todo.uid} />
|
||||
<input aria-label="Edit todo" type="text" name="text" value={todo.text} />
|
||||
<button class="save" aria-label="Save todo" />
|
||||
</form>
|
||||
|
||||
<form
|
||||
action="/todos/{todo.uid}.json?_method=DELETE"
|
||||
action="/todos?_method=DELETE"
|
||||
method="post"
|
||||
use:enhance={{
|
||||
pending: () => (todo.pending_delete = true),
|
||||
result: () => {
|
||||
todos = todos.filter((t) => t.uid !== todo.uid);
|
||||
}
|
||||
pending: () => (todo.pending_delete = true)
|
||||
}}
|
||||
>
|
||||
<input type="hidden" name="uid" value={todo.uid} />
|
||||
<button class="delete" aria-label="Delete todo" disabled={todo.pending_delete} />
|
||||
</form>
|
||||
</div>
|
||||
@@ -158,7 +116,7 @@
|
||||
.done {
|
||||
transform: none;
|
||||
opacity: 0.4;
|
||||
filter: drop-shadow(0px 0px 1px rgba(0, 0, 0, 0.1));
|
||||
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
|
||||
form.text {
|
||||
|
||||
@@ -5,8 +5,10 @@ const config = {
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
|
||||
// hydrate the <div id="svelte"> element in src/app.html
|
||||
target: '#svelte'
|
||||
// Override http methods in the Todo forms
|
||||
methodOverride: {
|
||||
allowed: ['PATCH', 'DELETE']
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
"@typescript-eslint/parser": "4.28.0",
|
||||
"async-retry": "1.2.3",
|
||||
"buffer-replace": "1.0.0",
|
||||
"cheerio": "1.0.0-rc.3",
|
||||
"eslint": "7.29.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-plugin-jest": "24.3.6",
|
||||
@@ -43,8 +42,9 @@
|
||||
"node-fetch": "2.6.1",
|
||||
"npm-package-arg": "6.1.0",
|
||||
"prettier": "2.3.1",
|
||||
"ts-eager": "2.0.2",
|
||||
"ts-jest": "27.0.4",
|
||||
"turbo": "1.0.18"
|
||||
"turbo": "1.1.9"
|
||||
},
|
||||
"scripts": {
|
||||
"lerna": "lerna",
|
||||
@@ -54,9 +54,10 @@
|
||||
"publish-from-github": "./utils/publish.sh",
|
||||
"changelog": "node utils/changelog.js",
|
||||
"build": "turbo run build",
|
||||
"vercel-build": "mkdir -p public && echo '<a href=\"https://vercel.com/import\">Import</a>' > public/output.html",
|
||||
"vercel-build": "yarn build && cd api && node -r ts-eager/register ./_lib/script/build.ts",
|
||||
"pre-commit": "lint-staged",
|
||||
"test-unit": "node utils/run.js test-unit",
|
||||
"test": "jest --rootDir=\"test\" --testPathPattern=\"\\.test.js\"",
|
||||
"test-unit": "yarn test && node utils/run.js test-unit",
|
||||
"test-integration-cli": "node utils/run.js test-integration-cli",
|
||||
"test-integration-once": "node utils/run.js test-integration-once",
|
||||
"test-integration-dev": "node utils/run.js test-integration-dev",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "2.13.1-canary.0",
|
||||
"version": "2.15.0",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
@@ -30,7 +30,7 @@
|
||||
"@types/node-fetch": "^2.1.6",
|
||||
"@types/semver": "6.0.0",
|
||||
"@types/yazl": "^2.4.1",
|
||||
"@vercel/frameworks": "0.5.1-canary.20",
|
||||
"@vercel/frameworks": "0.7.0",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"aggregate-error": "3.0.1",
|
||||
"async-retry": "1.2.3",
|
||||
|
||||
@@ -1,412 +0,0 @@
|
||||
import fs from 'fs-extra';
|
||||
import { join, parse, relative, dirname, basename, extname } from 'path';
|
||||
import glob from './fs/glob';
|
||||
import { normalizePath } from './fs/normalize-path';
|
||||
import { FILES_SYMBOL, Lambda } from './lambda';
|
||||
import type { BuildOptions, Files } from './types';
|
||||
import { debug, getIgnoreFilter } from '.';
|
||||
|
||||
// `.output` was already created by the Build Command, so we have
|
||||
// to ensure its contents don't get bundled into the Lambda. Similarily,
|
||||
// we don't want to bundle anything from `.vercel` either. Lastly,
|
||||
// Builders/Runtimes didn't have `vercel.json` or `now.json`.
|
||||
const ignoredPaths = ['.output', '.vercel', 'vercel.json', 'now.json'];
|
||||
|
||||
const shouldIgnorePath = (
|
||||
file: string,
|
||||
ignoreFilter: any,
|
||||
ignoreFile: boolean
|
||||
) => {
|
||||
const isNative = ignoredPaths.some(item => {
|
||||
return file.startsWith(item);
|
||||
});
|
||||
|
||||
if (!ignoreFile) {
|
||||
return isNative;
|
||||
}
|
||||
|
||||
return isNative || ignoreFilter(file);
|
||||
};
|
||||
|
||||
const getSourceFiles = async (workPath: string, ignoreFilter: any) => {
|
||||
const list = await glob('**', {
|
||||
cwd: workPath,
|
||||
});
|
||||
|
||||
// We're not passing this as an `ignore` filter to the `glob` function above,
|
||||
// so that we can re-use exactly the same `getIgnoreFilter` method that the
|
||||
// Build Step uses (literally the same code). Note that this exclusion only applies
|
||||
// when deploying. Locally, another exclusion is needed, which is handled
|
||||
// further below in the `convertRuntimeToPlugin` function.
|
||||
for (const file in list) {
|
||||
if (shouldIgnorePath(file, ignoreFilter, true)) {
|
||||
delete list[file];
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert legacy Runtime to a Plugin.
|
||||
* @param buildRuntime - a legacy build() function from a Runtime
|
||||
* @param packageName - the name of the package, for example `vercel-plugin-python`
|
||||
* @param ext - the file extension, for example `.py`
|
||||
*/
|
||||
export function _experimental_convertRuntimeToPlugin(
|
||||
buildRuntime: (options: BuildOptions) => Promise<{ output: Lambda }>,
|
||||
packageName: string,
|
||||
ext: string
|
||||
) {
|
||||
// This `build()` signature should match `plugin.build()` signature in `vercel build`.
|
||||
return async function build({ workPath }: { workPath: string }) {
|
||||
// We also don't want to provide any files to Runtimes that were ignored
|
||||
// through `.vercelignore` or `.nowignore`, because the Build Step does the same.
|
||||
const ignoreFilter = await getIgnoreFilter(workPath);
|
||||
|
||||
// Retrieve the files that are currently available on the File System,
|
||||
// before the Legacy Runtime has even started to build.
|
||||
const sourceFilesPreBuild = await getSourceFiles(workPath, ignoreFilter);
|
||||
|
||||
// Instead of doing another `glob` to get all the matching source files,
|
||||
// we'll filter the list of existing files down to only the ones
|
||||
// that are matching the entrypoint pattern, so we're first creating
|
||||
// a clean new list to begin.
|
||||
const entrypoints = Object.assign({}, sourceFilesPreBuild);
|
||||
|
||||
const entrypointMatch = new RegExp(`^api/.*${ext}$`);
|
||||
|
||||
// Up next, we'll strip out the files from the list of entrypoints
|
||||
// that aren't actually considered entrypoints.
|
||||
for (const file in entrypoints) {
|
||||
if (!entrypointMatch.test(file)) {
|
||||
delete entrypoints[file];
|
||||
}
|
||||
}
|
||||
|
||||
const pages: { [key: string]: any } = {};
|
||||
const pluginName = packageName.replace('vercel-plugin-', '');
|
||||
const outputPath = join(workPath, '.output');
|
||||
|
||||
const traceDir = join(
|
||||
outputPath,
|
||||
`inputs`,
|
||||
// Legacy Runtimes can only provide API Routes, so that's
|
||||
// why we can use this prefix for all of them. Here, we have to
|
||||
// make sure to not use a cryptic hash name, because people
|
||||
// need to be able to easily inspect the output.
|
||||
`api-routes-${pluginName}`
|
||||
);
|
||||
|
||||
await fs.ensureDir(traceDir);
|
||||
|
||||
const entryRoot = join(outputPath, 'server', 'pages');
|
||||
|
||||
for (const entrypoint of Object.keys(entrypoints)) {
|
||||
const { output } = await buildRuntime({
|
||||
files: sourceFilesPreBuild,
|
||||
entrypoint,
|
||||
workPath,
|
||||
config: {
|
||||
zeroConfig: true,
|
||||
},
|
||||
meta: {
|
||||
avoidTopLevelInstall: true,
|
||||
skipDownload: true,
|
||||
},
|
||||
});
|
||||
|
||||
// @ts-ignore This symbol is a private API
|
||||
const lambdaFiles: Files = output[FILES_SYMBOL];
|
||||
|
||||
// When deploying, the `files` that are passed to the Legacy Runtimes already
|
||||
// have certain files that are ignored stripped, but locally, that list of
|
||||
// files isn't used by the Legacy Runtimes, so we need to apply the filters
|
||||
// to the outputs that they are returning instead.
|
||||
for (const file in lambdaFiles) {
|
||||
if (shouldIgnorePath(file, ignoreFilter, false)) {
|
||||
delete lambdaFiles[file];
|
||||
}
|
||||
}
|
||||
|
||||
let handlerFileBase = output.handler;
|
||||
let handlerFile = lambdaFiles[handlerFileBase];
|
||||
let handlerHasImport = false;
|
||||
|
||||
const { handler } = output;
|
||||
const handlerMethod = handler.split('.').pop();
|
||||
const handlerFileName = handler.replace(`.${handlerMethod}`, '');
|
||||
|
||||
// For compiled languages, the launcher file for the Lambda generated
|
||||
// by the Legacy Runtime matches the `handler` defined for it, but for
|
||||
// interpreted languages, the `handler` consists of the launcher file name
|
||||
// without an extension, plus the name of the method inside of that file
|
||||
// that should be invoked, so we have to construct the file path explicitly.
|
||||
if (!handlerFile) {
|
||||
handlerFileBase = handlerFileName + ext;
|
||||
handlerFile = lambdaFiles[handlerFileBase];
|
||||
handlerHasImport = true;
|
||||
}
|
||||
|
||||
if (!handlerFile || !handlerFile.fsPath) {
|
||||
throw new Error(
|
||||
`Could not find a handler file. Please ensure that \`files\` for the returned \`Lambda\` contains an \`FileFsRef\` named "${handlerFileBase}" with a valid \`fsPath\`.`
|
||||
);
|
||||
}
|
||||
|
||||
const handlerExtName = extname(handlerFile.fsPath);
|
||||
|
||||
const entryBase = basename(entrypoint).replace(ext, handlerExtName);
|
||||
const entryPath = join(dirname(entrypoint), entryBase);
|
||||
const entry = join(entryRoot, entryPath);
|
||||
|
||||
// Create the parent directory of the API Route that will be created
|
||||
// for the current entrypoint inside of `.output/server/pages/api`.
|
||||
await fs.ensureDir(dirname(entry));
|
||||
|
||||
// For compiled languages, the launcher file will be binary and therefore
|
||||
// won't try to import a user-provided request handler (instead, it will
|
||||
// contain it). But for interpreted languages, the launcher might try to
|
||||
// load a user-provided request handler from the source file instead of bundling
|
||||
// it, so we have to adjust the import statement inside the launcher to point
|
||||
// to the respective source file. Previously, Legacy Runtimes simply expected
|
||||
// the user-provided request-handler to be copied right next to the launcher,
|
||||
// but with the new File System API, files won't be moved around unnecessarily.
|
||||
if (handlerHasImport) {
|
||||
const { fsPath } = handlerFile;
|
||||
const encoding = 'utf-8';
|
||||
|
||||
// This is the true directory of the user-provided request handler in the
|
||||
// source files, so that's what we will use as an import path in the launcher.
|
||||
const locationPrefix = relative(entry, outputPath);
|
||||
|
||||
let handlerContent = await fs.readFile(fsPath, encoding);
|
||||
|
||||
const importPaths = [
|
||||
// This is the full entrypoint path, like `./api/test.py`. In our tests
|
||||
// Python didn't support importing from a parent directory without using different
|
||||
// code in the launcher that registers it as a location for modules and then changing
|
||||
// the importing syntax, but continuing to import it like before seems to work. If
|
||||
// other languages need this, we should consider excluding Python explicitly.
|
||||
// `./${entrypoint}`,
|
||||
|
||||
// This is the entrypoint path without extension, like `api/test`
|
||||
entrypoint.slice(0, -ext.length),
|
||||
];
|
||||
|
||||
// Generate a list of regular expressions that we can use for
|
||||
// finding matches, but only allow matches if the import path is
|
||||
// wrapped inside single (') or double quotes (").
|
||||
const patterns = importPaths.map(path => {
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
return new RegExp(`('|")(${path.replace(/\./g, '\\.')})('|")`, 'g');
|
||||
});
|
||||
|
||||
let replacedMatch = null;
|
||||
|
||||
for (const pattern of patterns) {
|
||||
const newContent = handlerContent.replace(
|
||||
pattern,
|
||||
(_, p1, p2, p3) => {
|
||||
return `${p1}${join(locationPrefix, p2)}${p3}`;
|
||||
}
|
||||
);
|
||||
|
||||
if (newContent !== handlerContent) {
|
||||
debug(
|
||||
`Replaced "${pattern}" inside "${entry}" to ensure correct import of user-provided request handler`
|
||||
);
|
||||
|
||||
handlerContent = newContent;
|
||||
replacedMatch = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!replacedMatch) {
|
||||
new Error(
|
||||
`No replacable matches for "${importPaths[0]}" or "${importPaths[1]}" found in "${fsPath}"`
|
||||
);
|
||||
}
|
||||
|
||||
await fs.writeFile(entry, handlerContent, encoding);
|
||||
} else {
|
||||
await fs.copy(handlerFile.fsPath, entry);
|
||||
}
|
||||
|
||||
// Legacy Runtimes based on interpreted languages will create a new launcher file
|
||||
// for every entrypoint, but they will create each one inside `workPath`, which means that
|
||||
// the launcher for one entrypoint will overwrite the launcher provided for the previous
|
||||
// entrypoint. That's why, above, we copy the file contents into the new destination (and
|
||||
// optionally transform them along the way), instead of linking. We then also want to remove
|
||||
// the copy origin right here, so that the `workPath` doesn't contain a useless launcher file
|
||||
// once the build has finished running.
|
||||
await fs.remove(handlerFile.fsPath);
|
||||
debug(`Removed temporary file "${handlerFile.fsPath}"`);
|
||||
|
||||
const nft = `${entry}.nft.json`;
|
||||
|
||||
const json = JSON.stringify({
|
||||
version: 2,
|
||||
files: Object.keys(lambdaFiles)
|
||||
.map(file => {
|
||||
const { fsPath } = lambdaFiles[file];
|
||||
|
||||
if (!fsPath) {
|
||||
throw new Error(
|
||||
`File "${file}" is missing valid \`fsPath\` property`
|
||||
);
|
||||
}
|
||||
|
||||
// The handler was already moved into position above.
|
||||
if (file === handlerFileBase) {
|
||||
return;
|
||||
}
|
||||
|
||||
return normalizePath(relative(dirname(nft), fsPath));
|
||||
})
|
||||
.filter(Boolean),
|
||||
});
|
||||
|
||||
await fs.writeFile(nft, json);
|
||||
|
||||
// Add an entry that will later on be added to the `functions-manifest.json`
|
||||
// file that is placed inside of the `.output` directory.
|
||||
pages[normalizePath(entryPath)] = {
|
||||
// Because the underlying file used as a handler was placed
|
||||
// inside `.output/server/pages/api`, it no longer has the name it originally
|
||||
// had and is now named after the API Route that it's responsible for,
|
||||
// so we have to adjust the name of the Lambda handler accordingly.
|
||||
handler: handler.replace(handlerFileName, parse(entry).name),
|
||||
runtime: output.runtime,
|
||||
memory: output.memory,
|
||||
maxDuration: output.maxDuration,
|
||||
environment: output.environment,
|
||||
allowQuery: output.allowQuery,
|
||||
};
|
||||
}
|
||||
|
||||
// Add any Serverless Functions that were exposed by the Legacy Runtime
|
||||
// to the `functions-manifest.json` file provided in `.output`.
|
||||
await _experimental_updateFunctionsManifest({ workPath, pages });
|
||||
};
|
||||
}
|
||||
|
||||
async function readJson(filePath: string): Promise<{ [key: string]: any }> {
|
||||
try {
|
||||
const str = await fs.readFile(filePath, 'utf8');
|
||||
return JSON.parse(str);
|
||||
} catch (err) {
|
||||
if (err.code === 'ENOENT') {
|
||||
return {};
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If `.output/functions-manifest.json` exists, append to the pages
|
||||
* property. Otherwise write a new file.
|
||||
*/
|
||||
export async function _experimental_updateFunctionsManifest({
|
||||
workPath,
|
||||
pages,
|
||||
}: {
|
||||
workPath: string;
|
||||
pages: { [key: string]: any };
|
||||
}) {
|
||||
const functionsManifestPath = join(
|
||||
workPath,
|
||||
'.output',
|
||||
'functions-manifest.json'
|
||||
);
|
||||
const functionsManifest = await readJson(functionsManifestPath);
|
||||
|
||||
if (!functionsManifest.version) functionsManifest.version = 2;
|
||||
if (!functionsManifest.pages) functionsManifest.pages = {};
|
||||
|
||||
for (const [pageKey, pageConfig] of Object.entries(pages)) {
|
||||
functionsManifest.pages[pageKey] = { ...pageConfig };
|
||||
}
|
||||
|
||||
await fs.writeFile(functionsManifestPath, JSON.stringify(functionsManifest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Append routes to the `routes-manifest.json` file.
|
||||
* If the file does not exist, it will be created.
|
||||
*/
|
||||
export async function _experimental_updateRoutesManifest({
|
||||
workPath,
|
||||
redirects,
|
||||
rewrites,
|
||||
headers,
|
||||
dynamicRoutes,
|
||||
staticRoutes,
|
||||
}: {
|
||||
workPath: string;
|
||||
redirects?: {
|
||||
source: string;
|
||||
destination: string;
|
||||
statusCode: number;
|
||||
regex: string;
|
||||
}[];
|
||||
rewrites?: {
|
||||
source: string;
|
||||
destination: string;
|
||||
regex: string;
|
||||
}[];
|
||||
headers?: {
|
||||
source: string;
|
||||
headers: {
|
||||
key: string;
|
||||
value: string;
|
||||
}[];
|
||||
regex: string;
|
||||
}[];
|
||||
dynamicRoutes?: {
|
||||
page: string;
|
||||
regex: string;
|
||||
namedRegex?: string;
|
||||
routeKeys?: { [named: string]: string };
|
||||
}[];
|
||||
staticRoutes?: {
|
||||
page: string;
|
||||
regex: string;
|
||||
namedRegex?: string;
|
||||
routeKeys?: { [named: string]: string };
|
||||
}[];
|
||||
}) {
|
||||
const routesManifestPath = join(workPath, '.output', 'routes-manifest.json');
|
||||
|
||||
const routesManifest = await readJson(routesManifestPath);
|
||||
|
||||
if (!routesManifest.version) routesManifest.version = 3;
|
||||
if (routesManifest.pages404 === undefined) routesManifest.pages404 = true;
|
||||
|
||||
if (redirects) {
|
||||
if (!routesManifest.redirects) routesManifest.redirects = [];
|
||||
routesManifest.redirects.push(...redirects);
|
||||
}
|
||||
|
||||
if (rewrites) {
|
||||
if (!routesManifest.rewrites) routesManifest.rewrites = [];
|
||||
routesManifest.rewrites.push(...rewrites);
|
||||
}
|
||||
|
||||
if (headers) {
|
||||
if (!routesManifest.headers) routesManifest.headers = [];
|
||||
routesManifest.headers.push(...headers);
|
||||
}
|
||||
|
||||
if (dynamicRoutes) {
|
||||
if (!routesManifest.dynamicRoutes) routesManifest.dynamicRoutes = [];
|
||||
routesManifest.dynamicRoutes.push(...dynamicRoutes);
|
||||
}
|
||||
|
||||
if (staticRoutes) {
|
||||
if (!routesManifest.staticRoutes) routesManifest.staticRoutes = [];
|
||||
routesManifest.staticRoutes.push(...staticRoutes);
|
||||
}
|
||||
|
||||
await fs.writeFile(routesManifestPath, JSON.stringify(routesManifest));
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getPlatformEnv } from './';
|
||||
import { getPlatformEnv } from './get-platform-env';
|
||||
|
||||
export default function debug(message: string, ...additional: any[]) {
|
||||
if (getPlatformEnv('BUILDER_DEBUG')) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user