diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000..3b638a56 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,34 @@ +name: Deploy to Production +on: + release: + # type: released + # A release was published, or a pre-release was changed to a release. + types: [released] + # repository_dispatch: + # types: [deploy] + +jobs: + deploy: + name: Deploy to Fly.io and Netlify + runs-on: ubuntu-latest + steps: + - uses: superfly/flyctl-actions/setup-flyctl@master + - uses: dsaltares/fetch-gh-release-asset@master + with: + file: "static-assets.tar.gz" + - name: Un-tar static assets + run: tar -xzvf static-assets.tar.gz + - name: Publish to Netlify + uses: netlify/actions/cli@master + with: + args: deploy --dir=target/site --prod + env: + NETLIFY_SITE_ID: 92571a12-b93f-4e77-bf4e-744c8ccec4e5 + NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }} + - uses: dsaltares/fetch-gh-release-asset@master + with: + file: "fly.toml" + - run: flyctl deploy --image $IMAGE_LABEL + env: + FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} + IMAGE_LABEL: registry.fly.io/christopherbiscardi:${{github.event.release.name}} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..12e674cd --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,68 @@ +name: Cut Release +on: + push: + branches: + - "wasm-main" + paths: + - "src/**" + - "Dockerfile" + - "style/**" + - "tailwind.config.js" + - "fly.toml" + - "public/**" + +jobs: + release: + name: Test, Release [Docker, GH] + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + with: + toolchain: nightly-2024-08-10 + targets: "wasm32-unknown-unknown" + - uses: superfly/flyctl-actions/setup-flyctl@master + - uses: Swatinem/rust-cache@v2 + with: + # The prefix cache key, this can be changed to start a new cache manually. + prefix-key: "v0-rust" + + # A cache key that is used instead of the automatic `job`-based key, + # and is stable over multiple jobs. + # default: empty + # shared-key: "" + - name: "Install cargo-leptos" + run: curl --proto '=https' --tlsv1.2 -LsSf https://leptos-rs.artifacts.axodotdev.host/cargo-leptos/v0.2.12/cargo-leptos-installer.sh | sh + - run: cargo leptos test + - run: cargo leptos build --release + env: + CDN_PATH: https://cdn.christopherbiscardi.com + CDN_PKG_PATH: https://cdn.christopherbiscardi.com/pkg + LEPTOS_HASH_FILES: true + - name: Get current date + id: date + run: | + echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_ENV + - name: Publish Docker Image to Fly.io + run: flyctl deploy --build-only --push --image-label $IMAGE_LABEL + env: + FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} + IMAGE_LABEL: gh-${{ env.date }}-${{ github.sha }} + - name: Tar static files + run: | + tar -czvf static-assets.tar.gz target/site + - name: Publish GitHub Release + id: gh-release + uses: softprops/action-gh-release@v1 + with: + name: gh-${{ env.date }}-${{ github.sha }} + fail_on_unmatched_files: true + target_commitish: main + tag_name: ${{env.date}}-${{ github.sha }} + token: ${{ secrets.RELEASE_TOKEN }} + files: | + Cargo.toml + target/release/this-week-in-bevy + static-assets.tar.gz + target/release/hash.txt + fly.toml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..108b9bd0 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,12 @@ +name: test suite +on: [pull_request] + +jobs: + test: + name: cargo leptos test + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo install cargo-leptos + - run: cargo leptos test diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..6985cf1b --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 00000000..ea35942d --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1,4 @@ +max_width = 60 +wrap_comments = true +comment_width = 50 +fn_call_width = 40 diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..2264dd29 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,19 @@ +[workspace] +resolver = "2" +members = ["crates/*"] + + +# Defines a size-optimized profile for the WASM bundle in release mode +[profile.wasm-release] +inherits = "release" +opt-level = 'z' +lto = true +codegen-units = 1 +panic = "abort" + + +# [patch.crates-io] +# # leptos = { version = "0.7.0-beta" +# leptos = { git = "https://github.com/leptos-rs/leptos", branch = "leptos_0.7" } +# leptos_axum = { git = "https://github.com/leptos-rs/leptos", branch = "leptos_0.7" } +# leptos_router = { git = "https://github.com/leptos-rs/leptos", branch = "leptos_0.7" } diff --git a/crates/www/Cargo.toml b/crates/www/Cargo.toml new file mode 100644 index 00000000..9dc709f5 --- /dev/null +++ b/crates/www/Cargo.toml @@ -0,0 +1,108 @@ +[package] +name = "www" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +leptos_meta = { git = "https://github.com/leptos-rs/leptos", branch = "leptos_0.7" } +axum = { version = "0.7", optional = true } +console_error_panic_hook = "0.1" +leptos = { git = "https://github.com/leptos-rs/leptos", branch = "leptos_0.7", features = [ + "nightly", + "experimental-islands", +] } +leptos_axum = { git = "https://github.com/leptos-rs/leptos", branch = "leptos_0.7", optional = true } +leptos_router = { git = "https://github.com/leptos-rs/leptos", branch = "leptos_0.7", features = [ + "nightly", +] } +leptos-use = { git = "https://github.com/Synphonyte/leptos-use.git", branch = "leptos-0.7" } +tokio = { version = "1", features = ["rt-multi-thread"], optional = true } +tower = { version = "0.4", optional = true } +tower-http = { version = "0.5", features = ["fs"], optional = true } +wasm-bindgen = "=0.2.92" +thiserror = "1" +tracing = { version = "0.1", optional = true } +http = "1" + + +[features] +hydrate = ["leptos/hydrate"] +ssr = [ + "dep:axum", + "dep:tokio", + "dep:tower", + "dep:tower-http", + "dep:leptos_axum", + "leptos/ssr", + "leptos_meta/ssr", + "leptos_router/ssr", + "dep:tracing", +] + + +[package.metadata.leptos] +# The name used by wasm-bindgen/cargo-leptos for the JS/WASM bundle. Defaults to the crate name +output-name = "www" + +# The site root folder is where cargo-leptos generate all output. WARNING: all content of this folder will be erased on a rebuild. Use it in your server setup. +site-root = "target/site" + +# The site-root relative folder where all compiled output (JS, WASM and CSS) is written +# Defaults to pkg +site-pkg-dir = "pkg" + +# [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to //app.css +# style-file = "style/main.scss" +tailwind-input-file = "style/input.css" + +# Assets source dir. All files found here will be copied and synchronized to site-root. +# The assets-dir cannot have a sub directory with the same name/path as site-pkg-dir. +# +# Optional. Env: LEPTOS_ASSETS_DIR. +assets-dir = "public" + +# The IP and port (ex: 127.0.0.1:3000) where the server serves the content. Use it in your server setup. +site-addr = "127.0.0.1:3000" + +# The port to use for automatic reload monitoring +reload-port = 3001 + +# [Optional] Command to use when running end2end tests. It will run in the end2end dir. +# [Windows] for non-WSL use "npx.cmd playwright test" +# This binary name can be checked in Powershell with Get-Command npx +end2end-cmd = "npx playwright test" +end2end-dir = "end2end" + +# The browserlist query used for optimizing the CSS. +browserquery = "defaults" + +# The environment Leptos will run in, usually either "DEV" or "PROD" +env = "DEV" + +# The features to use when compiling the bin target +# +# Optional. Can be over-ridden with the command line parameter --bin-features +bin-features = ["ssr"] + +# If the --no-default-features flag should be used when compiling the bin target +# +# Optional. Defaults to false. +bin-default-features = false + +# The features to use when compiling the lib target +# +# Optional. Can be over-ridden with the command line parameter --lib-features +lib-features = ["hydrate"] + +# If the --no-default-features flag should be used when compiling the lib target +# +# Optional. Defaults to false. +lib-default-features = false + +# The profile to use for the lib target when compiling for release +# +# Optional. Defaults to "release". +lib-profile-release = "wasm-release" diff --git a/crates/www/LICENSE b/crates/www/LICENSE new file mode 100644 index 00000000..fdddb29a --- /dev/null +++ b/crates/www/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +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 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. + +For more information, please refer to diff --git a/crates/www/README.md b/crates/www/README.md new file mode 100644 index 00000000..b1d5de23 --- /dev/null +++ b/crates/www/README.md @@ -0,0 +1,90 @@ + + + Leptos Logo + + +# Leptos Axum Starter Template + +This is a template for use with the [Leptos](https://github.com/leptos-rs/leptos) web framework and the [cargo-leptos](https://github.com/akesson/cargo-leptos) tool using [Axum](https://github.com/tokio-rs/axum). + +## Creating your template repo + +If you don't have `cargo-leptos` installed you can install it with + +```bash +cargo install cargo-leptos --locked +``` + +Then run +```bash +cargo leptos new --git https://github.com/leptos-rs/start-axum-0.7 +``` + +to generate a new project template. + +```bash +cd www +``` + +to go to your newly created project. +Feel free to explore the project structure, but the best place to start with your application code is in `src/app.rs`. +Addtionally, Cargo.toml may need updating as new versions of the dependencies are released, especially if things are not working after a `cargo update`. + +## Running your project + +```bash +cargo leptos watch +``` + +## Installing Additional Tools + +By default, `cargo-leptos` uses `nightly` Rust, `cargo-generate`, and `sass`. If you run into any trouble, you may need to install one or more of these tools. + +1. `rustup toolchain install nightly --allow-downgrade` - make sure you have Rust nightly +2. `rustup target add wasm32-unknown-unknown` - add the ability to compile Rust to WebAssembly +3. `cargo install cargo-generate` - install `cargo-generate` binary (should be installed automatically in future) +4. `npm install -g sass` - install `dart-sass` (should be optional in future + +## Compiling for Release +```bash +cargo leptos build --release +``` + +Will generate your server binary in target/server/release and your site package in target/site + +## Testing Your Project +```bash +cargo leptos end-to-end +``` + +```bash +cargo leptos end-to-end --release +``` + +Cargo-leptos uses Playwright as the end-to-end test tool. +Tests are located in end2end/tests directory. + +## Executing a Server on a Remote Machine Without the Toolchain +After running a `cargo leptos build --release` the minimum files needed are: + +1. The server binary located in `target/server/release` +2. The `site` directory and all files within located in `target/site` + +Copy these files to your remote server. The directory structure should be: +```text +www +site/ +``` +Set the following environment variables (updating for your project as needed): +```text +LEPTOS_OUTPUT_NAME="www" +LEPTOS_SITE_ROOT="site" +LEPTOS_SITE_PKG_DIR="pkg" +LEPTOS_SITE_ADDR="127.0.0.1:3000" +LEPTOS_RELOAD_PORT="3001" +``` +Finally, run the server binary. + +## Licensing + +This template itself is released under the Unlicense. You should replace the LICENSE for your own application with an appropriate license if you plan to release it publicly. diff --git a/crates/www/end2end/package-lock.json b/crates/www/end2end/package-lock.json new file mode 100644 index 00000000..260e8eb1 --- /dev/null +++ b/crates/www/end2end/package-lock.json @@ -0,0 +1,167 @@ +{ + "name": "end2end", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "end2end", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@playwright/test": "^1.44.1", + "@types/node": "^20.12.12", + "typescript": "^5.4.5" + } + }, + "node_modules/@playwright/test": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.1.tgz", + "integrity": "sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.44.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@types/node": { + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.1.tgz", + "integrity": "sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.44.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.1.tgz", + "integrity": "sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "license": "MIT" + } + }, + "dependencies": { + "@playwright/test": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.1.tgz", + "integrity": "sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==", + "dev": true, + "requires": { + "playwright": "1.44.1" + } + }, + "@types/node": { + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "dev": true, + "requires": { + "undici-types": "~5.26.4" + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "playwright": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.1.tgz", + "integrity": "sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==", + "dev": true, + "requires": { + "fsevents": "2.3.2", + "playwright-core": "1.44.1" + } + }, + "playwright-core": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.1.tgz", + "integrity": "sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==", + "dev": true + }, + "typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true + }, + "undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + } + } +} diff --git a/crates/www/end2end/package.json b/crates/www/end2end/package.json new file mode 100644 index 00000000..a80ac597 --- /dev/null +++ b/crates/www/end2end/package.json @@ -0,0 +1,15 @@ +{ + "name": "end2end", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": {}, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@playwright/test": "^1.44.1", + "@types/node": "^20.12.12", + "typescript": "^5.4.5" + } +} diff --git a/crates/www/end2end/playwright.config.ts b/crates/www/end2end/playwright.config.ts new file mode 100644 index 00000000..aee2d46f --- /dev/null +++ b/crates/www/end2end/playwright.config.ts @@ -0,0 +1,105 @@ +import type { PlaywrightTestConfig } from "@playwright/test"; +import { devices, defineConfig } from "@playwright/test"; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// require('dotenv').config(); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: "./tests", + /* Maximum time one test can run for. */ + timeout: 30 * 1000, + expect: { + /** + * Maximum time expect() should wait for the condition to be met. + * For example in `await expect(locator).toHaveText();` + */ + timeout: 5000, + }, + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 1 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: "html", + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ + actionTimeout: 0, + /* Base URL to use in actions like `await page.goto('/')`. */ + // baseURL: 'http://localhost:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: "on-first-retry", + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: "chromium", + use: { + ...devices["Desktop Chrome"], + }, + }, + + { + name: "firefox", + use: { + ...devices["Desktop Firefox"], + }, + }, + + { + name: "webkit", + use: { + ...devices["Desktop Safari"], + }, + }, + + /* Test against mobile viewports. */ + // { + // name: 'Mobile Chrome', + // use: { + // ...devices['Pixel 5'], + // }, + // }, + // { + // name: 'Mobile Safari', + // use: { + // ...devices['iPhone 12'], + // }, + // }, + + /* Test against branded browsers. */ + // { + // name: 'Microsoft Edge', + // use: { + // channel: 'msedge', + // }, + // }, + // { + // name: 'Google Chrome', + // use: { + // channel: 'chrome', + // }, + // }, + ], + + /* Folder for test artifacts such as screenshots, videos, traces, etc. */ + // outputDir: 'test-results/', + + /* Run your local dev server before starting the tests */ + // webServer: { + // command: 'npm run start', + // port: 3000, + // }, +}); diff --git a/crates/www/end2end/tests/example.spec.ts b/crates/www/end2end/tests/example.spec.ts new file mode 100644 index 00000000..0139fc30 --- /dev/null +++ b/crates/www/end2end/tests/example.spec.ts @@ -0,0 +1,9 @@ +import { test, expect } from "@playwright/test"; + +test("homepage has title and heading text", async ({ page }) => { + await page.goto("http://localhost:3000/"); + + await expect(page).toHaveTitle("Welcome to Leptos"); + + await expect(page.locator("h1")).toHaveText("Welcome to Leptos!"); +}); diff --git a/crates/www/end2end/tsconfig.json b/crates/www/end2end/tsconfig.json new file mode 100644 index 00000000..e075f973 --- /dev/null +++ b/crates/www/end2end/tsconfig.json @@ -0,0 +1,109 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/crates/www/public/_redirects b/crates/www/public/_redirects new file mode 100644 index 00000000..c546bae3 --- /dev/null +++ b/crates/www/public/_redirects @@ -0,0 +1,14 @@ +/post/codeblocks,-mdx,-and-mdx-utils /post/codeblocks-mdx-and-mdx-utils +/post/design-systems-people,-processes,-and-emergent-behavior /post/design-systems-people-processes-and-emergent-behavior +/post/gatsby-themes,-webpack-loaders,-and-npm-packages /post/gatsby-themes-webpack-loaders-and-npm-packages +/post/kafka,-kube,-and-statefulsets-on-gke /post/kafka-kube-and-statefulsets-on-gke +/post/notes-on-parsing-the-graph-ql-sdl /post/notes-on-parsing-the-graphql-sdl +/posts /post +/post/manipulating-gatsby-page-context-with-on-create-page /post/manipulating-gatsby-page-context-with-oncreatepage +/post/a-first-look-at-fauna-db /post/a-first-look-at-faunadb +/post/using-mdxp-rovider-host-elements-in-react-live-scope /post/using-mdxprovider-host-elements-in-react-live-scope +/post/creating-mdx-nodes-from-raw-strings /post/creating-mdx-nodes-from-raw-strings-and-nodes +/post/if-you-can-t-delete-code-then-you-re-stuck-with-it /post/if-you-cant-delete-code-then-youre-stuck-with-it +/post/shipping-multi-package-repos-with-git-hub-actions-changesets-and-lerna /post/shipping-multipackage-repos-with-github-actions-changesets-and-lerna +/feed /rss.xml +/rss /rss.xml \ No newline at end of file diff --git a/crates/www/public/favicon.ico b/crates/www/public/favicon.ico new file mode 100644 index 00000000..00eb0877 Binary files /dev/null and b/crates/www/public/favicon.ico differ diff --git a/crates/www/public/logos/logo-c-mask.svg b/crates/www/public/logos/logo-c-mask.svg new file mode 100644 index 00000000..969c1232 --- /dev/null +++ b/crates/www/public/logos/logo-c-mask.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/crates/www/public/logos/logo-circle.svg b/crates/www/public/logos/logo-circle.svg new file mode 100644 index 00000000..0221dc53 --- /dev/null +++ b/crates/www/public/logos/logo-circle.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/crates/www/public/logos/logo-full.svg b/crates/www/public/logos/logo-full.svg new file mode 100644 index 00000000..396fbac4 --- /dev/null +++ b/crates/www/public/logos/logo-full.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/crates/www/public/logos/logo-rounded.svg b/crates/www/public/logos/logo-rounded.svg new file mode 100644 index 00000000..4709db1a --- /dev/null +++ b/crates/www/public/logos/logo-rounded.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/crates/www/public/logos/rust.svg b/crates/www/public/logos/rust.svg new file mode 100644 index 00000000..9e2f0fd0 --- /dev/null +++ b/crates/www/public/logos/rust.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/crates/www/public/rust-adventure.svg b/crates/www/public/rust-adventure.svg new file mode 100644 index 00000000..d69c921a --- /dev/null +++ b/crates/www/public/rust-adventure.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/crates/www/public/textures/binding-light.png b/crates/www/public/textures/binding-light.png new file mode 100644 index 00000000..c41860c2 Binary files /dev/null and b/crates/www/public/textures/binding-light.png differ diff --git a/crates/www/public/textures/concrete-wall.png b/crates/www/public/textures/concrete-wall.png new file mode 100644 index 00000000..a0aeb0c9 Binary files /dev/null and b/crates/www/public/textures/concrete-wall.png differ diff --git a/crates/www/public/textures/cubes.png b/crates/www/public/textures/cubes.png new file mode 100644 index 00000000..cfd79110 Binary files /dev/null and b/crates/www/public/textures/cubes.png differ diff --git a/crates/www/public/textures/dot-grid.webp b/crates/www/public/textures/dot-grid.webp new file mode 100644 index 00000000..023a42d0 Binary files /dev/null and b/crates/www/public/textures/dot-grid.webp differ diff --git a/crates/www/public/textures/dust_scratches.webp b/crates/www/public/textures/dust_scratches.webp new file mode 100644 index 00000000..b40b6505 Binary files /dev/null and b/crates/www/public/textures/dust_scratches.webp differ diff --git a/crates/www/public/textures/micro_carbon.png b/crates/www/public/textures/micro_carbon.png new file mode 100644 index 00000000..2559affd Binary files /dev/null and b/crates/www/public/textures/micro_carbon.png differ diff --git a/crates/www/public/textures/tactile_noise.webp b/crates/www/public/textures/tactile_noise.webp new file mode 100644 index 00000000..08b8f681 Binary files /dev/null and b/crates/www/public/textures/tactile_noise.webp differ diff --git a/crates/www/public/textures/webb.png b/crates/www/public/textures/webb.png new file mode 100644 index 00000000..bd444623 Binary files /dev/null and b/crates/www/public/textures/webb.png differ diff --git a/crates/www/src/app.rs b/crates/www/src/app.rs new file mode 100644 index 00000000..853ad8e0 --- /dev/null +++ b/crates/www/src/app.rs @@ -0,0 +1,56 @@ +use crate::{components::*, routes::index::IndexPage}; +use leptos::{html::Link, prelude::*}; +use leptos_meta::{ + provide_meta_context, MetaTags, Stylesheet, Title, +}; +use leptos_router::{ + components::{Route, Router, Routes}, + StaticSegment, +}; + +pub fn shell(options: LeptosOptions) -> impl IntoView { + view! { + + + + + + + + + + + + + + + + + } +} + +#[component] +pub fn App() -> impl IntoView { + // Provides context that manages stylesheets, + // titles, meta tags, etc. + provide_meta_context(); + + view! { + // injects a stylesheet into the document + // id=leptos means cargo-leptos will hot-reload this stylesheet + + + + + <ProgressBar/> + + <Router> + <main class="relative textured-bg"> + <Routes fallback=|| "Page not found.".into_view()> + <Route path=StaticSegment("") view=IndexPage/> + </Routes> + </main> + </Router> + <Footer/> + } +} diff --git a/crates/www/src/components.rs b/crates/www/src/components.rs new file mode 100644 index 00000000..87623094 --- /dev/null +++ b/crates/www/src/components.rs @@ -0,0 +1,6 @@ +pub mod button; +pub mod footer; +pub mod progress_bar; + +pub use footer::Footer; +pub use progress_bar::ProgressBar; diff --git a/crates/www/src/components/button.rs b/crates/www/src/components/button.rs new file mode 100644 index 00000000..48a95e53 --- /dev/null +++ b/crates/www/src/components/button.rs @@ -0,0 +1,153 @@ +use leptos::prelude::*; +// use serde::{Deserialize, Serialize}; + +const SOLID_CLASSES: &str = concat!( + "rounded-md", + " ", + // "bg-indigo-600", + " ", + "px-2.5", + " ", + "py-1.5", + " ", + "text-sm", + " ", + "font-semibold", + " ", + // "text-ctp-text", + " ", + "shadow-sm", + " ", + // "hover:bg-indigo-500", + " ", + "focus-visible:outline", + " ", + "focus-visible:outline-2", + " ", + "focus-visible:outline-offset-2", + " ", + // "focus-visible:outline-indigo-600", +); + +#[component] +pub fn Button( + #[prop(optional)] variant: Variant, + color: ButtonColor, + #[prop(into)] on_click: Callback<(), ()>, + children: Children, +) -> impl IntoView { + let classes = match variant { + Variant::Solid => { + format!("{SOLID_CLASSES} {} hover:bg-white/10, focus-visible:outline-{} text-white dark:text-black", color.bg(), color.as_str()) + } + Variant::Outline => todo!(), + Variant::Ghost => todo!(), + }; + + view! { + <button + type="button" + on:click=move |_| on_click(()) + class=classes> + {children()} + </button> + } +} + +#[derive(Default)] +pub enum Variant { + #[default] + Solid, + Outline, + Ghost, +} + +pub enum ButtonColor { + ROSEWATER, + FLAMINGO, + PINK, + MAUVE, + RED, + MAROON, + PEACH, + YELLOW, + GREEN, + TEAL, + SKY, + SAPPHIRE, + BLUE, + LAVENDER, + // social colors + TWITTER, + YOUTUBE, + MASTODON, +} + +impl ButtonColor { + fn bg(&self) -> &str { + match self { + ButtonColor::ROSEWATER => "bg-ctp-rosewater", + ButtonColor::FLAMINGO => "bg-ctp-flamingo", + ButtonColor::PINK => "bg-ctp-pink", + ButtonColor::MAUVE => "bg-ctp-mauve", + ButtonColor::RED => "bg-ctp-red", + ButtonColor::MAROON => "bg-ctp-maroon", + ButtonColor::PEACH => "bg-ctp-peach", + ButtonColor::YELLOW => "bg-ctp-yellow", + ButtonColor::GREEN => "bg-ctp-green", + ButtonColor::TEAL => "bg-ctp-teal", + ButtonColor::SKY => "bg-ctp-sky", + ButtonColor::SAPPHIRE => "bg-ctp-sapphire", + ButtonColor::BLUE => "bg-ctp-blue", + ButtonColor::LAVENDER => "bg-ctp-lavender", + + ButtonColor::TWITTER => todo!(), + ButtonColor::YOUTUBE => todo!(), + ButtonColor::MASTODON => todo!(), + } + } + fn as_str(&self) -> &str { + match self { + ButtonColor::ROSEWATER => "ctp-rosewater", + ButtonColor::FLAMINGO => "ctp-flamingo", + ButtonColor::PINK => "ctp-pink", + ButtonColor::MAUVE => "ctp-mauve", + ButtonColor::RED => "ctp-red", + ButtonColor::MAROON => "ctp-maroon", + ButtonColor::PEACH => "ctp-peach", + ButtonColor::YELLOW => "ctp-yellow", + ButtonColor::GREEN => "ctp-green", + ButtonColor::TEAL => "ctp-teal", + ButtonColor::SKY => "ctp-sky", + ButtonColor::SAPPHIRE => "ctp-sapphire", + ButtonColor::BLUE => "ctp-blue", + ButtonColor::LAVENDER => "ctp-lavender", + + ButtonColor::TWITTER => todo!(), + ButtonColor::YOUTUBE => todo!(), + ButtonColor::MASTODON => todo!(), + } + } + fn outline(&self) -> &str { + match self { + ButtonColor::ROSEWATER => "bg-ctp-rosewater", + ButtonColor::FLAMINGO => "bg-ctp-flamingo", + ButtonColor::PINK => "bg-ctp-pink", + ButtonColor::MAUVE => "bg-ctp-mauve", + ButtonColor::RED => "bg-ctp-red", + ButtonColor::MAROON => "bg-ctp-maroon", + ButtonColor::PEACH => "bg-ctp-peach", + ButtonColor::YELLOW => "bg-ctp-yellow", + ButtonColor::GREEN => "bg-ctp-green", + ButtonColor::TEAL => "bg-ctp-teal", + ButtonColor::SKY => "bg-ctp-sky", + ButtonColor::SAPPHIRE => "bg-ctp-sapphire", + ButtonColor::BLUE => "bg-ctp-blue", + ButtonColor::LAVENDER => "bg-ctp-lavender", + + ButtonColor::TWITTER => todo!(), + ButtonColor::YOUTUBE => todo!(), + ButtonColor::MASTODON => todo!(), + } + } +} diff --git a/crates/www/src/components/footer.rs b/crates/www/src/components/footer.rs new file mode 100644 index 00000000..bad348f3 --- /dev/null +++ b/crates/www/src/components/footer.rs @@ -0,0 +1,173 @@ +use leptos::prelude::*; + +#[component] +pub fn Footer() -> impl IntoView { + view! { + <div + class="main-header-darken" + style=" + background-image: linear-gradient(153deg, rgba(152, 152, 152, 0.03) 0%, rgba(152, 152, 152, 0.03) 9%, rgba(197, 197, 197, 0.03) 9%, rgba(197, 197, 197, 0.03) 21%, rgba(106, 106, 106, 0.03) 21%, rgba(106, 106, 106, 0.03) 32%, rgba(222, 222, 222, 0.03) 32%, rgba(222, 222, 222, 0.03) 72%, rgba(16, 16, 16, 0.03) 72%, rgba(16, 16, 16, 0.03) 92%, rgba(181, 181, 181, 0.03) 92%, rgba(181, 181, 181, 0.03) 97%, rgba(130, 130, 130, 0.03) 97%, rgba(130, 130, 130, 0.03) 100%), linear-gradient(39deg, rgba(237, 237, 237, 0.03) 0%, rgba(237, 237, 237, 0.03) 22%, rgba(126, 126, 126, 0.03) 22%, rgba(126, 126, 126, 0.03) 55%, rgba(196, 196, 196, 0.03) 55%, rgba(196, 196, 196, 0.03) 61%, rgba(121, 121, 121, 0.03) 61%, rgba(121, 121, 121, 0.03) 71%, rgba(133, 133, 133, 0.03) 71%, rgba(133, 133, 133, 0.03) 84%, rgba(132, 132, 132, 0.03) 84%, rgba(132, 132, 132, 0.03) 97%, rgba(185, 185, 185, 0.03) 97%, rgba(185, 185, 185, 0.03) 100%), linear-gradient(124deg, rgba(168, 168, 168, 0.03) 0%, rgba(168, 168, 168, 0.03) 7%, rgba(169, 169, 169, 0.03) 7%, rgba(169, 169, 169, 0.03) 19%, rgba(73, 73, 73, 0.03) 19%, rgba(73, 73, 73, 0.03) 50%, rgba(150, 150, 150, 0.03) 50%, rgba(150, 150, 150, 0.03) 67%, rgba(68, 68, 68, 0.03) 67%, rgba(68, 68, 68, 0.03) 81%, rgba(111, 111, 111, 0.03) 81%, rgba(111, 111, 111, 0.03) 91%, rgba(191, 191, 191, 0.03) 91%, rgba(191, 191, 191, 0.03) 100%), linear-gradient(95deg, rgba(147, 147, 147, 0.03) 0%, rgba(147, 147, 147, 0.03) 17%, rgba(79, 79, 79, 0.03) 17%, rgba(79, 79, 79, 0.03) 27%, rgba(28, 28, 28, 0.03) 27%, rgba(28, 28, 28, 0.03) 45%, rgba(27, 27, 27, 0.03) 45%, rgba(27, 27, 27, 0.03) 56%, rgba(228, 228, 228, 0.03) 56%, rgba(228, 228, 228, 0.03) 64%, rgba(38, 38, 38, 0.03) 64%, rgba(38, 38, 38, 0.03) 72%, rgba(42, 42, 42, 0.03) 72%, rgba(42, 42, 42, 0.03) 100%), linear-gradient(346deg, rgba(59, 59, 59, 0.03) 0%, rgba(59, 59, 59, 0.03) 16%, rgba(66, 66, 66, 0.03) 16%, rgba(66, 66, 66, 0.03) 20%, rgba(236, 236, 236, 0.03) 20%, rgba(236, 236, 236, 0.03) 41%, rgba(244, 244, 244, 0.03) 41%, rgba(244, 244, 244, 0.03) 55%, rgba(106, 106, 106, 0.03) 55%, rgba(106, 106, 106, 0.03) 61%, rgba(220, 220, 220, 0.03) 61%, rgba(220, 220, 220, 0.03) 63%, rgba(209, 209, 209, 0.03) 63%, rgba(209, 209, 209, 0.03) 100%), linear-gradient(124deg, rgba(255, 36, 0, 0.17), rgba(232, 29, 29, 0.17), rgba(232, 183, 29, 0.17), rgba(227, 232, 29, 0.17), rgba(29, 232, 64, 0.17), rgba(29, 221, 232, 0.17), rgba(43, 29, 232, 0.17), rgba(221, 0, 243, 0.17), rgba(221, 0, 243, 0.17)) + " + > + + // <ConvertKitForm /> + + <footer class="mix-blend-color-dodge"> + <div class="max-w-screen-xl mx-auto py-12 px-4 sm:px-6 lg:py-16 lg:px-8"> + <div class="xl:grid xl:grid-cols-3 xl:gap-8"> + <div class="grid grid-cols-2 gap-8 xl:col-span-2"> + <div class="md:grid md:grid-cols-2 md:gap-8"> + <div> + <h4 class="text-sm leading-5 font-semibold text-gray-400 tracking-wider uppercase"> + I Cover + </h4> + <ul class="mt-4 space-y-4"> + <li> + <a + href="/game-development" + class="text-base leading-6 text-gray-300 hover:text-white" + > + Game Development + </a> + </li> + <li> + <a + href="/rust" + class="text-base leading-6 text-ctp-text hover:text-white" + > + Rust + </a> + </li> + <li> + <a + href="/wasm" + class="text-base leading-6 text-ctp-text hover:text-white" + > + Wasm + </a> + </li> + {/* <li> + <a + href="#" + class="text-base leading-6 text-gray-300 hover:text-white" + > + The <span class="text-pink-300">Edge</span> Newsletter + </a> + </li> */} + </ul> + </div> + <div class="mt-12 md:mt-0"> + <h4 class="text-sm leading-5 font-semibold text-gray-400 tracking-wider uppercase"> + I Make + </h4> + <ul class="mt-4 space-y-4"> + <li> + <a + href="https://rustadventure.dev" + class="text-base leading-6 text-gray-300 hover:text-white" + > + Rust Adventure + </a> + </li> + <li> + <a + href="https://thisweekinbevy.com" + class="text-base leading-6 text-gray-300 hover:text-white" + > + This Week in Bevy Engine + </a> + </li> + <li> + <a + href="https://pages.convertkit.com/04c24646a3/c136f814fc" + class="text-ctp-red leading-6 text-gray-300 hover:text-white" + > + <span class="text-blue-300">Personal</span> Newsletter + </a> + </li> + // <li> + // <a + // href="https://sector.tools/" + // class="text-base leading-6 text-gray-300 hover:text-white" + // > + // Sector Tools + // </a> + // </li> + </ul> + </div> + </div> + <div class="md:grid md:grid-cols-2 md:gap-8"> + <div class="mt-12 md:mt-0"> + <h4 class="text-sm leading-5 font-semibold text-gray-400 tracking-wider uppercase"> + I Exist + </h4> + <ul class="mt-4 space-y-4"> + <li> + <a + href="https://www.youtube.com/@chrisbiscardi" + class="text-base leading-6 text-gray-300 hover:text-brand-youtube" + > + YouTube + </a> + </li> + <li> + <a + href="https://hachyderm.io/@chrisbiscardi" + class="text-base leading-6 text-gray-300 hover:text-brand-mastodon" + > + Mastodon + </a> + </li> + + </ul> + </div> + </div> + </div> + </div> + <div class="mt-8 border-t border-gray-500 pt-8 md:flex md:items-center md:justify-between"> + <div class="flex space-x-6 md:order-2"> + <a + href="https://twitter.com/chrisbiscardi" + class="text-gray-400 hover:text-gray-300" + > + <span class="sr-only">Twitter</span> + <svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24"> + <path d="M8.29 20.251c7.547 0 11.675-6.253 11.675-11.675 0-.178 0-.355-.012-.53A8.348 8.348 0 0022 5.92a8.19 8.19 0 01-2.357.646 4.118 4.118 0 001.804-2.27 8.224 8.224 0 01-2.605.996 4.107 4.107 0 00-6.993 3.743 11.65 11.65 0 01-8.457-4.287 4.106 4.106 0 001.27 5.477A4.072 4.072 0 012.8 9.713v.052a4.105 4.105 0 003.292 4.022 4.095 4.095 0 01-1.853.07 4.108 4.108 0 003.834 2.85A8.233 8.233 0 012 18.407a11.616 11.616 0 006.29 1.84" /> + </svg> + </a> + <a + href="https://github.com/christopherbiscardi/" + class="text-gray-400 hover:text-gray-300" + > + <span class="sr-only">GitHub</span> + <svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24"> + <path + fill-rule="evenodd" + d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" + clip-rule="evenodd" + /> + </svg> + </a> + <a + href="https://dribbble.com/chrisbiscardi" + class="text-gray-400 hover:text-gray-300" + > + <span class="sr-only">Dribbble</span> + <svg class="h-6 w-6" fill="currentColor" viewBox="0 0 24 24"> + <path + fill-rule="evenodd" + d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10c5.51 0 10-4.48 10-10S17.51 2 12 2zm6.605 4.61a8.502 8.502 0 011.93 5.314c-.281-.054-3.101-.629-5.943-.271-.065-.141-.12-.293-.184-.445a25.416 25.416 0 00-.564-1.236c3.145-1.28 4.577-3.124 4.761-3.362zM12 3.475c2.17 0 4.154.813 5.662 2.148-.152.216-1.443 1.941-4.48 3.08-1.399-2.57-2.95-4.675-3.189-5A8.687 8.687 0 0112 3.475zm-3.633.803a53.896 53.896 0 013.167 4.935c-3.992 1.063-7.517 1.04-7.896 1.04a8.581 8.581 0 014.729-5.975zM3.453 12.01v-.26c.37.01 4.512.065 8.775-1.215.25.477.477.965.694 1.453-.109.033-.228.065-.336.098-4.404 1.42-6.747 5.303-6.942 5.629a8.522 8.522 0 01-2.19-5.705zM12 20.547a8.482 8.482 0 01-5.239-1.8c.152-.315 1.888-3.656 6.703-5.337.022-.01.033-.01.054-.022a35.318 35.318 0 011.823 6.475 8.4 8.4 0 01-3.341.684zm4.761-1.465c-.086-.52-.542-3.015-1.659-6.084 2.679-.423 5.022.271 5.314.369a8.468 8.468 0 01-3.655 5.715z" + clip-rule="evenodd" + /> + </svg> + </a> + </div> + <p class="mt-8 text-base leading-6 text-gray-400 md:mt-0 md:order-1"> + Built with <a href="https://leptos.dev/">Leptos</a>, <a href="https://github.com/tokio-rs/axum">Axum</a>, and Wasm + </p> + </div> + </div> + </footer> + </div> + } +} diff --git a/crates/www/src/components/progress_bar.rs b/crates/www/src/components/progress_bar.rs new file mode 100644 index 00000000..50978b83 --- /dev/null +++ b/crates/www/src/components/progress_bar.rs @@ -0,0 +1,160 @@ +use leptos::prelude::*; +use leptos_use::{use_event_listener, use_window}; + +const STYLES: &str = "#top-progress { + background: #11151da6; + } + #top-progress::-webkit-progress-value { + background: linear-gradient( + 124deg, + #ff2400, + #e81d1d, + #e8b71d, + #e3e81d, + #1de840, + #1ddde8, + #2b1de8, + #dd00f3, + #dd00f3 + ); + background-size: 100vw; + opacity: 0.4; + } + #top-progress::-webkit-progress-bar { + background: transparent; + opacity: 1; + } + #top-progress::-moz-progress-bar { + background: linear-gradient( + 124deg, + #ff2400, + #e81d1d, + #e8b71d, + #e3e81d, + #1de840, + #1ddde8, + #2b1de8, + #dd00f3, + #dd00f3 + ); + background-size: 100vw; + opacity: 0.4; + }"; + +fn get_indicator_percentage_width( + current_pos: f64, + total_scroll: f64, +) -> f64 { + (current_pos / total_scroll) * 100. +} + +#[component] +pub fn ProgressBar() -> impl IntoView { + let scroll_position_percentage = RwSignal::new(0.); + + #[cfg(not(feature = "ssr"))] + Effect::watch( + move || {}, + move |_, _, _| { + let _ = use_event_listener( + use_window(), + leptos::ev::scroll, + move |_| { + log!("click from element"); + + let Some(ref window) = *use_window() + else { + return; + }; + + let current_pos = + window.scroll_y().unwrap(); + let inner_height = window + .inner_height() + .unwrap() + .as_f64() + .unwrap_or(0.); + let scroll_height = get_scroll_height(); + let scroll_distance = + scroll_height as f64 - inner_height; + + let indicator_width = + get_indicator_percentage_width( + current_pos, + scroll_distance, + ); + + scroll_position_percentage + .set(indicator_width); + }, + ); + + let win = use_window(); + let window = win.as_ref().clone().unwrap(); + + let inner_height = window + .inner_height() + .unwrap() + .as_f64() + .unwrap_or(0.); + let scroll_height = get_scroll_height(); + let scroll_distance = + scroll_height as f64 - inner_height; + let indicator_width = + get_indicator_percentage_width( + window.scroll_y().unwrap(), + scroll_distance, + ); + + scroll_position_percentage.set(indicator_width); + }, + false, + ); + + view! { + <> + <style>{STYLES}</style> + <progress + id="top-progress" + class="z-50 fixed top-0 left-0 appearance-none w-full h-1 opacity-100" + // value={isNaN(scroll_position_pecentage) ? 100. : scroll_position_pecentage} + value=scroll_position_percentage + max="100" + > + 70 % + </progress> + </> + } +} + +#[cfg(not(feature = "ssr"))] +// find the total height of window +fn get_scroll_height() -> i32 { + let win = use_window(); + let document = win.document(); + // https://javascript.info/size-and-scroll-window#width-height-of-the-document + *[ + document.body().unwrap().scroll_height(), + document + .as_ref() + .unwrap() + .document_element() + .unwrap() + .scroll_height(), + document.body().unwrap().offset_height(), + // document + // .document_element() + // .unwrap() + // .offset_height(), + document.body().unwrap().client_height(), + document + .as_ref() + .unwrap() + .document_element() + .unwrap() + .client_height(), + ] + .iter() + .max() + .unwrap() +} diff --git a/crates/www/src/lib.rs b/crates/www/src/lib.rs new file mode 100644 index 00000000..e4cabbab --- /dev/null +++ b/crates/www/src/lib.rs @@ -0,0 +1,12 @@ +pub mod app; +mod components; +mod routes; + +#[cfg(feature = "hydrate")] +#[wasm_bindgen::prelude::wasm_bindgen] +pub fn hydrate() { + use crate::app::*; + console_error_panic_hook::set_once(); + // leptos::mount::hydrate_body(App); + leptos::mount::hydrate_islands(); +} diff --git a/crates/www/src/main.rs b/crates/www/src/main.rs new file mode 100644 index 00000000..d6bfe8af --- /dev/null +++ b/crates/www/src/main.rs @@ -0,0 +1,38 @@ + +#[cfg(feature = "ssr")] +#[tokio::main] +async fn main() { + use axum::Router; + use leptos::prelude::*; + use leptos_axum::{generate_route_list, LeptosRoutes}; + use www::app::*; + + let conf = get_configuration(None).unwrap(); + let addr = conf.leptos_options.site_addr; + let leptos_options = conf.leptos_options; + // Generate the list of routes in your Leptos App + let routes = generate_route_list(App); + + let app = Router::new() + .leptos_routes(&leptos_options, routes, { + let leptos_options = leptos_options.clone(); + move || shell(leptos_options.clone()) + }) + .fallback(leptos_axum::file_and_error_handler(shell)) + .with_state(leptos_options); + + // run our app with hyper + // `axum::Server` is a re-export of `hyper::Server` + log!("listening on http://{}", &addr); + let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); + axum::serve(listener, app.into_make_service()) + .await + .unwrap(); +} + +#[cfg(not(feature = "ssr"))] +pub fn main() { + // no client-side main function + // unless we want this to work with e.g., Trunk for pure client-side testing + // see lib.rs for hydration function instead +} diff --git a/crates/www/src/routes.rs b/crates/www/src/routes.rs new file mode 100644 index 00000000..33edc959 --- /dev/null +++ b/crates/www/src/routes.rs @@ -0,0 +1 @@ +pub mod index; diff --git a/crates/www/src/routes/index.rs b/crates/www/src/routes/index.rs new file mode 100644 index 00000000..898b665f --- /dev/null +++ b/crates/www/src/routes/index.rs @@ -0,0 +1,303 @@ +use leptos::{either::Either, prelude::*}; +// use sens8::button::*; + +#[component] +fn BentoBox<'a>( + #[prop(optional)] border_gradient: &'a str, + bg: Option<&'a str>, + image_header: Option<&'a str>, + #[prop(default = 2.)] speed: f64, + children: Children, +) -> impl IntoView + 'a { + let mut style = "".to_string(); + if !border_gradient.is_empty() { + style.push_str("--border-gradient: "); + style.push_str(border_gradient); + style.push_str(" border-box; "); + }; + if let Some(bg) = bg { + style.push_str("--bg-grad: "); + style.push_str(bg); + style.push_str(" padding-box;"); + }; + let mut container_style = "".to_string(); + container_style.push_str("--border-speed: "); + container_style.push_str(&speed.to_string()); + container_style.push_str(";"); + view! { + <div + style=container_style + class="bento-container h-full" + > + <div + style=style + class="bento-box h-full" + > + { + if let Some(src) = image_header { + Either::Left(view!{ + <img + class="img-header" + src=src + /> + }) + } else { + Either::Right(view!("")) + } + } + {children()} + </div> + </div> + } +} + +#[derive(Clone)] +struct BentoBoxContent<'a> { + title: &'a str, + content: &'a str, + bg: Option<&'a str>, + border_gradient: Option<&'a str>, + speed: f64, + center_title: bool, + image_header: Option<&'a str>, +} +impl<'a> Default for BentoBoxContent<'a> { + fn default() -> Self { + Self { + title: Default::default(), + content: Default::default(), + bg: Default::default(), + border_gradient: Default::default(), + speed: 2., + center_title: false, + image_header: None, + } + } +} + +#[component] +pub fn IndexPage() -> impl IntoView { + let boxes = RwSignal::new( + vec![ + BentoBoxContent { + title: "Bevy", + content: "svg-bevy", + bg: Some("linear-gradient(-45deg, #232326, #1e1e22)"), + // bg: Some("url('')"), + border_gradient: Some("conic-gradient( from calc(180deg + var(--angle)) at 50% 70%, #1e1e22, #ececec)"), + image_header: Some("https://res.cloudinary.com/dilgcuzda/image/upload/v1723431989/thisweekinbevy/01J528TBS3A73AHPN9KHWGJ7T0.avif"), + ..Default::default() + }, + BentoBoxContent { + title: "", + content: "wasm", + bg: None, + // 38.0 30.0 92.0 #624DEA + border_gradient: Some("conic-gradient( from calc(180deg + var(--angle)) at 50% 70%, #624DEA, #ded9fb)"), + center_title: true, + image_header: Some("/img/wasm-heading.avif"), + ..Default::default() + }, + BentoBoxContent { + title: "Shaders", + content: "svg-art", + bg: None, + border_gradient: None, + + ..Default::default() + }, + BentoBoxContent { + title: "Rust Adventure", + content: "learn something and do some rust stuff", + bg: Some("linear-gradient(-45deg, #2e1e1e 0%, var(--ctp-base) 60%)"), + border_gradient: Some("conic-gradient( from calc(180deg + var(--angle)) at 50% 70%, #2e1e1e, var(--ctp-red))"), + speed: 10., + center_title: true, + ..Default::default() + }, + BentoBoxContent { + title: "Something", + content: "svg-hex", + bg: None, + border_gradient: Some("conic-gradient( from calc(180deg + var(--angle)) at 50% 70%, hsl(265, 55%, 30%), hsl(265, 55%, 60%))"), + ..Default::default() + }, + BentoBoxContent { + title: "YouTube", + content: "YouTube", + bg: None, + border_gradient: None, + ..Default::default() + }, + BentoBoxContent { + title: "YouTube", + content: "YouTube", + bg: None, + border_gradient: Some("conic-gradient( + from calc(180deg + var(--angle)) at 50% 70%, + #e8b71d55, + #e81d1d55, + #ff240055 + )"), + ..Default::default() + }, + BentoBoxContent { + title: "YouTube", + content: "YouTube", + bg: None, + border_gradient: None, + ..Default::default() + }, + ] + .into_iter() + .enumerate() + .collect::<Vec<(usize, BentoBoxContent)>>(), + ); + view! { + <Hero/> + <div class="grid grid-cols-3 gap-4 mx-auto max-w-7xl sm:px-6 lg:px-8 py-14"> + <For + // a function that returns the items we're iterating over; a signal is fine + each=move || boxes.get() + // a unique key for each item + key=|boxy| boxy.0.to_string() + // renders each item to a view + // min-h-24 min-h-32 min-h-36 min-h-16 min-h-64 + children=move |(index, content)| { + view! { + <div + class=format!( + "row-span-1 {}", + // "row-span-1 rounded-xl border-2 border-slate-400/10 bg-neutral-100 p-4 dark:bg-ctp-surface0 min-h-full {}", + if index == 3 || index == 6 { + "col-span-2" + } else { + "" + }) + > + <BentoBox + border_gradient=content.border_gradient.unwrap_or("") + bg=content.bg + speed=content.speed + image_header=content.image_header + > + <p class=format!("text-2xl font-bold leading-7 text-ctp-text sm:truncate sm:text-3xl sm:tracking-tight {}", + if content.center_title { + "text-center" + } else { + "" + } + )>{content.title}</p> + { + if content.content == "svg-art" { + view!{ + <span class="text-ctp-text"> + wgpu and wgsl + </span> + }.into_any() + } else if content.content == "svg-hex" { + view! { + <span> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 800"><defs><filter id="b" width="400%" height="400%" x="-100%" y="-100%" color-interpolation-filters="sRGB" filterUnits="objectBoundingBox" primitiveUnits="userSpaceOnUse"><feGaussianBlur width="100%" height="100%" x="0%" y="0%" in="SourceGraphic" result="blur" stdDeviation="17 8"/></filter><filter id="c" width="400%" height="400%" x="-100%" y="-100%" color-interpolation-filters="sRGB" filterUnits="objectBoundingBox" primitiveUnits="userSpaceOnUse"><feGaussianBlur width="100%" height="100%" x="0%" y="0%" in="SourceGraphic" result="blur" stdDeviation="10 17"/></filter><linearGradient id="a" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="hsl(265, 55%, 30%)"/><stop offset="100%" stop-color="hsl(265, 55%, 60%)"/></linearGradient></defs><g fill="none" stroke="url(#a)" stroke-width="16"><path d="M388.453 233.461a23.095 23.095 0 0 1 23.094.001l126.906 73.27A23.093 23.093 0 0 1 550 326.73v146.538c0 8.25-4.402 15.875-11.547 20l-126.906 73.27a23.095 23.095 0 0 1-23.094-.001l-126.906-73.27A23.093 23.093 0 0 1 250 473.27V326.731c0-8.25 4.402-15.875 11.547-20l126.906-73.27Z" filter="url(#b)"/><path d="M400.453 233.461a23.095 23.095 0 0 1 23.094.001l126.906 73.27A23.093 23.093 0 0 1 562 326.73v146.538c0 8.25-4.402 15.875-11.547 20l-126.906 73.27a23.095 23.095 0 0 1-23.094-.001l-126.906-73.27A23.093 23.093 0 0 1 262 473.27V326.731c0-8.25 4.402-15.875 11.547-20l126.906-73.27Z" filter="url(#c)" opacity=".25"/><path d="M376.453 233.461a23.095 23.095 0 0 1 23.094.001l126.906 73.27A23.093 23.093 0 0 1 538 326.73v146.538c0 8.25-4.402 15.875-11.547 20l-126.906 73.27a23.095 23.095 0 0 1-23.094-.001l-126.906-73.27A23.093 23.093 0 0 1 238 473.27V326.731c0-8.25 4.402-15.875 11.547-20l126.906-73.27Z" filter="url(#c)" opacity=".25"/><path d="M388.453 233.461a23.095 23.095 0 0 1 23.094.001l126.906 73.27A23.093 23.093 0 0 1 550 326.73v146.538c0 8.25-4.402 15.875-11.547 20l-126.906 73.27a23.095 23.095 0 0 1-23.094-.001l-126.906-73.27A23.093 23.093 0 0 1 250 473.27V326.731c0-8.25 4.402-15.875 11.547-20l126.906-73.27Z"/></g></svg> + </span> + }.into_any() + } else if content.content == "svg-bevy" { + view! { + <span> + game development + </span> + }.into_any() + } else if content.content == "wasm" { + view! { + <div class="visible-on-hover text-slate-900"> + <h2 class="outfit-900"> + <a href="/wasm" class="focus:outline-none"> + <span class="absolute inset-0 z-1" aria-hidden="true"></span> + Wasm + </a> + </h2> + <span class="drop-shadow-2xl"> + Webassembly, Leptos, Rust, and more... + </span> + </div> + }.into_any() + } else { + view!{ + <span> + // <p class="text-ctp-text">{content.content}</p> + <svg/> + </span> + }.into_any() + } + } + </BentoBox> + </div> + } + } + /> + </div> + } +} + +#[component] +pub fn Hero() -> impl IntoView { + return view! { + <div + class="relative main-header-darken" + style= + "background-image: linear-gradient(153deg, rgba(152, 152, 152, 0.03) 0%, rgba(152, 152, 152, 0.03) 9%,rgba(197, 197, 197, 0.03) 9%, rgba(197, 197, 197, 0.03) 21%,rgba(106, 106, 106, 0.03) 21%, rgba(106, 106, 106, 0.03) 32%,rgba(222, 222, 222, 0.03) 32%, rgba(222, 222, 222, 0.03) 72%,rgba(16, 16, 16, 0.03) 72%, rgba(16, 16, 16, 0.03) 92%,rgba(181, 181, 181, 0.03) 92%, rgba(181, 181, 181, 0.03) 97%,rgba(130, 130, 130, 0.03) 97%, rgba(130, 130, 130, 0.03) 100%),linear-gradient(39deg, rgba(237, 237, 237, 0.03) 0%, rgba(237, 237, 237, 0.03) 22%,rgba(126, 126, 126, 0.03) 22%, rgba(126, 126, 126, 0.03) 55%,rgba(196, 196, 196, 0.03) 55%, rgba(196, 196, 196, 0.03) 61%,rgba(121, 121, 121, 0.03) 61%, rgba(121, 121, 121, 0.03) 71%,rgba(133, 133, 133, 0.03) 71%, rgba(133, 133, 133, 0.03) 84%,rgba(132, 132, 132, 0.03) 84%, rgba(132, 132, 132, 0.03) 97%,rgba(185, 185, 185, 0.03) 97%, rgba(185, 185, 185, 0.03) 100%),linear-gradient(124deg, rgba(168, 168, 168, 0.03) 0%, rgba(168, 168, 168, 0.03) 7%,rgba(169, 169, 169, 0.03) 7%, rgba(169, 169, 169, 0.03) 19%,rgba(73, 73, 73, 0.03) 19%, rgba(73, 73, 73, 0.03) 50%,rgba(150, 150, 150, 0.03) 50%, rgba(150, 150, 150, 0.03) 67%,rgba(68, 68, 68, 0.03) 67%, rgba(68, 68, 68, 0.03) 81%,rgba(111, 111, 111, 0.03) 81%, rgba(111, 111, 111, 0.03) 91%,rgba(191, 191, 191, 0.03) 91%, rgba(191, 191, 191, 0.03) 100%),linear-gradient(95deg, rgba(147, 147, 147, 0.03) 0%, rgba(147, 147, 147, 0.03) 17%,rgba(79, 79, 79, 0.03) 17%, rgba(79, 79, 79, 0.03) 27%,rgba(28, 28, 28, 0.03) 27%, rgba(28, 28, 28, 0.03) 45%,rgba(27, 27, 27, 0.03) 45%, rgba(27, 27, 27, 0.03) 56%,rgba(228, 228, 228, 0.03) 56%, rgba(228, 228, 228, 0.03) 64%,rgba(38, 38, 38, 0.03) 64%, rgba(38, 38, 38, 0.03) 72%,rgba(42, 42, 42, 0.03) 72%, rgba(42, 42, 42, 0.03) 100%),linear-gradient(346deg, rgba(59, 59, 59, 0.03) 0%, rgba(59, 59, 59, 0.03) 16%,rgba(66, 66, 66, 0.03) 16%, rgba(66, 66, 66, 0.03) 20%,rgba(236, 236, 236, 0.03) 20%, rgba(236, 236, 236, 0.03) 41%,rgba(244, 244, 244, 0.03) 41%, rgba(244, 244, 244, 0.03) 55%,rgba(106, 106, 106, 0.03) 55%, rgba(106, 106, 106, 0.03) 61%,rgba(220, 220, 220, 0.03) 61%, rgba(220, 220, 220, 0.03) 63%,rgba(209, 209, 209, 0.03) 63%, rgba(209, 209, 209, 0.03) 100%),linear-gradient(124deg, rgba(255, 36, 0, 0.17), rgba(232, 29, 29, 0.17), rgba(232, 183, 29, 0.17), rgba(227, 232, 29, 0.17), rgba(29, 232, 64, 0.17), rgba(29, 221, 232, 0.17), rgba(43, 29, 232, 0.17), rgba(221, 0, 243, 0.17), rgba(221, 0, 243, 0.17))" + > + <div class="relative max-w-7xl mx-auto py-24 px-4 sm:py-32 sm:px-6 lg:px-8"> + <h1 class="text-4xl font-extrabold tracking-tight text-white sm:text-5xl lg:text-6xl flex"> + "Hey, I'm Chris" + <img + style="height: 4rem" + class="sm:ml-4 outfit-900" + src="/img/party-corgi.gif" + alt="party corgi rainbow animated" + /> + </h1> + <p class="mt-6 text-xl text-indigo-100 max-w-3xl"> + I write about{" "} + <a class="text-red-400" href="/rust"> + Rust + </a>{", "} + JavaScript, and occassionally other languages. + This site is built with Leptos and Wasm. + The content is written in + <a class="text-blue-400" href="https://twitter.com/sectortools"> + Sector + </a> + . + </p> + <ul class="flex py-4 gap-x-2 mt-4"> + // <li class=""> + // <Button href="https://twitter.com/chrisbiscardi" + // color=ButtonColor::TWITTER + // icon="twitter"> + // Twitter + // </Button> + // </li> + // <li class=""> + // <Button + // href="https://www.youtube.com/channel/UCiSIL42pQRpc-8JNiYDFyzQ" + // color=ButtonColor::YOUTUBE + // icon="youtube" + // > + // YouTube + // </Button> + // </li> + // <li class=""> + // <SocialButton + // href="https://github.com/ChristopherBiscardi" + // icon="github" + // > + // GitHub + // </SocialButton> + // </li> + </ul> + {/* <LowerTilt /> */} + </div> + </div> + }; +} diff --git a/crates/www/style/input.css b/crates/www/style/input.css new file mode 100644 index 00000000..0f2b02ab --- /dev/null +++ b/crates/www/style/input.css @@ -0,0 +1,332 @@ +/* catppuccin variables */ +.ctp-latte { + --ctp-rosewater: rgb(220, 138, 120); + --ctp-flamingo: rgb(221, 120, 120); + --ctp-pink: rgb(234, 118, 203); + --ctp-mauve: rgb(136, 57, 239); + --ctp-red: rgb(210, 15, 57); + --ctp-maroon: rgb(230, 69, 83); + --ctp-peach: rgb(254, 100, 11); + --ctp-yellow: rgb(223, 142, 29); + --ctp-green: rgb(64, 160, 43); + --ctp-teal: rgb(23, 146, 153); + --ctp-sky: rgb(4, 165, 229); + --ctp-sapphire: rgb(32, 159, 181); + --ctp-blue: rgb(30, 102, 245); + --ctp-lavender: rgb(114, 135, 253); + --ctp-text: rgb(76, 79, 105); + --ctp-subtext1: rgb(92, 95, 119); + --ctp-subtext0: rgb(108, 111, 133); + --ctp-overlay2: rgb(124, 127, 147); + --ctp-overlay1: rgb(140, 143, 161); + --ctp-overlay0: rgb(156, 160, 176); + --ctp-surface2: rgb(172, 176, 190); + --ctp-surface1: rgb(188, 192, 204); + --ctp-surface0: rgb(204, 208, 218); + --ctp-base: rgb(239, 241, 245); + --ctp-mantle: rgb(230, 233, 239); + --ctp-crust: rgb(220, 224, 232); +} +.ctp-frappe { + --ctp-rosewater: rgb(242, 213, 207); + --ctp-flamingo: rgb(238, 190, 190); + --ctp-pink: rgb(244, 184, 228); + --ctp-mauve: rgb(202, 158, 230); + --ctp-red: rgb(231, 130, 132); + --ctp-maroon: rgb(234, 153, 156); + --ctp-peach: rgb(239, 159, 118); + --ctp-yellow: rgb(229, 200, 144); + --ctp-green: rgb(166, 209, 137); + --ctp-teal: rgb(129, 200, 190); + --ctp-sky: rgb(153, 209, 219); + --ctp-sapphire: rgb(133, 193, 220); + --ctp-blue: rgb(140, 170, 238); + --ctp-lavender: rgb(186, 187, 241); + --ctp-text: rgb(198, 208, 245); + --ctp-subtext1: rgb(181, 191, 226); + --ctp-subtext0: rgb(165, 173, 206); + --ctp-overlay2: rgb(148, 156, 187); + --ctp-overlay1: rgb(131, 139, 167); + --ctp-overlay0: rgb(115, 121, 148); + --ctp-surface2: rgb(98, 104, 128); + --ctp-surface1: rgb(81, 87, 109); + --ctp-surface0: rgb(65, 69, 89); + --ctp-base: rgb(48, 52, 70); + --ctp-mantle: rgb(41, 44, 60); + --ctp-crust: rgb(35, 38, 52); +} +.ctp-macchiato { + --ctp-rosewater: rgb(244, 219, 214); + --ctp-flamingo: rgb(240, 198, 198); + --ctp-pink: rgb(245, 189, 230); + --ctp-mauve: rgb(198, 160, 246); + --ctp-red: rgb(237, 135, 150); + --ctp-maroon: rgb(238, 153, 160); + --ctp-peach: rgb(245, 169, 127); + --ctp-yellow: rgb(238, 212, 159); + --ctp-green: rgb(166, 218, 149); + --ctp-teal: rgb(139, 213, 202); + --ctp-sky: rgb(145, 215, 227); + --ctp-sapphire: rgb(125, 196, 228); + --ctp-blue: rgb(138, 173, 244); + --ctp-lavender: rgb(183, 189, 248); + --ctp-text: rgb(202, 211, 245); + --ctp-subtext1: rgb(184, 192, 224); + --ctp-subtext0: rgb(165, 173, 203); + --ctp-overlay2: rgb(147, 154, 183); + --ctp-overlay1: rgb(128, 135, 162); + --ctp-overlay0: rgb(110, 115, 141); + --ctp-surface2: rgb(91, 96, 120); + --ctp-surface1: rgb(73, 77, 100); + --ctp-surface0: rgb(54, 58, 79); + --ctp-base: rgb(36, 39, 58); + --ctp-mantle: rgb(30, 32, 48); + --ctp-crust: rgb(24, 25, 38); +} +.ctp-mocha { + --ctp-rosewater: rgb(245, 224, 220); + --ctp-flamingo: rgb(242, 205, 205); + --ctp-pink: rgb(245, 194, 231); + --ctp-mauve: rgb(203, 166, 247); + --ctp-red: rgb(243, 139, 168); + --ctp-maroon: rgb(235, 160, 172); + --ctp-peach: rgb(250, 179, 135); + --ctp-yellow: rgb(249, 226, 175); + --ctp-green: rgb(166, 227, 161); + --ctp-teal: rgb(148, 226, 213); + --ctp-sky: rgb(137, 220, 235); + --ctp-sapphire: rgb(116, 199, 236); + --ctp-blue: rgb(137, 180, 250); + --ctp-lavender: rgb(180, 190, 254); + --ctp-text: rgb(205, 214, 244); + --ctp-subtext1: rgb(186, 194, 222); + --ctp-subtext0: rgb(166, 173, 200); + --ctp-overlay2: rgb(147, 153, 178); + --ctp-overlay1: rgb(127, 132, 156); + --ctp-overlay0: rgb(108, 112, 134); + --ctp-surface2: rgb(88, 91, 112); + --ctp-surface1: rgb(69, 71, 90); + --ctp-surface0: rgb(49, 50, 68); + --ctp-base: rgb(30, 30, 46); + --ctp-mantle: rgb(24, 24, 37); + --ctp-crust: rgb(17, 17, 27); +} + +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --ctp-rosewater: rgb(220, 138, 120); + --ctp-flamingo: rgb(221, 120, 120); + --ctp-pink: rgb(234, 118, 203); + --ctp-mauve: rgb(136, 57, 239); + --ctp-red: rgb(210, 15, 57); + --ctp-maroon: rgb(230, 69, 83); + --ctp-peach: rgb(254, 100, 11); + --ctp-yellow: rgb(223, 142, 29); + --ctp-green: rgb(64, 160, 43); + --ctp-teal: rgb(23, 146, 153); + --ctp-sky: rgb(4, 165, 229); + --ctp-sapphire: rgb(32, 159, 181); + --ctp-blue: rgb(30, 102, 245); + --ctp-lavender: rgb(114, 135, 253); + --ctp-text: rgb(76, 79, 105); + --ctp-subtext1: rgb(92, 95, 119); + --ctp-subtext0: rgb(108, 111, 133); + --ctp-overlay2: rgb(124, 127, 147); + --ctp-overlay1: rgb(140, 143, 161); + --ctp-overlay0: rgb(156, 160, 176); + --ctp-surface2: rgb(172, 176, 190); + --ctp-surface1: rgb(188, 192, 204); + --ctp-surface0: rgb(204, 208, 218); + --ctp-base: rgb(239, 241, 245); + --ctp-mantle: rgb(230, 233, 239); + --ctp-crust: rgb(220, 224, 232); +} + +@media (prefers-color-scheme: dark) { + :root { + --ctp-rosewater: rgb(245, 224, 220); + --ctp-flamingo: rgb(242, 205, 205); + --ctp-pink: rgb(245, 194, 231); + --ctp-mauve: rgb(203, 166, 247); + --ctp-red: rgb(243, 139, 168); + --ctp-maroon: rgb(235, 160, 172); + --ctp-peach: rgb(250, 179, 135); + --ctp-yellow: rgb(249, 226, 175); + --ctp-green: rgb(166, 227, 161); + --ctp-teal: rgb(148, 226, 213); + --ctp-sky: rgb(137, 220, 235); + --ctp-sapphire: rgb(116, 199, 236); + --ctp-blue: rgb(137, 180, 250); + --ctp-lavender: rgb(180, 190, 254); + --ctp-text: rgb(205, 214, 244); + --ctp-subtext1: rgb(186, 194, 222); + --ctp-subtext0: rgb(166, 173, 200); + --ctp-overlay2: rgb(147, 153, 178); + --ctp-overlay1: rgb(127, 132, 156); + --ctp-overlay0: rgb(108, 112, 134); + --ctp-surface2: rgb(88, 91, 112); + --ctp-surface1: rgb(69, 71, 90); + --ctp-surface0: rgb(49, 50, 68); + --ctp-base: rgb(30, 30, 46); + --ctp-mantle: rgb(24, 24, 37); + --ctp-crust: rgb(17, 17, 27); + } +} + +/* Bento Boxes */ +@property --angle { + inherits: true; + initial-value: 0deg; + syntax: "<angle>"; +} + +.bento-container { + --border-width: 1; + --border-radius: 5; + --border-speed: 2; + --angle: 0; + animation: rotate-gradient calc(var(--border-speed, 2) * 1s) infinite linear; + animation-play-state: paused; + --gradient: conic-gradient( + from calc(180deg + var(--angle)) at 50% 70%, + #ff240055, + #e81d1d55, + #e8b71d55, + #e3e81d55, + #1de84055, + #1ddde855, + #2b1de855, + #dd00f355, + #dd00f355 + ); +} +.bento-container:hover { + animation-play-state: running; + --alpha: 0; +} +@keyframes rotate-gradient { + from { + --angle: 0deg; + } + to { + --angle: 360deg; + } +} +.bento-box { + --bg: var(--ctp-base); + --bg-grad: linear-gradient(-45deg, var(--ctp-surface0), var(--ctp-base)) + padding-box; + --border-gradient: var(--gradient) border-box; + background: var(--bg-grad); /*, var(--border-gradient);*/ + border: calc(var(--border-width, 2) * 1px) solid transparent; + padding: 2rem; + border-radius: calc(var(--border-radius, 8) * 1px); + position: relative; + transform: translate3d(0, 0, 0); + transition: background 0.1s; + box-shadow: 0px 8px 16px 0px rgba(17, 17, 27, 0.24), + 0px 0px 4px 0px rgba(17, 17, 27, 0.04), + rgba(205, 214, 244, 0.235) 0px 0px 1px 0px inset; + background-size: 100%; + background-repeat: no-repeat; + overflow: hidden; +} +.bento-box:hover { + background: var(--bg-grad), var(--border-gradient); + background-size: 110%; + background-repeat: no-repeat; + background-position: top center; +} + +.bento-box::before { + content: ""; + position: absolute; + inset: calc(var(--border-width) * -1px); + border-radius: calc(var(--border-radius) * 1px); + background: var(--ctp-surface0); + opacity: var(--alpha, 0.5); + transition: opacity 0.2s; +} + +.bento-box .img-header { + transition: all 0.1s ease-out; + margin: -2rem; + position: absolute; + z-index: -1; +} +.bento-box:hover .img-header { + filter: blur(5px); + transform: scale3d(1.15, 1.15, 1.15); +} +.bento-box .visible-on-hover { + visibility: hidden; +} +.bento-box:hover .visible-on-hover { + visibility: visible; +} +.bento-box .img-header::after { + background: #1fa9f4; + content: ""; +} + +.rainbow-borders { + border-image-source: linear-gradient( + 90deg, + rgba(251, 89, 74, 0.3) 0%, + rgba(251, 222, 75, 0.3) 25%, + rgba(112, 228, 112, 0.3) 50%, + rgba(51, 183, 255, 0.3) 75% + ); + + border-bottom-width: 2px; + border-image-slice: 1; +} +.rainbow-borders:hover { + border-image-source: linear-gradient( + 90deg, + rgba(251, 89, 74, 1) 0%, + rgba(251, 222, 75, 1) 25%, + rgba(112, 228, 112, 1) 50%, + rgba(51, 183, 255, 1) 75% + ); +} + +.outfit-900 { + font-family: "Outfit", sans-serif; + font-optical-sizing: auto; + font-weight: 900; + font-style: normal; +} + +@media (prefers-color-scheme: light) { + .main-header-darken { + background: #555; + } +} + +.textured-bg:before { + content: " "; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + background: url(/textures/cubes.png), var(--ctp-base); + background-blend-mode: multiply; +} + +@media (prefers-color-scheme: dark) { + .textured-bg:before { + content: " "; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + background: url(/textures/micro_carbon.png), var(--ctp-base); + background-blend-mode: luminosity; + } +} diff --git a/crates/www/tailwind.config.js b/crates/www/tailwind.config.js new file mode 100644 index 00000000..b287473b --- /dev/null +++ b/crates/www/tailwind.config.js @@ -0,0 +1,371 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: { + files: ["*.html", "./crates/www/**/*.rs"], + }, + theme: { + extend: { + backgroundColor: { + "ctp-rosewater": "var(--ctp-rosewater)", + "ctp-flamingo": "var(--ctp-flamingo)", + "ctp-pink": "var(--ctp-pink)", + "ctp-mauve": "var(--ctp-mauve)", + "ctp-red": "var(--ctp-red)", + "ctp-maroon": "var(--ctp-maroon)", + "ctp-peach": "var(--ctp-peach)", + "ctp-yellow": "var(--ctp-yellow)", + "ctp-green": "var(--ctp-green)", + "ctp-teal": "var(--ctp-teal)", + "ctp-sky": "var(--ctp-sky)", + "ctp-sapphire": "var(--ctp-sapphire)", + "ctp-blue": "var(--ctp-blue)", + "ctp-lavender": "var(--ctp-lavender)", + "ctp-text": "var(--ctp-text)", + "ctp-subtext1": "var(--ctp-subtext1)", + "ctp-subtext0": "var(--ctp-subtext0)", + "ctp-overlay2": "var(--ctp-overlay2)", + "ctp-overlay1": "var(--ctp-overlay1)", + "ctp-overlay0": "var(--ctp-overlay0)", + "ctp-surface2": "var(--ctp-surface2)", + "ctp-surface1": "var(--ctp-surface1)", + "ctp-surface0": "var(--ctp-surface0)", + "ctp-base": "var(--ctp-base)", + "ctp-mantle": "var(--ctp-mantle)", + "ctp-crust": "var(--ctp-crust)", + "brand-youtube": "#ff0000", + "brand-mastodon": "#6364FF", + }, + borderColor: { + "ctp-rosewater": "var(--ctp-rosewater)", + "ctp-flamingo": "var(--ctp-flamingo)", + "ctp-pink": "var(--ctp-pink)", + "ctp-mauve": "var(--ctp-mauve)", + "ctp-red": "var(--ctp-red)", + "ctp-maroon": "var(--ctp-maroon)", + "ctp-peach": "var(--ctp-peach)", + "ctp-yellow": "var(--ctp-yellow)", + "ctp-green": "var(--ctp-green)", + "ctp-teal": "var(--ctp-teal)", + "ctp-sky": "var(--ctp-sky)", + "ctp-sapphire": "var(--ctp-sapphire)", + "ctp-blue": "var(--ctp-blue)", + "ctp-lavender": "var(--ctp-lavender)", + "ctp-text": "var(--ctp-text)", + "ctp-subtext1": "var(--ctp-subtext1)", + "ctp-subtext0": "var(--ctp-subtext0)", + "ctp-overlay2": "var(--ctp-overlay2)", + "ctp-overlay1": "var(--ctp-overlay1)", + "ctp-overlay0": "var(--ctp-overlay0)", + "ctp-surface2": "var(--ctp-surface2)", + "ctp-surface1": "var(--ctp-surface1)", + "ctp-surface0": "var(--ctp-surface0)", + "ctp-base": "var(--ctp-base)", + "ctp-mantle": "var(--ctp-mantle)", + "ctp-crust": "var(--ctp-crust)", + "brand-youtube": "#ff0000", + "brand-mastodon": "#6364FF", + }, + caretColor: { + "ctp-rosewater": "var(--ctp-rosewater)", + "ctp-flamingo": "var(--ctp-flamingo)", + "ctp-pink": "var(--ctp-pink)", + "ctp-mauve": "var(--ctp-mauve)", + "ctp-red": "var(--ctp-red)", + "ctp-maroon": "var(--ctp-maroon)", + "ctp-peach": "var(--ctp-peach)", + "ctp-yellow": "var(--ctp-yellow)", + "ctp-green": "var(--ctp-green)", + "ctp-teal": "var(--ctp-teal)", + "ctp-sky": "var(--ctp-sky)", + "ctp-sapphire": "var(--ctp-sapphire)", + "ctp-blue": "var(--ctp-blue)", + "ctp-lavender": "var(--ctp-lavender)", + "ctp-text": "var(--ctp-text)", + "ctp-subtext1": "var(--ctp-subtext1)", + "ctp-subtext0": "var(--ctp-subtext0)", + "ctp-overlay2": "var(--ctp-overlay2)", + "ctp-overlay1": "var(--ctp-overlay1)", + "ctp-overlay0": "var(--ctp-overlay0)", + "ctp-surface2": "var(--ctp-surface2)", + "ctp-surface1": "var(--ctp-surface1)", + "ctp-surface0": "var(--ctp-surface0)", + "ctp-base": "var(--ctp-base)", + "ctp-mantle": "var(--ctp-mantle)", + "ctp-crust": "var(--ctp-crust)", + "brand-youtube": "#ff0000", + "brand-mastodon": "#6364FF", + }, + colors: { + "ctp-rosewater": "var(--ctp-rosewater)", + "ctp-flamingo": "var(--ctp-flamingo)", + "ctp-pink": "var(--ctp-pink)", + "ctp-mauve": "var(--ctp-mauve)", + "ctp-red": "var(--ctp-red)", + "ctp-maroon": "var(--ctp-maroon)", + "ctp-peach": "var(--ctp-peach)", + "ctp-yellow": "var(--ctp-yellow)", + "ctp-green": "var(--ctp-green)", + "ctp-teal": "var(--ctp-teal)", + "ctp-sky": "var(--ctp-sky)", + "ctp-sapphire": "var(--ctp-sapphire)", + "ctp-blue": "var(--ctp-blue)", + "ctp-lavender": "var(--ctp-lavender)", + "ctp-text": "var(--ctp-text)", + "ctp-subtext1": "var(--ctp-subtext1)", + "ctp-subtext0": "var(--ctp-subtext0)", + "ctp-overlay2": "var(--ctp-overlay2)", + "ctp-overlay1": "var(--ctp-overlay1)", + "ctp-overlay0": "var(--ctp-overlay0)", + "ctp-surface2": "var(--ctp-surface2)", + "ctp-surface1": "var(--ctp-surface1)", + "ctp-surface0": "var(--ctp-surface0)", + "ctp-base": "var(--ctp-base)", + "ctp-mantle": "var(--ctp-mantle)", + "ctp-crust": "var(--ctp-crust)", + "brand-youtube": "#ff0000", + "brand-mastodon": "#6364FF", + }, + divideColor: { + "ctp-rosewater": "var(--ctp-rosewater)", + "ctp-flamingo": "var(--ctp-flamingo)", + "ctp-pink": "var(--ctp-pink)", + "ctp-mauve": "var(--ctp-mauve)", + "ctp-red": "var(--ctp-red)", + "ctp-maroon": "var(--ctp-maroon)", + "ctp-peach": "var(--ctp-peach)", + "ctp-yellow": "var(--ctp-yellow)", + "ctp-green": "var(--ctp-green)", + "ctp-teal": "var(--ctp-teal)", + "ctp-sky": "var(--ctp-sky)", + "ctp-sapphire": "var(--ctp-sapphire)", + "ctp-blue": "var(--ctp-blue)", + "ctp-lavender": "var(--ctp-lavender)", + "ctp-text": "var(--ctp-text)", + "ctp-subtext1": "var(--ctp-subtext1)", + "ctp-subtext0": "var(--ctp-subtext0)", + "ctp-overlay2": "var(--ctp-overlay2)", + "ctp-overlay1": "var(--ctp-overlay1)", + "ctp-overlay0": "var(--ctp-overlay0)", + "ctp-surface2": "var(--ctp-surface2)", + "ctp-surface1": "var(--ctp-surface1)", + "ctp-surface0": "var(--ctp-surface0)", + "ctp-base": "var(--ctp-base)", + "ctp-mantle": "var(--ctp-mantle)", + "ctp-crust": "var(--ctp-crust)", + "brand-youtube": "#ff0000", + "brand-mastodon": "#6364FF", + }, + fill: { + "ctp-rosewater": "var(--ctp-rosewater)", + "ctp-flamingo": "var(--ctp-flamingo)", + "ctp-pink": "var(--ctp-pink)", + "ctp-mauve": "var(--ctp-mauve)", + "ctp-red": "var(--ctp-red)", + "ctp-maroon": "var(--ctp-maroon)", + "ctp-peach": "var(--ctp-peach)", + "ctp-yellow": "var(--ctp-yellow)", + "ctp-green": "var(--ctp-green)", + "ctp-teal": "var(--ctp-teal)", + "ctp-sky": "var(--ctp-sky)", + "ctp-sapphire": "var(--ctp-sapphire)", + "ctp-blue": "var(--ctp-blue)", + "ctp-lavender": "var(--ctp-lavender)", + "ctp-text": "var(--ctp-text)", + "ctp-subtext1": "var(--ctp-subtext1)", + "ctp-subtext0": "var(--ctp-subtext0)", + "ctp-overlay2": "var(--ctp-overlay2)", + "ctp-overlay1": "var(--ctp-overlay1)", + "ctp-overlay0": "var(--ctp-overlay0)", + "ctp-surface2": "var(--ctp-surface2)", + "ctp-surface1": "var(--ctp-surface1)", + "ctp-surface0": "var(--ctp-surface0)", + "ctp-base": "var(--ctp-base)", + "ctp-mantle": "var(--ctp-mantle)", + "ctp-crust": "var(--ctp-crust)", + "brand-youtube": "#ff0000", + "brand-mastodon": "#6364FF", + }, + gradientColorStops: { + "ctp-rosewater": "var(--ctp-rosewater)", + "ctp-flamingo": "var(--ctp-flamingo)", + "ctp-pink": "var(--ctp-pink)", + "ctp-mauve": "var(--ctp-mauve)", + "ctp-red": "var(--ctp-red)", + "ctp-maroon": "var(--ctp-maroon)", + "ctp-peach": "var(--ctp-peach)", + "ctp-yellow": "var(--ctp-yellow)", + "ctp-green": "var(--ctp-green)", + "ctp-teal": "var(--ctp-teal)", + "ctp-sky": "var(--ctp-sky)", + "ctp-sapphire": "var(--ctp-sapphire)", + "ctp-blue": "var(--ctp-blue)", + "ctp-lavender": "var(--ctp-lavender)", + "ctp-text": "var(--ctp-text)", + "ctp-subtext1": "var(--ctp-subtext1)", + "ctp-subtext0": "var(--ctp-subtext0)", + "ctp-overlay2": "var(--ctp-overlay2)", + "ctp-overlay1": "var(--ctp-overlay1)", + "ctp-overlay0": "var(--ctp-overlay0)", + "ctp-surface2": "var(--ctp-surface2)", + "ctp-surface1": "var(--ctp-surface1)", + "ctp-surface0": "var(--ctp-surface0)", + "ctp-base": "var(--ctp-base)", + "ctp-mantle": "var(--ctp-mantle)", + "ctp-crust": "var(--ctp-crust)", + "brand-youtube": "#ff0000", + "brand-mastodon": "#6364FF", + }, + placeholderColor: { + "ctp-rosewater": "var(--ctp-rosewater)", + "ctp-flamingo": "var(--ctp-flamingo)", + "ctp-pink": "var(--ctp-pink)", + "ctp-mauve": "var(--ctp-mauve)", + "ctp-red": "var(--ctp-red)", + "ctp-maroon": "var(--ctp-maroon)", + "ctp-peach": "var(--ctp-peach)", + "ctp-yellow": "var(--ctp-yellow)", + "ctp-green": "var(--ctp-green)", + "ctp-teal": "var(--ctp-teal)", + "ctp-sky": "var(--ctp-sky)", + "ctp-sapphire": "var(--ctp-sapphire)", + "ctp-blue": "var(--ctp-blue)", + "ctp-lavender": "var(--ctp-lavender)", + "ctp-text": "var(--ctp-text)", + "ctp-subtext1": "var(--ctp-subtext1)", + "ctp-subtext0": "var(--ctp-subtext0)", + "ctp-overlay2": "var(--ctp-overlay2)", + "ctp-overlay1": "var(--ctp-overlay1)", + "ctp-overlay0": "var(--ctp-overlay0)", + "ctp-surface2": "var(--ctp-surface2)", + "ctp-surface1": "var(--ctp-surface1)", + "ctp-surface0": "var(--ctp-surface0)", + "ctp-base": "var(--ctp-base)", + "ctp-mantle": "var(--ctp-mantle)", + "ctp-crust": "var(--ctp-crust)", + "brand-youtube": "#ff0000", + "brand-mastodon": "#6364FF", + }, + ringColor: { + "ctp-rosewater": "var(--ctp-rosewater)", + "ctp-flamingo": "var(--ctp-flamingo)", + "ctp-pink": "var(--ctp-pink)", + "ctp-mauve": "var(--ctp-mauve)", + "ctp-red": "var(--ctp-red)", + "ctp-maroon": "var(--ctp-maroon)", + "ctp-peach": "var(--ctp-peach)", + "ctp-yellow": "var(--ctp-yellow)", + "ctp-green": "var(--ctp-green)", + "ctp-teal": "var(--ctp-teal)", + "ctp-sky": "var(--ctp-sky)", + "ctp-sapphire": "var(--ctp-sapphire)", + "ctp-blue": "var(--ctp-blue)", + "ctp-lavender": "var(--ctp-lavender)", + "ctp-text": "var(--ctp-text)", + "ctp-subtext1": "var(--ctp-subtext1)", + "ctp-subtext0": "var(--ctp-subtext0)", + "ctp-overlay2": "var(--ctp-overlay2)", + "ctp-overlay1": "var(--ctp-overlay1)", + "ctp-overlay0": "var(--ctp-overlay0)", + "ctp-surface2": "var(--ctp-surface2)", + "ctp-surface1": "var(--ctp-surface1)", + "ctp-surface0": "var(--ctp-surface0)", + "ctp-base": "var(--ctp-base)", + "ctp-mantle": "var(--ctp-mantle)", + "ctp-crust": "var(--ctp-crust)", + "brand-youtube": "#ff0000", + "brand-mastodon": "#6364FF", + }, + ringOffsetColor: { + "ctp-rosewater": "var(--ctp-rosewater)", + "ctp-flamingo": "var(--ctp-flamingo)", + "ctp-pink": "var(--ctp-pink)", + "ctp-mauve": "var(--ctp-mauve)", + "ctp-red": "var(--ctp-red)", + "ctp-maroon": "var(--ctp-maroon)", + "ctp-peach": "var(--ctp-peach)", + "ctp-yellow": "var(--ctp-yellow)", + "ctp-green": "var(--ctp-green)", + "ctp-teal": "var(--ctp-teal)", + "ctp-sky": "var(--ctp-sky)", + "ctp-sapphire": "var(--ctp-sapphire)", + "ctp-blue": "var(--ctp-blue)", + "ctp-lavender": "var(--ctp-lavender)", + "ctp-text": "var(--ctp-text)", + "ctp-subtext1": "var(--ctp-subtext1)", + "ctp-subtext0": "var(--ctp-subtext0)", + "ctp-overlay2": "var(--ctp-overlay2)", + "ctp-overlay1": "var(--ctp-overlay1)", + "ctp-overlay0": "var(--ctp-overlay0)", + "ctp-surface2": "var(--ctp-surface2)", + "ctp-surface1": "var(--ctp-surface1)", + "ctp-surface0": "var(--ctp-surface0)", + "ctp-base": "var(--ctp-base)", + "ctp-mantle": "var(--ctp-mantle)", + "ctp-crust": "var(--ctp-crust)", + "brand-youtube": "#ff0000", + "brand-mastodon": "#6364FF", + }, + stroke: { + "ctp-rosewater": "var(--ctp-rosewater)", + "ctp-flamingo": "var(--ctp-flamingo)", + "ctp-pink": "var(--ctp-pink)", + "ctp-mauve": "var(--ctp-mauve)", + "ctp-red": "var(--ctp-red)", + "ctp-maroon": "var(--ctp-maroon)", + "ctp-peach": "var(--ctp-peach)", + "ctp-yellow": "var(--ctp-yellow)", + "ctp-green": "var(--ctp-green)", + "ctp-teal": "var(--ctp-teal)", + "ctp-sky": "var(--ctp-sky)", + "ctp-sapphire": "var(--ctp-sapphire)", + "ctp-blue": "var(--ctp-blue)", + "ctp-lavender": "var(--ctp-lavender)", + "ctp-text": "var(--ctp-text)", + "ctp-subtext1": "var(--ctp-subtext1)", + "ctp-subtext0": "var(--ctp-subtext0)", + "ctp-overlay2": "var(--ctp-overlay2)", + "ctp-overlay1": "var(--ctp-overlay1)", + "ctp-overlay0": "var(--ctp-overlay0)", + "ctp-surface2": "var(--ctp-surface2)", + "ctp-surface1": "var(--ctp-surface1)", + "ctp-surface0": "var(--ctp-surface0)", + "ctp-base": "var(--ctp-base)", + "ctp-mantle": "var(--ctp-mantle)", + "ctp-crust": "var(--ctp-crust)", + "brand-youtube": "#ff0000", + "brand-mastodon": "#6364FF", + }, + textColor: { + "ctp-rosewater": "var(--ctp-rosewater)", + "ctp-flamingo": "var(--ctp-flamingo)", + "ctp-pink": "var(--ctp-pink)", + "ctp-mauve": "var(--ctp-mauve)", + "ctp-red": "var(--ctp-red)", + "ctp-maroon": "var(--ctp-maroon)", + "ctp-peach": "var(--ctp-peach)", + "ctp-yellow": "var(--ctp-yellow)", + "ctp-green": "var(--ctp-green)", + "ctp-teal": "var(--ctp-teal)", + "ctp-sky": "var(--ctp-sky)", + "ctp-sapphire": "var(--ctp-sapphire)", + "ctp-blue": "var(--ctp-blue)", + "ctp-lavender": "var(--ctp-lavender)", + "ctp-text": "var(--ctp-text)", + "ctp-subtext1": "var(--ctp-subtext1)", + "ctp-subtext0": "var(--ctp-subtext0)", + "ctp-overlay2": "var(--ctp-overlay2)", + "ctp-overlay1": "var(--ctp-overlay1)", + "ctp-overlay0": "var(--ctp-overlay0)", + "ctp-surface2": "var(--ctp-surface2)", + "ctp-surface1": "var(--ctp-surface1)", + "ctp-surface0": "var(--ctp-surface0)", + "ctp-base": "var(--ctp-base)", + "ctp-mantle": "var(--ctp-mantle)", + "ctp-crust": "var(--ctp-crust)", + "brand-youtube": "#ff0000", + "brand-mastodon": "#6364FF", + }, + }, + }, + plugins: [require("@tailwindcss/forms"), require("@tailwindcss/typography")], +}; diff --git a/fly.toml b/fly.toml new file mode 100644 index 00000000..1f083a86 --- /dev/null +++ b/fly.toml @@ -0,0 +1,37 @@ +app = "christopherbiscardi" +kill_signal = "SIGINT" +kill_timeout = 5 +processes = [] + +[env] +RUST_LOG = "info" + +[experimental] +allowed_public_ports = [] +auto_rollback = true + +[[services]] +http_checks = [] +internal_port = 3000 +processes = ["app"] +protocol = "tcp" +script_checks = [] +[services.concurrency] +hard_limit = 25 +soft_limit = 20 +type = "connections" + +[[services.ports]] +force_https = true +handlers = ["http"] +port = 80 + +[[services.ports]] +handlers = ["tls", "http"] +port = 443 + +[[services.tcp_checks]] +grace_period = "1s" +interval = "15s" +restart_limit = 0 +timeout = "2s" diff --git a/justfile b/justfile new file mode 100644 index 00000000..b477f63e --- /dev/null +++ b/justfile @@ -0,0 +1,4 @@ +watch: + cargo leptos watch --project www +build: + cargo leptos build --project www --release \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..fc116afb --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "nightly-2024-08-10"