chore: import upstream snapshot with attribution
CI / compile_and_lint (push) Failing after 0s
CI / docker_build (linux/amd64, -linux-amd64-duckdb, duckdb) (push) Failing after 0s
CI / docker_build (linux/arm64, -linux-arm64, minimal) (push) Failing after 2s
CI / docker_build (linux/arm64, -linux-arm64-duckdb, duckdb) (push) Failing after 1s
CI / docker_build (linux/amd64, minimal) (push) Failing after 1s
CI / test (, sqlite, sqlite::memory:) (push) Has been skipped
CI / test (mssql, mssql, mssql://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / test (mysql, mysql, mysql://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / test (oracle, oracle, Driver=Oracle 21 ODBC driver;Dbq=//127.0.0.1:1521/FREEPDB1;Uid=root;Pwd=Password123!) (push) Has been skipped
CI / test (postgres, odbc, Driver=PostgreSQL Unicode;Server=127.0.0.1;Port=5432;Database=sqlpage;UID=root;PWD=Password123!, true) (push) Has been skipped
CI / test (postgres, postgres, postgres://root:Password123!@127.0.0.1/sqlpage) (push) Has been skipped
CI / playwright (push) Has been skipped
CI / docker_build (linux/arm/v7, -linux-arm-v7, minimal) (push) Failing after 0s
CI / hurl_examples (push) Failing after 8s
deploy website / deploy_official_site (push) Failing after 1s
CI / hurl (${{ matrix.example }}) (push) Has been skipped
CI / docker_push (duckdb) (push) Has been cancelled
CI / docker_push (minimal) (push) Has been cancelled
CI / windows_test (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 12:31:57 +08:00
commit d718c5a372
986 changed files with 74597 additions and 0 deletions
@@ -0,0 +1,186 @@
select 'dynamic' as component, properties FROM example WHERE component = 'shell' LIMIT 1;
select 'text' as component, '
# Creating your own SQLPage components
If you have some frontend development experience, you can create your own components, by placing
[`.handlebars`](https://handlebarsjs.com/guide/) files in a folder called `sqlpage/templates` at the root of your server.
## Web page structure
### The [`shell`](./documentation.sql?component=shell#component) component
Each page in SQLPage is composed of a `shell` component,
which contains the page title and the navigation bar,
and a series of normal components that display the data.
The `shell` component is always present unless explicitly skipped via the `?_sqlpage_embed` query parameter.
If you don''t call it explicitly, it will be invoked with the default parameters automatically before your first component
invocation that tries to render data on the page.
#### Custom `shell` components
You can override the default `shell` component by creating a file called `shell.handlebars` in the `sqlpage/templates` folder.
If you want to keep the default `shell` component on most of your pages, but want to create a custom `shell` component for a specific page,
you can create a file called `shell-custom.handlebars` (or any other name starting with `shell`) in the `sqlpage/templates` folder.
Here is an example for a minimal custom `shell` component:
```handlebars
<!DOCTYPE html>
<html>
<head>
<title>{{default title "SQLPage"}}</title>
</head>
<body>
{{~#each_row~}}{{~/each_row~}}
</body>
</html>
```
Since you have full control over the `shell` component, you can use it to generate non-HTML content.
For instance, you can write an XML shell to create a custom RSS feed.
## Component template syntax
Components are written in [handlebars](https://handlebarsjs.com/guide/),
which is a simple templating language that allows you to insert data in your HTML.
Here is a simple example of a component that displays a list of items:
```handlebars
<h1>{{title}}</h1>
<ul>
{{#each_row}}
<li>{{my_property}} {{other_property}}</li>
{{/each_row}}
</ul>
```
If you save this file as `sqlpage/templates/my_list.handlebars`, you can use it in your SQL queries
by calling the `my_list` component:
```sql
SELECT ''my_list'' AS component, ''My list'' AS title;
SELECT first_name AS my_property, last_name AS other_property FROM clients;
```
### Styling
SQLPage uses [tabler](https://tabler.io/) for its default styling.
You can include any of the tabler classes in your components to style them.
Since tabler inherits from [bootstrap](https://getbootstrap.com/), you can also use bootstrap classes.
For instance, you can easily create a multi-column layout with the following code:
```handlebars
<div class="row">
{{#each_row}}
<div class="col">
{{my_property}}
</div>
{{/each_row}}
</div>
```
For custom styling, you can write your own CSS files
and include them in your page header.
You can use the `css` parameter of the default [`shell`](./documentation.sql?component=shell#component) component,
or create your own custom `shell` component with a `<link>` tag.
### Helpers
Handlebars has a concept of [helpers](https://handlebarsjs.com/guide/expressions.html#helpers),
which are functions that you can call from your templates to perform some operations.
Handlebars comes with [a few built-in helpers](https://handlebarsjs.com/guide/builtin-helpers.html),
and SQLPage adds a few more:
- `eq`, `ne`: compares two values for equality (equal, not equal)
- `gt`, `gte`, `lt`, `lte`: compares two values (greater than, greater than or equal, less than, less than or equal)
- `or`, `and`: combines two boolean values (logical operators)
- `not`: negates a boolean value (logical operator)
- `len`: returns the length of a list or string, or the number of keys in an object
- `stringify`: converts a value to its json string representation, useful to pass parameters from the database to javascript functions
- `parse_json`: parses a json string into a value, useful to accept complex parameters from databases that don''t have a native json type
- `default`: returns the first argument if it is not null, otherwise returns the second argument. For instance: `{{default my_value ''default value''}}`.
- `entries`: returns the entries of an object as a list of `{key, value}` objects.
- `delay` and `flush_delayed`: temporarily saves a value to memory, and outputs it later. For instance:
- ```handlebars
{{#if complex_condition}}
<a href="{{link}}">
{{#delay}}
</a>
{{/delay}}
{{/if}}
...
{{flush_delayed}}
```
- `sort`: sorts a list of values
- `plus`, `minus`, `sum`: mathematical operators
- `starts_with`: returns true if a string starts with another string
- `to_array`: useful to accept parameters that can optionally be repeated:
- if the argument is a list, returns it unchanged,
- if the argument is a string containing a valid json list, returns the parsed list,
- otherwise returns a list containing only the argument
- `array_contains`: returns true if a list contains a value
- `static_path`: returns the path to one of the static files bundled with SQLPage. Accepts arguments like `sqlpage.js`, `sqlpage.css`, `apexcharts.js`, etc.
- `app_config`: returns the value of a configuration parameter from sqlpage''s configuration file, such as `max_uploaded_file_size`, `site_prefix`, etc.
- `icon_img`: generate an svg icon from a *tabler* icon name
- `markdown`: renders markdown text. Accepts an optional 2nd argument `''allow_unsafe''` that will render embedded html blocks: use only on trusted content. See the [Commonmark spec](https://spec.commonmark.org/0.31.2/#html-blocks) for more info.
- `each_row`: iterates over the rows of a query result
- `typeof`: returns the type of a value (`string`, `number`, `boolean`, `object`, `array`, `null`)
- `rfc2822_date`: formats a date as a string in the [RFC 2822](https://tools.ietf.org/html/rfc2822#section-3.3) format, that is, `Thu, 21 Dec 2000 16:01:07 +0200`
- `url_encode`: percent-encodes a string for use in a URL. For instance, `{{url_encode "hello world"}}` returns `hello%20world`.
### Attributes
In addition to the parameters you pass to your components in your SQL queries,
SQLPage adds the following attributes to the context of your components:
- `@component_index` : the index of the current component in the page. Useful to generate unique ids or classes.
- `@row_index` : the index of the current row in the current component. Useful to implement special behavior on the first row, for instance.
- `@csp_nonce` : a random nonce that you must use as the `nonce` attribute of your `<script>` tags if you include external scripts.
## External javascript
For security, by default SQLPage ships with a [Content Security Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) that prevents the execution of inline javascript
and the loading of external scripts. However, you can include external scripts in your page by adding them to the `javascript` parameter of the default [`shell`](./documentation.sql?component=shell#component) component,
or inside your own custom components using
```handlebars
<script nonce="{{@csp_nonce}}">
// your javascript code here
</script>
```
## Overwriting the default components
You can overwrite the default components, including the `shell` component,
by creating a file with the same name in the `sqlpage/templates` folder.
For example, if you want to change the appearance of the `shell` component,
you can create a file called `sqlpage/templates/shell.handlebars` and write your own HTML in it.
If you don''t want to start from scratch, you can copy the default `shell` component
[from the SQLPage source code](https://github.com/sqlpage/SQLPage/blob/main/sqlpage/templates/shell.handlebars).
## Examples
All the default components are written in handlebars, and you can read their source code to learn how to write your own.
[See the default components source code](https://github.com/sqlpage/SQLPage/blob/main/sqlpage/templates).
Some interesting examples are:
- [The `shell` component](https://github.com/sqlpage/SQLPage/blob/main/sqlpage/templates/shell.handlebars)
- [The `card` component](https://github.com/sqlpage/SQLPage/blob/main/sqlpage/templates/card.handlebars): simple yet complete example of a component that displays a list of items.
- [The `table` component](https://github.com/sqlpage/SQLPage/blob/main/sqlpage/templates/table.handlebars): more complex example of a component that uses
- the `eq`, `or`, and `sort` handlebars helpers,
- the `../` syntax to access the parent context,
- and the `@key` to work with objects whose keys are not known in advance.
' as contents_md;