diff --git a/.gitignore b/.gitignore index b2d6de3..f2dca41 100644 --- a/.gitignore +++ b/.gitignore @@ -1,20 +1,5 @@ -# Dependencies -/node_modules +node_modules +build -# Production -/build - -# Generated files .docusaurus -.cache-loader - -# Misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* +.vscode diff --git a/docs/Comparison.mdx b/docs/Comparison.mdx index 65c9c59..0a4cc46 100644 --- a/docs/Comparison.mdx +++ b/docs/Comparison.mdx @@ -31,7 +31,7 @@ export const Center = ({ children }) => { - + diff --git a/docs/common-pitfalls.mdx b/docs/common-pitfalls.mdx index 1198f4d..aebbea8 100644 --- a/docs/common-pitfalls.mdx +++ b/docs/common-pitfalls.mdx @@ -13,7 +13,7 @@ export const getCode = name => { return code.substring(start + startComment.length + 1, end); }; -saucer aims to be easy to use and hard to misuse, however there are still some pitfalls saucer can't detect. +The API aims to be easy to use and hard to misuse, however there are still some pitfalls saucer can't detect. This page tries to document the most common mistakes and how to avoid them. ## Execution Order Matters @@ -21,13 +21,13 @@ This page tries to document the most common mistakes and how to avoid them. The order in which you call some methods matters! Common mistakes that fall under this category are those, in which you call `set_url` _(or `serve`)_ before `expose`. - + {getCode('execution-order-ill-formed')} -In this example, it is not guaranteed that the function `add_random` is available to the web-page immediately after loading. +In this case, it is not guaranteed that the function `add_random` is available to the web-page immediately. To fix this issue simply re-order the code. - + {getCode('execution-order-fixed')} diff --git a/docs/getting-started/basic-app.mdx b/docs/getting-started/basic-app.mdx index 328fa0a..72c19ef 100644 --- a/docs/getting-started/basic-app.mdx +++ b/docs/getting-started/basic-app.mdx @@ -4,8 +4,11 @@ sidebar_position: 2 # Your First Application -In this chapter I'll explain how to setup a very basic saucer application. -Make sure you've read the previous pages and have the system dependencies installed. +> On this page you'll learn how to setup your very first saucer project. + +:::caution +Make sure you've read the previous pages and have the system dependencies installed! +::: ## CMake Setup diff --git a/docs/getting-started/dependencies.mdx b/docs/getting-started/dependencies.mdx index ac97f61..2cb98c5 100644 --- a/docs/getting-started/dependencies.mdx +++ b/docs/getting-started/dependencies.mdx @@ -7,23 +7,31 @@ import TabItem from '@theme/TabItem'; # Dependencies -Saucer expects some dependencies to be installed on your system. -We depend on fairly common packages to make sure that the installation will be as smooth as possible. +Saucer relies on certain system-level dependencies that you are expected to have installed. +These dependencies are fairly common though, so chances are you won't have to additionally instally anything. -On Windows the WebView2 Runtime is required, which is usually already installed on the system and comes -pre-installed on Windows 11. - -In case you don't have it installed already you can download it from Microsoft's official website [here](https://developer.microsoft.com/microsoft-edge/webview2/#download-section). +On Windows the [WebView2 Runtime](https://developer.microsoft.com/microsoft-edge/webview2/#download-section) is required, which is usually already installed on the system and comes pre-installed since Windows 11. -On Linux saucer depends on Qt (Qt5 and Qt6 are supported) as it is well established in the Linux world and most systems have it installed already. +On Linux saucer depends on Qt5 or Qt6 as it is well established in the Linux world and most systems have it installed already. + +In case you dont have Qt installed on your system already, you may refer to your distribution on how to install the following packages: + +:::caution +Package names may differ on your distribution! +::: -In case you dont have Qt installed on your system already, you may refer to your distrubtion on how to install the following packages: `qt5-qtwebengine qt5-qtwebchannel qt5-qtbase-gui qt5-qtbase` _(Names may differ depending on the distro used)_. +
    +
  • qt5-qtwebengine
  • +
  • qt5-qtwebchannel
  • +
  • qt5-qtbase-gui
  • +
  • qt5-qtbase
  • +
diff --git a/docs/getting-started/embedding.mdx b/docs/getting-started/embedding.mdx index 25cb1eb..2f667c9 100644 --- a/docs/getting-started/embedding.mdx +++ b/docs/getting-started/embedding.mdx @@ -5,34 +5,39 @@ The easiest way to accomplish this is to use the [saucer-cli](https://github.com ## Pre-Requisites -- Generate a static version of your website -- In case you use a Router make sure it's supported, see [Common Pitfalls](../common-pitfalls) +- A built version of your website _(that should consist of `.html`, `.js`, ... files)_ -## Recommended Usage +## Usage -We recommend that you use `saucer-cli` within the build script of your frontends `package.json`. +### Recommended Usage -Simply add `saucer-cli` as a dependency, i.e. `pnpm install saucer-cli`, and then modify your `package.json`: +We recommend to use `saucer-cli` within your `package.json` build script. + +Simply add `saucer-cli` as a dependency _(i.e. `pnpm install saucer-cli`)_ and then conduct the following changes: ```json { // ... "scripts": { - "build": " && saucer embed dist" + "build": " && saucer embed " } + // ... } ``` ### Manually Embedding Files :::caution -I do not recommend manually embedding the frontend files. -Refer to [the recommended usage](#recommended-usage). +Manually embedding is discouraged. +Please prefer the method mentioned above! ::: -First off, place all your web content into a single folder. +First off, make sure you have the `saucer-cli` installed globally. +This can be achieved by installing it as a global npm package: `npm i -g saucer-app`. + +Now place all your web content into a single folder. -```text title="Example Folder Structure" +```text title="Example: Folder Structure" out ├── 404.html ├── icon.webp @@ -60,7 +65,7 @@ out └── _ssgManifest.js ``` -Now you can use the `saucer-cli` to generate the required embedding files. +Use the `saucer-cli` to generate the required embedding files. ```bash title="Command Syntax" saucer embed [] @@ -76,14 +81,14 @@ After running the embed command through the cli, a folder named `"embedded"` _- Now simply consume this folder as a include directory. -```cmake title="Consuming Embedding folder through CMake" +```cmake title="Example: Consuming Embedded Folder" target_include_directories(${PROJECT_NAME} PRIVATE "path/to/generated/folder") ``` Now it's only a matter of including the header in your code and calling `embed` on the webview. To serve the files simply call `serve` and specify the file name. -```cpp title="Example" +```cpp title="Example: Using Embedded Files" // green #include diff --git a/docs/getting-started/events.mdx b/docs/getting-started/events.mdx index 23407a3..73279f1 100644 --- a/docs/getting-started/events.mdx +++ b/docs/getting-started/events.mdx @@ -17,18 +17,18 @@ import domReady from './events/dom-ready.cpp'; # Events -In this chapter, I'll describe the available events and how to use them. +> On this page you'll learn about the available events and how to use them. ## Basics Events are simply callbacks which are invoked for specific actions and can, in certain circumstances, even alter the behavior of the application. -### Register Event Callback +### Register Callback To register an event callback simply call the `on` method of your webview. You'll need to pass the event-type as the template parameter and the callback as the function argument. -Every call to `on` will return an `event-id` which can later be used to `remove` the same callback. +Every call to `on()` will return an id which can later be used to remove the same callback. ```cpp title="Example Callback (Resize Window)" smartview.on([](int width, int height) @@ -37,12 +37,12 @@ smartview.on([](int width, int height) }); ``` -### Unregister Event Callback +### Remove Callback -As previously mentioned you can unregister an event callback by saving it's `event-id`. -To unregister, simply call `remove`, with the event-type as the first and the `event-id` as the second argument. +As previously mentioned you can unregister callbacks by saving their id. +To remove a callback, simply call `remove` with the event-type as the first and the id as the second argument. -```cpp title="Example Callback Removal" +```cpp title="Example: Callback Removal" auto id = smartview.on([](int width, int height) { // ... @@ -52,9 +52,9 @@ smartview.remove(saucer::window_event::resize, id); ``` :::tip -If you simply want to remove all event callbacks belonging to a specific event-type you can use the `clear` method. +In case you simply want to remove all event callbacks of a specific event-type you can use the `clear` method. -```cpp title="Clearing all Resize Callbacks" +```cpp title="Example: Clearing all Resize Callbacks" smartview.clear(saucer::window_event::resize); ``` diff --git a/docs/getting-started/installation.mdx b/docs/getting-started/installation.mdx index d14a27a..5e4fe10 100644 --- a/docs/getting-started/installation.mdx +++ b/docs/getting-started/installation.mdx @@ -7,18 +7,21 @@ import TabItem from '@theme/TabItem'; # Installation -On this page I'll explain how to install saucer through any of the officially supported ways. -To get started choose your desired installation method below. +> On this page you'll learn how to install saucer through any of the officially supported ways. :::caution Saucer requires a fairly recent compiler! In case you encounter any errors while building please make sure to update your compiler. ::: +To get started choose your desired installation method below. + + -I recommend [CPM](https://github.com/cpm-cmake/CPM.cmake) for managing dependencies with CMake. +I recommend [CPM](https://github.com/cpm-cmake/CPM.cmake) for managing dependencies with CMake. +Please refer to their [docs](https://github.com/cpm-cmake/CPM.cmake#adding-cpm) on how to install it. ```cmake CPMFindPackage( @@ -37,7 +40,11 @@ target_link_libraries(${PROJECT_NAME} [PRIVATE|PUBLIC] saucer::saucer) -We also have an official [vcpkg](https://github.com/microsoft/vcpkg) port. +:::info +Eventhough an offical vcpkg port exists, I would still recommend using CMake. +::: + +Saucer also has an official [vcpkg](https://github.com/microsoft/vcpkg) port. To consume saucer simply run the following command. ```bash title="Normal Installation" diff --git a/docs/getting-started/interoperability.mdx b/docs/getting-started/interoperability.mdx index 7c6abf9..a133191 100644 --- a/docs/getting-started/interoperability.mdx +++ b/docs/getting-started/interoperability.mdx @@ -8,18 +8,20 @@ import CodeBlock from '@theme/CodeBlock'; # Interoperability In the previous chapter, you've created your first saucer application. -Without explaining what exactly is being done, I've used a smartview in conjunction with the `Glaze-Serializer` to expose a native function. -I'll now go into more detail on how exactly Interoperability works and will briefly talk about what a Serializer is. +Without diving into the library headers, you've probably not noticed, that `saucer::smartview` has a defaulted template parameter `Serializer`. + +I'll now go into more detail on how exactly Interoperability works and will briefly talk about what a serializer is. ## What is a Serializer -In short, a serializer is something to help us transform our native types into something that both JavaScript and C++ understand. -Saucer ships the `Glaze-Serializer` by default, however you can also write your own Serializer in case you need something more specific. +In short, a serializer is something that transforms native types into something that both JavaScript and C++ understand. + +Saucer currently ships a default serializer that is based on [glaze](https://github.com/stephenberry/glaze), however you're free to implement your own if desired (see [Custom Serializers](../advanced/Custom%20Serializers)). ## What is a `smartview` -A `smartview` is a type of `webview` that is able to use a serializer to exchange data between C++ and JavaScript. +A `smartview` is a type of `webview` that makes use of a serializer to exchange data between C++ and JavaScript. For more information see: @@ -30,7 +32,7 @@ For more information see: You can expose a native function to the JavaScript world by calling `expose` on your `smartview`. -```cpp title="Exposing a function" +```cpp title="Example: Exposing a function" smartview.expose("add_ten", [](int i) { return i + 10; @@ -38,11 +40,10 @@ smartview.expose("add_ten", [](int i) ``` -By default all exposed functions will be called synchronously, which just means that the `webview` will block until your function is finished, which is usually -not a problem unless your function performs some heavy operations. -You can change this behavior by passing `true` as the last parameter to the `expose` call. +All exposed functions are called synchronously by default. +To make the call to your function asynchronous, simply pass `true` as the last parameter. -```cpp title="Exposing a function asynchronously" +```cpp title="Example: Exposing a function asynchronously" smartview.expose("add_ten", [](int i) { std::this_thread::sleep_for(std::chrono::seconds(10)); @@ -52,22 +53,22 @@ smartview.expose("add_ten", [](int i) ``` -Once you've exposed your function from the C++ side, you can easily call it from JavaScript. +Once you've exposed your function from the C++ side, you can call it from JavaScript. -```js title="Calling your exposed function from the JavaScript World" +```js title="Example: Calling your exposed function from the JavaScript World" const ten_added = await window.saucer.call('add_ten', [10]); // > ten_added == 20 ``` ## Calling JavaScript -Using the `smartview` you'll also be able to evaluate JavaScript code and capture it's result. +You can also execute JavaScript code and capture it's result using the `evaluate` method. ```cpp auto random = smartview.evaluate("Math.random()").get(); ``` -You can also pass C++ Objects as parameters when calling `eval`. +You can also pass C++ objects as parameters when calling `evaluate`. ```cpp auto random = smartview.evaluate("Math.pow({}, {})", 2, 5).get(); @@ -75,7 +76,7 @@ smartview.evaluate("console.log({})", std::vector{10}).get(); ``` :::tip -Instead of manually typing out the parameters you can also make use of `saucer::make_args`. +Instead of manually typing out the parameters you can also utilize `saucer::make_args`. ```cpp auto random = smartview.evaluate("Math.pow({})", saucer::make_args(2, 5)).get(); @@ -84,7 +85,7 @@ auto random = smartview.evaluate("Math.pow({})", saucer::make_args(2, 5)) ::: :::caution -`evaluate()` returns a `std::future`, which means that using it outside of an asynchronous context will cause your `webview` to lock up! +`evaluate` returns `std::future`, which means that calling it outside of an asynchronous context will cause a deadlock! To circumvent this take a look at the [Future Utilities](#future-utilities). ::: @@ -100,16 +101,14 @@ Start off by including the utility header: ### Then -Because there is no `std::future::then` yet I've implemented a small alternative. +`saucer::then` is a basic implementation for `std::future::then` _(Which does not currently exist in the standard)_ -```cpp +```cpp title="Example Usage" saucer::then(smartview.evaluate("Math.random()"), [](float result) { std::cout << "The random number was " << result << std::endl; }); -// ...or - smartview.evaluate("Math.random()") | saucer::then([](float result) { std::cout << "Result: " << result << std::endl; @@ -118,30 +117,27 @@ smartview.evaluate("Math.random()") | saucer::then([](float result) ### Forget -This can be used to perform a simple fire-and-forget operation. +Use `saucer::forget` in case you want to discard _(not use)_ the result of the evaluation. -```cpp +```cpp title="Example Usage" saucer::forget(smartview.evaluate("Math.random()")); -// ...or - smartview.evaluate("Math.random()") | saucer::forget(); ``` -:::note +:::warning A `std::future` will also block on destruction if: > (2) the shared state is not yet ready[¹](https://en.cppreference.com/w/cpp/thread/future/%7Efuture) -So make sure you call `saucer::forget` on the future if you don't care about it's return value! - +As a result, any calls to `smartview.evaluate(...)` should be forwarded to `saucer::forget` ::: ### All -If you have multiple `std::future`s and want to wait until all of them are ready you can use `saucer::all`. +In case you have multiple `std::future`_s_ and want to wait until all of them are ready you can use `saucer::all`. -```cpp +```cpp title="Example Usage" auto a = smartview.evaluate("Math.random()"); auto b = smartview.evaluate("Math.random()"); auto c = smartview.evaluate("Math.random()"); @@ -151,9 +147,9 @@ auto [random, random2, random3] = saucer::all(a, b, c); ## User Defined Types -The `Glaze-Serializer`, which saucer ships by default, supports the serialization of primitives as well as some STL-types by default. +[glaze](https://github.com/stephenberry/glaze) supports the serialization of primitives as well as many STL types by default. Please refer to their [documentation](https://github.com/stephenberry/glaze#example) on how to add support for third-party types. - + {code} diff --git a/src/css/custom.css b/src/css/custom.css index 56f3f1d..112a2ac 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -1,25 +1,54 @@ :root { --ifm-color-primary: #8d3de0; - --ifm-color-primary-dark: #8438ea; - --ifm-color-primary-darker: #7634e1; - --ifm-color-primary-darkest: #6620d9; - --ifm-color-primary-light: #ee59f5; - --ifm-color-primary-lighter: #e457e6; - --ifm-color-primary-lightest: #dd8fdf; + --ifm-color-primary-dark: #8559FF; + --ifm-color-primary-darker: #9d7cd8; +} + +.hero .theme-code-block { + --ifm-global-shadow-lw: var(--ifm-global-shadow-tl); +} + +.card { + --ifm-global-shadow-lw: 0 1px 16px 0 rgba(0, 0, 0, 0.05); +} - --ifm-navbar-shadow: 0; - --feature-box: #353133; - --hero-banner-ternary: #f1f2f6; +/* + * Light Theme + */ + +[data-theme='light'] { + --ifm-background-color: #FDF0ED !important; + --ifm-hero-background-color: #FCE9E4; + --ifm-card-background-color: #F9CEC34D; + --ifm-navbar-background-color: var(--ifm-background-color); } -.footer--dark { - --ifm-footer-background-color: #292a26; +[data-theme='light'] footer { + --ifm-color-secondary: #06060C; + --ifm-footer-title-color: #06060CB3; + --ifm-footer-background-color: #FBDED7; } +/* + * Dark Theme + */ + [data-theme='dark'] { - --hero-banner-ternary: #2a2a2a; + --ifm-background-color: #31364e !important; + --ifm-card-background-color: #373d58; + --ifm-hero-background-color: #3a415e; + --ifm-font-color-base-inverse: #c0caf5; + --ifm-navbar-background-color: var(--ifm-background-color); } +[data-theme='dark'] footer { + --ifm-footer-background-color: #24283b; +} + +/* + * Code Blocks + */ + .code-block-gray { background-color: #6a6a6a20; display: block; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 0013de4..22d86ba 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -71,7 +71,7 @@ const features: Feature.Feature[] = [ { title: 'FOSS', button: 'See License', - link: 'https://github.com/saucer/saucer/blob/dev/LICENSE', + link: 'https://github.com/saucer/saucer/blob/master/LICENSE', icon: , description: ( <> @@ -98,7 +98,7 @@ export default function Home(): JSX.Element { - + {features.map(feature => (