├── src ├── page │ ├── partial │ │ ├── mod.rs │ │ ├── footer.rs │ │ └── header.rs │ ├── mod.rs │ ├── not_found.rs │ └── about.rs ├── generated │ └── mod.rs └── lib.rs ├── netlify.toml ├── tsconfig.json ├── favicons ├── favicon.ico ├── favicon-16x16.png ├── favicon-32x32.png ├── mstile-150x150.png ├── apple-touch-icon.png ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── browserconfig.xml ├── site.webmanifest └── safari-pinned-tab.svg ├── static ├── images │ ├── photo_1.png │ ├── photo_2.jpg │ ├── og_image.jpg │ ├── realworld_logo.png │ ├── loading.svg │ ├── next.svg │ ├── link_arrow.svg │ ├── top.svg │ ├── logo.svg │ ├── download.svg │ ├── gear.svg │ ├── cross.svg │ ├── hellweb_logo.svg │ ├── hamburger.svg │ └── seed_logo.svg ├── Martin_Kavik_resume.pdf ├── fonts │ ├── inter │ │ ├── Inter-Bold.woff │ │ ├── Inter-Bold.woff2 │ │ ├── Inter-Regular.woff │ │ ├── Inter-Regular.woff2 │ │ ├── Inter-SemiBold.woff │ │ └── Inter-SemiBold.woff2 │ └── metropolis │ │ ├── Metropolis-Bold.woff │ │ ├── Metropolis-Bold.woff2 │ │ ├── Metropolis-Thin.woff │ │ ├── Metropolis-Thin.woff2 │ │ ├── Metropolis-Regular.woff │ │ ├── Metropolis-Regular.woff2 │ │ ├── Metropolis-SemiBold.woff │ │ ├── Metropolis-SemiBold.woff2 │ │ ├── Metropolis-RegularItalic.woff │ │ └── Metropolis-RegularItalic.woff2 ├── index.css_classes.ts ├── templates │ ├── favicons.hbs │ ├── loading_page.hbs │ └── social_media.hbs └── index.hbs ├── tsconfig.css_classes.json ├── index.ts ├── .gitignore ├── tests └── test.rs ├── css ├── styles.css ├── custom.css └── fonts.css ├── RELEASE_CHECKLIST.md ├── rustfmt.toml ├── .github ├── FUNDING.yml └── workflows │ └── main.yml ├── tsconfig.base.json ├── Cargo.toml ├── postcss.config.js ├── LICENSE ├── .travis.yml_not_maintained ├── webpack.css_classes.config.js ├── package.json ├── Makefile.toml ├── CHANGELOG.md ├── webpack.config.js ├── tailwind.config.js ├── README.md └── Cargo.lock /src/page/partial/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod footer; 2 | pub mod header; 3 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [[redirects]] 2 | from = "/*" 3 | to = "/index.html" 4 | status = 200 5 | -------------------------------------------------------------------------------- /src/page/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod about; 2 | pub mod home; 3 | pub mod not_found; 4 | pub mod partial; 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base", 3 | "exclude": ["index.css_classes.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /favicons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/favicons/favicon.ico -------------------------------------------------------------------------------- /static/images/photo_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/images/photo_1.png -------------------------------------------------------------------------------- /static/images/photo_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/images/photo_2.jpg -------------------------------------------------------------------------------- /favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /favicons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/favicons/mstile-150x150.png -------------------------------------------------------------------------------- /static/images/og_image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/images/og_image.jpg -------------------------------------------------------------------------------- /favicons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/favicons/apple-touch-icon.png -------------------------------------------------------------------------------- /static/Martin_Kavik_resume.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/Martin_Kavik_resume.pdf -------------------------------------------------------------------------------- /tsconfig.css_classes.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.base", 3 | "include": ["./static/index.css_classes.ts"] 4 | } 5 | -------------------------------------------------------------------------------- /static/images/realworld_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/images/realworld_logo.png -------------------------------------------------------------------------------- /favicons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/favicons/android-chrome-192x192.png -------------------------------------------------------------------------------- /favicons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/favicons/android-chrome-512x512.png -------------------------------------------------------------------------------- /static/fonts/inter/Inter-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/inter/Inter-Bold.woff -------------------------------------------------------------------------------- /static/fonts/inter/Inter-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/inter/Inter-Bold.woff2 -------------------------------------------------------------------------------- /static/fonts/inter/Inter-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/inter/Inter-Regular.woff -------------------------------------------------------------------------------- /static/fonts/inter/Inter-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/inter/Inter-Regular.woff2 -------------------------------------------------------------------------------- /static/fonts/inter/Inter-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/inter/Inter-SemiBold.woff -------------------------------------------------------------------------------- /static/fonts/inter/Inter-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/inter/Inter-SemiBold.woff2 -------------------------------------------------------------------------------- /src/generated/mod.rs: -------------------------------------------------------------------------------- 1 | // File `css_classes.rs` is (re)created during webpack compilation. 2 | // (see `postcss.config.js`) 3 | pub mod css_classes; 4 | -------------------------------------------------------------------------------- /static/fonts/metropolis/Metropolis-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/metropolis/Metropolis-Bold.woff -------------------------------------------------------------------------------- /static/fonts/metropolis/Metropolis-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/metropolis/Metropolis-Bold.woff2 -------------------------------------------------------------------------------- /static/fonts/metropolis/Metropolis-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/metropolis/Metropolis-Thin.woff -------------------------------------------------------------------------------- /static/fonts/metropolis/Metropolis-Thin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/metropolis/Metropolis-Thin.woff2 -------------------------------------------------------------------------------- /static/fonts/metropolis/Metropolis-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/metropolis/Metropolis-Regular.woff -------------------------------------------------------------------------------- /static/fonts/metropolis/Metropolis-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/metropolis/Metropolis-Regular.woff2 -------------------------------------------------------------------------------- /static/fonts/metropolis/Metropolis-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/metropolis/Metropolis-SemiBold.woff -------------------------------------------------------------------------------- /static/fonts/metropolis/Metropolis-SemiBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/metropolis/Metropolis-SemiBold.woff2 -------------------------------------------------------------------------------- /static/fonts/metropolis/Metropolis-RegularItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/metropolis/Metropolis-RegularItalic.woff -------------------------------------------------------------------------------- /index.ts: -------------------------------------------------------------------------------- 1 | import "./css/styles.css"; 2 | 3 | (async () => { 4 | // Note: files in `./pkg/` will be created on the first build. 5 | await import("./pkg/index"); 6 | })(); 7 | -------------------------------------------------------------------------------- /static/fonts/metropolis/Metropolis-RegularItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/seed-rs/seed-quickstart-webpack/HEAD/static/fonts/metropolis/Metropolis-RegularItalic.woff2 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | bin 4 | pkg 5 | target 6 | wasm-pack.log 7 | .idea 8 | 9 | src/generated/** 10 | !src/generated/mod.rs 11 | !**/.keep 12 | css_classes.rs -------------------------------------------------------------------------------- /tests/test.rs: -------------------------------------------------------------------------------- 1 | extern crate wasm_bindgen_test; 2 | use wasm_bindgen_test::*; 3 | 4 | wasm_bindgen_test_configure!(run_in_browser); 5 | 6 | #[wasm_bindgen_test] 7 | fn pass() { 8 | assert_eq!(1, 1); 9 | } 10 | -------------------------------------------------------------------------------- /static/index.css_classes.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is used when `yarn generate:css_classes` is called. 3 | * We want to run only pipeline that processes CSS so it generates `css_classes.rs`. 4 | */ 5 | import "../css/styles.css"; 6 | 7 | -------------------------------------------------------------------------------- /css/styles.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss/base"; 2 | 3 | @import "fonts.css"; 4 | 5 | @import "tailwindcss/components"; 6 | @import "tailwindcss/utilities"; 7 | 8 | @import "custom.css" 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /RELEASE_CHECKLIST.md: -------------------------------------------------------------------------------- 1 | # Release Checklist 2 | 3 | 1. Update `CHANGELOG.md` (content + increment version). 4 | 1. Update version also in `package.json`. 5 | 1. Run `cargo make verify` 6 | 1. Commit "v#.#.#". 7 | 1. Push. 8 | 1. Wait for the CI to go green. 9 | 1. Create GitHub release (create a new tag). 10 | -------------------------------------------------------------------------------- /favicons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #2b5797 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static/templates/favicons.hbs: -------------------------------------------------------------------------------- 1 | {{! https://realfavicongenerator.net }} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /favicons/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Kavik.cz", 3 | "short_name": "Kavik.cz", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff", 18 | "display": "standalone" 19 | } 20 | -------------------------------------------------------------------------------- /static/images/loading.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | # https://github.com/rust-lang/rustfmt/blob/master/Configurations.md 2 | 3 | newline_style = "Unix" 4 | use_field_init_shorthand = true 5 | use_try_shorthand = true 6 | 7 | # nightly 8 | 9 | ignore = [ 10 | "src/generated", 11 | ] 12 | normalize_doc_attributes = true 13 | reorder_impl_items = true 14 | normalize_comments = true 15 | match_block_trailing_comma = true 16 | merge_imports = true 17 | report_fixme = "Always" 18 | error_on_unformatted = true 19 | use_small_heuristics = "Off" 20 | max_width = 80 21 | 22 | #version = "Two" 23 | #report_todo = "Always" 24 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [MartinKavik] 4 | patreon: martinkavik 5 | #open_collective: # Replace with a single Open Collective username 6 | #ko_fi: # Replace with a single Ko-fi username 7 | #tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | #community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | #liberapay: # Replace with a single Liberapay username 10 | #issuehunt: # Replace with a single IssueHunt username 11 | #otechie: # Replace with a single Otechie username 12 | #custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /static/index.hbs: -------------------------------------------------------------------------------- 1 | {{! http://handlebarsjs.com }} 2 | 3 | 4 | 5 | 6 | {{!-- 7 | You can change it to e.g. `/ui/`, 8 | but also edit values `publicPath` and `historyApiFallback` in`webpack.config.js`. 9 | --}} 10 | 11 | 12 | {{> social_media}} 13 | {{> favicons}} 14 | 15 | 16 |
17 | {{> loading_page}} 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /static/templates/loading_page.hbs: -------------------------------------------------------------------------------- 1 |
2 |

YOU ARE AWESOME!

3 | {{! spinner from https://loading.io }} 4 | 10 | 13 | 14 | 15 |
-------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esNext", 5 | "lib": ["dom", "es2015"], 6 | "strict": true, 7 | "esModuleInterop": true, 8 | "sourceMap": true, 9 | "noImplicitAny": true, 10 | "noUnusedLocals": true, 11 | "noUnusedParameters": true, 12 | "noImplicitReturns": true, 13 | "noImplicitThis": true, 14 | "strictBindCallApply": true, 15 | "allowJs": false, 16 | "allowUnreachableCode": false, 17 | "allowSyntheticDefaultImports": false, 18 | "allowUnusedLabels": false, 19 | "alwaysStrict": true, 20 | "strictFunctionTypes": true, 21 | "strictNullChecks": true, 22 | "strictPropertyInitialization": true, 23 | "forceConsistentCasingInFileNames": true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | version = "0.1.0" 3 | name = "kavik_cz" 4 | repository = "https://github.com/MartinKavik/kavik.cz" 5 | authors = ["Martin Kavík "] 6 | description = "Personal website kavik.cz" 7 | categories = ["wasm", "rust", "tailwindcss", "seed", "personal", "website"] 8 | license = "MIT" 9 | readme = "./README.md" 10 | edition = "2018" 11 | 12 | [lib] 13 | crate-type = ["cdylib"] 14 | 15 | [dev-dependencies] 16 | wasm-bindgen-test = "0.3.18" 17 | 18 | [dependencies] 19 | seed = "0.8.0" 20 | fixed-vec-deque = "0.1.9" 21 | 22 | [dependencies.web-sys] 23 | version = "0.3.45" 24 | features = [ 25 | "ScrollToOptions", 26 | "Navigator", 27 | ] 28 | 29 | [profile.release] 30 | lto = true 31 | opt-level = 'z' 32 | codegen-units = 1 33 | 34 | [package.metadata.wasm-pack.profile.release] 35 | wasm-opt = ['-Os'] 36 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ file, options, env }) => { 2 | 3 | return { 4 | plugins: [ 5 | require("postcss-import"), 6 | require("tailwindcss")('tailwind.config.js'), 7 | require("postcss-typed-css-classes")({ 8 | generator: "rust", 9 | purge: env === "production", 10 | output_filepath: "src/generated/css_classes.rs", 11 | content: [ 12 | { path: ['src/**/*.rs'] }, 13 | { 14 | path: ['static/index.hbs', 'static/templates/**/*.hbs'], 15 | regex: /class\s*=\s*["'|][^"'|]+["'|]/g, 16 | mapper: className => { 17 | return (className.match(/class\s*=\s*["'|]([^"'|]+)["'|]/)[1]).match(/\S+/g) 18 | }, 19 | escape: true 20 | } 21 | ], 22 | }), 23 | require("autoprefixer") 24 | ] 25 | }; 26 | }; 27 | -------------------------------------------------------------------------------- /static/images/next.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /static/images/link_arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /static/images/top.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /static/templates/social_media.hbs: -------------------------------------------------------------------------------- 1 | {{! https://megatags.co/ ; meta "name" changed to "property" }} 2 | {{! COMMON TAGS }} 3 | 4 | Kavik.cz 5 | {{! Search Engine }} 6 | 7 | 8 | {{! Schema.org for Google }} 9 | 10 | 11 | 12 | {{! Open Graph general (Facebook, Pinterest & Google+) }} 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /static/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /static/images/download.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Seed Quickstart with Webpack 'MartinKavik/seed-quickstart-webpack': 2 | Copyright (c) 2019 Martin Kavík 3 | 4 | Quickstart is based on 'rustwasm/rust-webpack-template': 5 | Copyright (c) 2015 The Rust Project Developers 6 | 7 | Permission is hereby granted, free of charge, to any 8 | person obtaining a copy of this software and associated 9 | documentation files (the "Software"), to deal in the 10 | Software without restriction, including without 11 | limitation the rights to use, copy, modify, merge, 12 | publish, distribute, sublicense, and/or sell copies of 13 | the Software, and to permit persons to whom the Software 14 | is furnished to do so, subject to the following 15 | conditions: 16 | 17 | The above copyright notice and this permission notice 18 | shall be included in all copies or substantial portions 19 | of the Software. 20 | 21 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 22 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 23 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 24 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 25 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 26 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 27 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 28 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 29 | DEALINGS IN THE SOFTWARE. 30 | -------------------------------------------------------------------------------- /.travis.yml_not_maintained: -------------------------------------------------------------------------------- 1 | language: rust 2 | 3 | rust: 4 | - stable 5 | 6 | os: 7 | - linux 8 | 9 | addons: 10 | firefox: latest 11 | 12 | install: 13 | - curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash 14 | - source ~/.nvm/nvm.sh 15 | - nvm install node # # "node" is an alias for the latest version (https://github.com/nvm-sh/nvm#usage) 16 | - curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f 17 | - cargo install --force cargo-make # remove --force in the future (https://github.com/rust-lang/cargo/issues/6797) 18 | - rustup install nightly 19 | - rustup component add rustfmt --toolchain nightly 20 | 21 | cache: 22 | - yarn 23 | - directories: 24 | - node_modules 25 | - $HOME/.cargo 26 | 27 | # https://levans.fr/rust_travis_cache.html 28 | before_cache: 29 | - rm -rf $HOME/.cargo/registry 30 | 31 | env: 32 | global: 33 | - RUST_BACKTRACE=1 34 | 35 | script: 36 | - yarn 37 | - yarn build:prerender # change it to `yarn build:release` if you don't want to prerender pages 38 | - cargo make verify_only # includes task `test_h_firefox` 39 | 40 | before_deploy: 41 | - yarn global add netlify-cli 42 | 43 | deploy: 44 | provider: script 45 | script: netlify deploy -s $NETLIFY_SITE_ID --auth $NETLIFY_ACCESS_TOKEN -p --dir ./dist 46 | skip_cleanup: true 47 | on: 48 | branch: master 49 | condition: $TRAVIS_OS_NAME = linux 50 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Main 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | RUST_BACKTRACE: 1 7 | 8 | jobs: 9 | build_test_deploy: 10 | runs-on: ubuntu-latest 11 | if: "!contains(github.event.head_commit.message, '[ci skip]')" 12 | steps: 13 | - name: Checkout sources 14 | uses: actions/checkout@v1 15 | 16 | - name: Install nightly Rust and rustfmt 17 | uses: actions-rs/toolchain@v1 18 | with: 19 | profile: minimal 20 | toolchain: nightly 21 | components: rustfmt 22 | 23 | - name: Install stable Rust 24 | uses: actions-rs/toolchain@v1 25 | with: 26 | profile: minimal 27 | toolchain: stable 28 | 29 | - name: Install cargo-make 30 | uses: davidB/rust-cargo-make@v1 31 | 32 | - name: Install Node dependencies 33 | run: yarn 34 | 35 | - name: Build & prerender 36 | run: yarn build:prerender 37 | 38 | - name: Run tests 39 | run: cargo make verify_only 40 | 41 | - name: Install Netlify CLI 42 | if: github.ref == 'refs/heads/master' 43 | run: sudo npm install --unsafe-perm=true netlify-cli -g 44 | 45 | - name: Deploy 46 | if: github.ref == 'refs/heads/master' 47 | env: 48 | NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }} 49 | NETLIFY_ACCESS_TOKEN: ${{ secrets.NETLIFY_ACCESS_TOKEN }} 50 | run: sudo netlify deploy -s $NETLIFY_SITE_ID --auth $NETLIFY_ACCESS_TOKEN -p --dir ./dist 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /css/custom.css: -------------------------------------------------------------------------------- 1 | 2 | .blur { 3 | filter: blur(7px); 4 | } 5 | 6 | .underline-yellow-7 { 7 | text-decoration-color: hsl(36, 77%, 49%) 8 | } 9 | 10 | .underline-blue-5 { 11 | text-decoration-color: hsl(205, 65%, 55%) 12 | } 13 | 14 | 15 | 16 | /* ====== ====== ANIMATIONS ====== ====== */ 17 | 18 | 19 | 20 | .fade-in { 21 | animation: fade-in 500ms linear 200ms both; 22 | } 23 | 24 | .rotate { 25 | animation: rotate-center 1s linear infinite both; 26 | } 27 | 28 | /* ---------------------------------------------- 29 | * Generated by Animista on 2019-9-6 16:20:47 30 | * Licensed under FreeBSD License. 31 | * See http://animista.net/license for more info. 32 | * w: http://animista.net, t: @cssanimista 33 | * ---------------------------------------------- */ 34 | 35 | /** 36 | * ---------------------------------------- 37 | * animation fade-in 38 | * ---------------------------------------- 39 | */ 40 | @keyframes fade-in { 41 | 0% { 42 | opacity: 0; 43 | } 44 | 100% { 45 | opacity: 1; 46 | } 47 | } 48 | 49 | /* ---------------------------------------------- 50 | * Generated by Animista on 2019-9-6 17:48:36 51 | * Licensed under FreeBSD License. 52 | * See http://animista.net/license for more info. 53 | * w: http://animista.net, t: @cssanimista 54 | * ---------------------------------------------- */ 55 | 56 | /** 57 | * ---------------------------------------- 58 | * animation rotate-center 59 | * ---------------------------------------- 60 | */ 61 | @keyframes rotate-center { 62 | 0% { 63 | transform: rotate(0); 64 | } 65 | 100% { 66 | transform: rotate(360deg); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/page/not_found.rs: -------------------------------------------------------------------------------- 1 | use crate::{generated::css_classes::C, Msg}; 2 | use seed::{prelude::*, *}; 3 | 4 | pub fn view() -> Node { 5 | div![ 6 | C![ 7 | C.mt_16, 8 | C.flex_grow, 9 | C.flex, 10 | C.flex_col, 11 | C.items_center, 12 | C.justify_center, 13 | // sm__ 14 | C.sm__mt_24, 15 | ], 16 | h1![ 17 | C![ 18 | C.font_display, 19 | C.font_thin, 20 | C.text_29, 21 | C.text_gray_10, 22 | // sm__ 23 | C.sm__text_45, 24 | // lg__ 25 | C.lg__text_55, 26 | ], 27 | "PAGE NOT FOUND!" 28 | ], 29 | // Sad mouth 30 | svg![ 31 | C![ 32 | C.mt_5, C.w_16, // sm__ 33 | C.sm__mt_6, C.sm__w_20, // lg__ 34 | C.lg__mt_8, C.lg__w_24, 35 | ], 36 | style! { 37 | "background" => "rgba(0, 0, 0, 0) none repeat scroll 0% 0%", 38 | "transform" => "scaleY(-1)", 39 | }, 40 | attrs! { 41 | At::ViewBox => "0 0 100 100", 42 | // @TODO: Rewrite once `preserveAspectRatio` is supported. 43 | At::Custom("preserveAspectRatio".into()) => "xMidYMid", 44 | }, 45 | path![attrs! { 46 | // @TODO: Rewrite once `stroke` is supported. 47 | At::Custom("stroke".into()) => "none", 48 | At::D => "M10 50A40 40 0 0 0 90 50A40 42 0 0 1 10 50" 49 | }] 50 | ] 51 | ] 52 | } 53 | -------------------------------------------------------------------------------- /webpack.css_classes.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | const WebpackBar = require("webpackbar"); 4 | const { CleanWebpackPlugin } = require("clean-webpack-plugin"); 5 | 6 | // Webpack generates `css_classes.rs` with this config. 7 | // This config is used in command `yarn generate:css_classes`. 8 | // See `webpack.config.js` for more info about individual settings. 9 | 10 | module.exports = (env, argv) => { 11 | return { 12 | entry: path.resolve(__dirname, "./static/index.css_classes.ts"), 13 | output: { 14 | path: path.resolve(__dirname, "dist"), 15 | filename: "css_classes.js", 16 | }, 17 | plugins: [new WebpackBar(), new CleanWebpackPlugin()], 18 | module: { 19 | rules: [ 20 | { 21 | test: /\.(jpg|jpeg|png|woff|woff2|eot|ttf|svg)$/, 22 | use: [ 23 | { 24 | loader: "file-loader", 25 | options: { 26 | emitFile: false, 27 | name: "[path][name].[ext]", 28 | }, 29 | }, 30 | ], 31 | }, 32 | { 33 | test: /\.ts$/, 34 | use: [ 35 | { 36 | loader: "ts-loader", 37 | options: { 38 | configFile: "tsconfig.css_classes.json" 39 | } 40 | } 41 | ] 42 | }, 43 | { 44 | test: /\.css$/, 45 | use: [ 46 | "style-loader", 47 | "css-loader", 48 | { 49 | loader: "postcss-loader", 50 | options: { 51 | postcssOptions: { 52 | config: path.resolve(__dirname, "postcss.config.js"), 53 | } 54 | }, 55 | }, 56 | ], 57 | }, 58 | ], 59 | }, 60 | }; 61 | }; 62 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Martin Kavík ", 3 | "name": "seed-quickstart-webpack", 4 | "version": "0.7.6", 5 | "repository": "https://github.com/MartinKavik/seed-quickstart-webpack", 6 | "license": "MIT", 7 | "scripts": { 8 | "start": "yarn generate:css_classes && webpack serve --config webpack.config.js --mode=development", 9 | "start:release": "yarn generate:css_classes && webpack serve --config webpack.config.js --mode=production", 10 | "build": "yarn generate:css_classes && webpack --config webpack.config --mode=development", 11 | "build:release": "yarn generate:css_classes && webpack --config webpack.config --mode=production", 12 | "build:prerender": "yarn build:release && yarn prerender", 13 | "serve:dist": "yarn serve -s -l 8000 dist", 14 | "prerender": "yarn concurrently -k -s first \"yarn serve:dist\" \"wait-on http://localhost:8000/ && react-snap\"", 15 | "generate:css_classes": "webpack --config webpack.css_classes.config --mode=development" 16 | }, 17 | "reactSnap": { 18 | "source": "dist", 19 | "externalServer": true, 20 | "port": 8000 21 | }, 22 | "devDependencies": { 23 | "@wasm-tool/wasm-pack-plugin": "1.0.1", 24 | "autoprefixer": "^10.2.5", 25 | "clean-webpack-plugin": "^3.0.0", 26 | "concurrently": "^6.0.1", 27 | "copy-webpack-plugin": "^8.1.1", 28 | "css-loader": "^5.2.0", 29 | "file-loader": "^6.2.0", 30 | "find": "^0.3.0", 31 | "handlebars": "^4.7.7", 32 | "handlebars-loader": "^1.7.1", 33 | "html-webpack-plugin": "^5.3.1", 34 | "mini-css-extract-plugin": "^1.4.0", 35 | "no-emit-webpack-plugin": "^4.0.1", 36 | "postcss-import": "^14.0.1", 37 | "postcss-loader": "^5.2.0", 38 | "postcss-typed-css-classes": "^0.2.4", 39 | "react-snap": "^1.23.0", 40 | "serve": "^11.3.2", 41 | "style-loader": "^2.0.0", 42 | "tailwindcss": "^2.1.1", 43 | "text-encoding": "^0.7.0", 44 | "ts-loader": "^8.1.0", 45 | "typescript": "^4.2.3", 46 | "wait-on": "^5.3.0", 47 | "webpack": "^5.30.0", 48 | "webpack-cli": "^4.6.0", 49 | "webpack-dev-server": "^3.11.2", 50 | "webpackbar": "^5.0.0-3" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /css/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: Metropolis; 3 | font-weight: 700; 4 | font-style: normal; 5 | font-display: swap; 6 | src: url(../static/fonts/metropolis/Metropolis-Bold.woff2) format("woff2"), 7 | url(../static/fonts/metropolis/Metropolis-Bold.woff) format("woff"); 8 | } 9 | 10 | @font-face { 11 | font-family: Metropolis; 12 | font-weight: 400; 13 | font-style: normal; 14 | font-display: swap; 15 | src: url(../static/fonts/metropolis/Metropolis-Regular.woff2) format("woff2"), 16 | url(../static/fonts/metropolis/Metropolis-Regular.woff) format("woff"); 17 | } 18 | 19 | @font-face { 20 | font-family: Metropolis; 21 | font-weight: 400; 22 | font-style: italic; 23 | font-display: swap; 24 | src: url(../static/fonts/metropolis/Metropolis-RegularItalic.woff2) format("woff2"), 25 | url(../static/fonts/metropolis/Metropolis-RegularItalic.woff) format("woff"); 26 | } 27 | 28 | @font-face { 29 | font-family: Metropolis; 30 | font-weight: 600; 31 | font-style: normal; 32 | font-display: swap; 33 | src: url(../static/fonts/metropolis/Metropolis-SemiBold.woff2) format("woff2"), 34 | url(../static/fonts/metropolis/Metropolis-SemiBold.woff) format("woff"); 35 | } 36 | 37 | @font-face { 38 | font-family: Metropolis; 39 | font-weight: 100; 40 | font-style: normal; 41 | font-display: swap; 42 | src: url(../static/fonts/metropolis/Metropolis-Thin.woff2) format("woff2"), 43 | url(../static/fonts/metropolis/Metropolis-Thin.woff) format("woff"); 44 | } 45 | 46 | @font-face { 47 | font-family: Inter; 48 | font-style: normal; 49 | font-weight: 700; 50 | font-display: swap; 51 | src: url(../static/fonts/inter/Inter-Bold.woff2) format("woff2"), 52 | url(../static/fonts/inter/Inter-Bold.woff) format("woff"); 53 | } 54 | 55 | @font-face { 56 | font-family: Inter; 57 | font-style: normal; 58 | font-weight: 400; 59 | font-display: swap; 60 | src: url(../static/fonts/inter/Inter-Regular.woff2) format("woff2"), 61 | url(../static/fonts/inter/Inter-Regular.woff) format("woff"); 62 | } 63 | 64 | @font-face { 65 | font-family: Inter; 66 | font-style: normal; 67 | font-weight: 600; 68 | font-display: swap; 69 | src: url(../static/fonts/inter/Inter-SemiBold.woff2) format("woff2"), 70 | url(../static/fonts/inter/Inter-SemiBold.woff) format("woff"); 71 | } -------------------------------------------------------------------------------- /static/images/gear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/page/partial/footer.rs: -------------------------------------------------------------------------------- 1 | use crate::{generated::css_classes::C, image_src, Msg, MAIL_TO_KAVIK}; 2 | use seed::{prelude::*, *}; 3 | 4 | pub fn view() -> Node { 5 | footer![ 6 | C![ 7 | C.h_16, 8 | C.shadow_2xl_above, 9 | C.flex, 10 | C.justify_center, 11 | // sm__ 12 | C.sm__h_24, 13 | ], 14 | div![ 15 | C![ 16 | C.w_xs, 17 | C.h_full, 18 | C.px_5, 19 | C.flex, 20 | C.justify_between, 21 | C.items_center, 22 | // sm__ 23 | C.sm__w_132 24 | ], 25 | div![ 26 | C![ 27 | // lg__ 28 | C.lg__pb_3, 29 | ], 30 | img![ 31 | C![ 32 | C.inline, 33 | C.w_6, 34 | C.align_baseline, 35 | // sm__ 36 | C.sm__w_12 37 | ], 38 | attrs! { 39 | At::Src => image_src("logo.svg") 40 | } 41 | ], 42 | span![ 43 | C![ 44 | C.ml_1, 45 | C.font_display, 46 | C.font_semibold, 47 | C.text_15, 48 | C.text_yellow_6, 49 | // sm__ 50 | C.sm__mt_2, 51 | C.sm__text_25, 52 | ], 53 | "2019" 54 | ] 55 | ], 56 | a![ 57 | attrs! { 58 | At::Href => MAIL_TO_KAVIK, 59 | }, 60 | C![ 61 | C.font_display, 62 | C.font_semibold, 63 | C.text_16, 64 | C.text_gray_10, 65 | C.underline, 66 | C.underline_yellow_7, 67 | // sm__ 68 | C.sm__text_26 69 | ], 70 | "martin@kavik.cz" 71 | ], 72 | div![ 73 | C![C.cursor_pointer, C.h_full, C.flex, C.items_center,], 74 | ev(Ev::Click, |_| Msg::ScrollToTop), 75 | img![ 76 | C![ 77 | C.mt_1, C.w_12, // sm__ 78 | C.sm__w_16 79 | ], 80 | attrs! { 81 | At::Src => image_src("top.svg") 82 | } 83 | ], 84 | ] 85 | ] 86 | ] 87 | } 88 | -------------------------------------------------------------------------------- /Makefile.toml: -------------------------------------------------------------------------------- 1 | # ---- GENERAL ---- 2 | 3 | [tasks.verify] 4 | description = "Format, lint with Clippy and run tests" 5 | dependencies = ["fmt", "clippy", "test_h_chrome"] 6 | 7 | [tasks.verify_only] 8 | description = "Like `verify`, but fails if the code isn't formatted. Primarily for CI." 9 | dependencies = ["fmt_check", "clippy", "test_h_chrome"] 10 | 11 | # ---- TEST ---- 12 | 13 | [tasks.test] 14 | description = "Run tests. Ex: 'cargo make test firefox'. Test envs: [chrome, firefox, safari]" 15 | clear = true 16 | install_crate = { crate_name = "wasm-pack", binary = "wasm-pack", test_arg = "-V" } 17 | command = "wasm-pack" 18 | args = ["test", "--${@}"] 19 | 20 | [tasks.test_release] 21 | extend = "test" 22 | description = "Run tests in release mode. Ex: 'cargo make test_release firefox'. Test envs: [chrome, firefox, safari]" 23 | args = ["test", "--${@}", "--release"] 24 | 25 | [tasks.test_h] 26 | description = "Run headless tests. Ex: 'cargo make test_h firefox'. Test envs: [chrome, firefox, safari]" 27 | extend = "test" 28 | args = ["test", "--headless", "--${@}"] 29 | 30 | [tasks.test_h_chrome] 31 | description = "Run headless tests with Chrome." 32 | extend = "test" 33 | args = ["test", "--headless", "--chrome"] 34 | 35 | [tasks.test_h_firefox] 36 | description = "Run headless tests with Firefox." 37 | extend = "test" 38 | args = ["test", "--headless", "--firefox"] 39 | 40 | [tasks.test_h_release] 41 | extend = "test_h" 42 | description = "Run headless tests in release mode. Ex: 'cargo make test_h firefox'. Test envs: [chrome, firefox, safari]" 43 | args = ["test", "--headless", "--${@}", "--release"] 44 | 45 | [tasks.test_one] 46 | description = "Run a single test in Firefox. Ex 'cargo make test_one my_test'" 47 | clear = true 48 | install_crate = { crate_name = "wasm-pack", binary = "wasm-pack", test_arg = "-V" } 49 | command = "wasm-pack" 50 | args = ["test", "--firefox", "--", "--lib", "${@}"] 51 | 52 | [tasks.test_one_h] 53 | description = "Run a single test in headless Firefox. Ex 'cargo make test_one_h my_test'" 54 | clear = true 55 | install_crate = { crate_name = "wasm-pack", binary = "wasm-pack", test_arg = "-V" } 56 | command = "wasm-pack" 57 | args = ["test", "--firefox", "--headless", "--", "--lib", "${@}"] 58 | 59 | # ---- LINT ---- 60 | 61 | [tasks.fmt] 62 | description = "Format with nightly rustfmt" 63 | toolchain = "nightly" 64 | command = "cargo" 65 | args = ["fmt", "--all"] 66 | 67 | [tasks.fmt_check] 68 | extend = "fmt" 69 | description = "Check format with nightly rustfmt" 70 | args = ["fmt", "--all", "--", "--check"] 71 | 72 | [tasks.clippy] 73 | description = "Lint with Clippy" 74 | clear = true 75 | install_crate = { rustup_component_name = "clippy", binary = "cargo-clippy", test_arg = "--help" } 76 | command = "cargo" 77 | args = ["clippy", "--all-features", "--", "--deny", "warnings", "--deny", "clippy::pedantic", "--deny", "clippy::nursery"] 78 | 79 | 80 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | [UNRELEASED] 4 | 5 | [0.7.5] 6 | 7 | - Updated dependencies (including Seed 0.8.0). 8 | 9 | [0.7.4] 10 | 11 | - Change dist output location 12 | - Temporarily switch test to Chrome - [Gecko fails](https://github.com/rustwasm/wasm-bindgen/issues/2261) 13 | 14 | [0.7.3] 15 | 16 | - Upgrade postcss-typed-css-classes to bring in bug fix 17 | 18 | [0.7.2] 19 | 20 | - Upgrade postcss-typed-css-classes 21 | 22 | [0.7.1] 23 | 24 | - dependabot > [Changelog](https://github.com/seed-rs/seed-quickstart-webpack/pull/21#issue-429231397) 25 | 26 | [0.7.0] 27 | 28 | - Moved files and directories located in `crate` directory to project root directory. 29 | - Moved files and directories located in `configs` directory to project root directory. 30 | - Moved files and directories located in `entries` directory to static directory. 31 | - Moved `entries/index.ts` to project root directoy. 32 | - Update/remove references to `crate`, `configs` and `entries` directories in configuration files and documentation. 33 | 34 | [0.6.0] 35 | 36 | - Updated all JS dependencies. 37 | - Added `` and related comments to support non-root deploys. 38 | - Updated all JS dependencies. 39 | - App adapted to Seed 0.7.0. 40 | - Disable unnecessary error message on the overlay. 41 | - App refactored. 42 | - Added `FUNDING.yml`. 43 | - Updated `README.md`. 44 | 45 | [0.5.0] 46 | 47 | - `Seed` updated to `0.6.0`. 48 | - [BREAKING] `wasm-pack` > `0.9.0` required. 49 | - Deleted unnecessary `optimize-wasm.js` script. 50 | - Minor `lib.rs` changes - removed `Clone` constraint on `Msg` and `prerendered` variable is replaced with a `Model`'s property. 51 | - Added `wasm_bindgen_test_configure!(run_in_browser);` into `test.rs`. 52 | - Disabled performance hints in `webpack.config.js`. 53 | - Removed `critters-webpack-plugin`. 54 | 55 | [0.4.1] 56 | 57 | - Ignore `clippy` lint rule `must_use_candidate`. 58 | - Optimized build (WASM file size changed from 584 to 349 KB). 59 | - `Seed` updated to `0.5.1` + updated `crate/src/lib.rs`. 60 | - Updated all Rust dependencies. 61 | - Updated all JS dependencies. 62 | 63 | [0.4.0] 64 | 65 | - `Seed` updated to `0.5.0` + refactored `crate/src/lib.rs`. 66 | - All Rust and JS dependencies updated. 67 | - GHA workflow `main.yml` - `on: [push]` changed to `on: [push, pull_request]`. 68 | 69 | [0.3.1] 70 | 71 | - `Travis CI` replaced with `Github Actions`. 72 | - `Seed` updated to `0.4.2` + refactored `crate/src/lib.rs`. 73 | 74 | [0.3.0] 75 | 76 | - Quickstart is now based on `https://github.com/MartinKavik/kavik.cz`. 77 | - Rewritten `README.md`. 78 | - Previous version moved into branch `older`. 79 | 80 | [0.2.0] 81 | 82 | - Updated all dependencies + project adapted to them: 83 | - Set `outDir` in `WasmPackPlugin`. 84 | - Removed `css/tailwind.js`. 85 | - Changed paths in `entries/index.ts`. 86 | - Removed comments from `css/styles.css`. 87 | - Updated CSS classes in `crate/src/app.rs`. 88 | - Updated import of `ClearnWepackPlugin`. 89 | - Dev server port changed from `3000` to `8000`. 90 | - Added `netlify.toml` for better SPA support. 91 | - `crate/*` changes: 92 | - Updated dependencies in `Cargo.toml` and `Seed` set to `master` (probably temporary). 93 | - Refactored `app.rs`, `lib.rs`, `rust_api.rs`, `clock.ts`, `ts_apis`, `seed_helpers.ts`. 94 | - Removed `seed_helpers.rs`. 95 | 96 | [0.1.0] 97 | 98 | - Initial version. 99 | -------------------------------------------------------------------------------- /static/images/cross.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /static/images/hellweb_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /static/images/hamburger.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const dist = path.resolve(__dirname, "dist"); 3 | 4 | const WebpackBar = require("webpackbar"); 5 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 6 | const WasmPackPlugin = require("@wasm-tool/wasm-pack-plugin"); 7 | const CopyWebpackPlugin = require("copy-webpack-plugin"); 8 | const { CleanWebpackPlugin } = require("clean-webpack-plugin"); 9 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 10 | 11 | module.exports = (env, argv) => { 12 | return { 13 | performance: { 14 | // Don't break compilation because of WASM file bigger than 244 KB. 15 | hints: false 16 | }, 17 | entry: { 18 | // Bundle root with name `app.js`. 19 | app: path.resolve(__dirname, "index.ts") 20 | }, 21 | output: { 22 | // You can change it to e.g. `/ui/`, but also edit `historyApiFallback` below and ` in `index.hbs`. 23 | publicPath: '/', 24 | // You can deploy your site from this folder (after build with e.g. `yarn build:release`) 25 | path: dist, 26 | filename: '[name].[contenthash].js' 27 | }, 28 | devServer: { 29 | contentBase: dist, 30 | // You can connect to dev server from devices in your network (e.g. 192.168.0.3:8000). 31 | host: "0.0.0.0", 32 | port: 8000, 33 | // Route everything to index to support SPA. It should be the same like `publicPath` above. 34 | historyApiFallback: { 35 | index: '/' 36 | }, 37 | noInfo: true, 38 | stats: "errors-only", 39 | overlay: { 40 | // Commented to prevent error: 41 | // `./crate/pkg/index_bg.js 382:14-53 Critical dependency: the request of a dependency is an expression` 42 | // warnings: true, 43 | errors: true 44 | }, 45 | }, 46 | devtool: "eval", 47 | experiments: { 48 | asyncWebAssembly: true, 49 | }, 50 | plugins: [ 51 | // Show compilation progress bar in console. 52 | new WebpackBar(), 53 | // Clean `dist` folder before compilation. 54 | new CleanWebpackPlugin(), 55 | // Extract CSS styles into a file. 56 | new MiniCssExtractPlugin({ 57 | filename: '[name].[contenthash].css' 58 | }), 59 | // Add scripts, css, ... to html template. 60 | new HtmlWebpackPlugin({ 61 | template: path.resolve(__dirname, "static/index.hbs") 62 | }), 63 | // Compile Rust. 64 | new WasmPackPlugin({ 65 | crateDirectory: __dirname 66 | }), 67 | 68 | // You can find files from folder `../static` on url `http://my-site.com/static/`. 69 | // And favicons in the root. 70 | new CopyWebpackPlugin({ 71 | patterns: [ 72 | { 73 | from: "static", 74 | to: "static" 75 | }, 76 | { 77 | from: "favicons", 78 | to: "" 79 | } 80 | ] 81 | }), 82 | ], 83 | // Webpack try to guess how to resolve imports in this order: 84 | resolve: { 85 | extensions: [".ts", ".js", ".wasm"], 86 | alias: { 87 | crate: __dirname 88 | } 89 | }, 90 | module: { 91 | rules: [ 92 | { 93 | test: /\.hbs$/, 94 | use: [ 95 | { 96 | loader: "handlebars-loader", 97 | options: { 98 | rootRelative: './templates/' 99 | } 100 | } 101 | ] 102 | }, 103 | { 104 | test: /\.(jpg|jpeg|png|woff|woff2|eot|ttf|svg)$/, 105 | use: [ 106 | { 107 | loader: "file-loader", 108 | options: { 109 | // Don't copy files to `dist`, we do it through `CopyWebpackPlugin` (see above) 110 | // - we only want to resolve urls to these files. 111 | emitFile: false, 112 | name: "[path][name].[ext]" 113 | } 114 | } 115 | ] 116 | }, 117 | { 118 | test: /\.ts$/, 119 | use: [ 120 | { 121 | loader: "ts-loader", 122 | options: { 123 | configFile: "tsconfig.css_classes.json" 124 | } 125 | } 126 | ] 127 | 128 | }, 129 | { 130 | test: /\.css$/, 131 | use: [ 132 | MiniCssExtractPlugin.loader, 133 | "css-loader", 134 | { 135 | loader: "postcss-loader", 136 | options: { 137 | postcssOptions: { 138 | config: path.resolve(__dirname, "postcss.config.js"), 139 | } 140 | }, 141 | }, 142 | ] 143 | } 144 | ] 145 | } 146 | }; 147 | }; 148 | -------------------------------------------------------------------------------- /static/images/seed_logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // @TODO: uncomment once https://github.com/rust-lang/rust/issues/54726 stable 2 | //#![rustfmt::skip::macros(class)] 3 | 4 | #![allow( 5 | clippy::used_underscore_binding, 6 | clippy::non_ascii_literal, 7 | clippy::enum_glob_use, 8 | clippy::must_use_candidate, 9 | clippy::wildcard_imports 10 | )] 11 | 12 | mod generated; 13 | mod page; 14 | 15 | use fixed_vec_deque::FixedVecDeque; 16 | use generated::css_classes::C; 17 | use seed::{prelude::*, *}; 18 | use Visibility::*; 19 | 20 | const TITLE_SUFFIX: &str = "Kavik.cz"; 21 | // https://mailtolink.me/ 22 | const MAIL_TO_KAVIK: &str = "mailto:martin@kavik.cz?subject=Something%20for%20Martin&body=Hi!%0A%0AI%20am%20Groot.%20I%20like%20trains."; 23 | const MAIL_TO_HELLWEB: &str = 24 | "mailto:martin@hellweb.app?subject=Hellweb%20-%20pain&body=Hi!%0A%0AI%20hate"; 25 | const USER_AGENT_FOR_PRERENDERING: &str = "ReactSnap"; 26 | const STATIC_PATH: &str = "static"; 27 | const IMAGES_PATH: &str = "static/images"; 28 | 29 | const ABOUT: &str = "about"; 30 | 31 | // ------ ------ 32 | // Init 33 | // ------ ------ 34 | 35 | fn init(url: Url, orders: &mut impl Orders) -> Model { 36 | orders 37 | .subscribe(Msg::UrlChanged) 38 | .stream(streams::window_event(Ev::Scroll, |_| Msg::Scrolled)); 39 | 40 | Model { 41 | base_url: url.to_base_url(), 42 | page: Page::init(url), 43 | scroll_history: ScrollHistory::new(), 44 | menu_visibility: Hidden, 45 | in_prerendering: is_in_prerendering(), 46 | } 47 | } 48 | 49 | fn is_in_prerendering() -> bool { 50 | let user_agent = 51 | window().navigator().user_agent().expect("cannot get user agent"); 52 | 53 | user_agent == USER_AGENT_FOR_PRERENDERING 54 | } 55 | 56 | // ------ ------ 57 | // Model 58 | // ------ ------ 59 | 60 | #[derive(Clone, Copy, Eq, PartialEq)] 61 | pub enum Visibility { 62 | Visible, 63 | Hidden, 64 | } 65 | 66 | impl Visibility { 67 | pub fn toggle(&mut self) { 68 | *self = match self { 69 | Visible => Hidden, 70 | Hidden => Visible, 71 | } 72 | } 73 | } 74 | 75 | // We need at least 3 last values to detect scroll direction, 76 | // because neighboring ones are sometimes equal. 77 | type ScrollHistory = FixedVecDeque<[i32; 3]>; 78 | 79 | pub struct Model { 80 | pub base_url: Url, 81 | pub page: Page, 82 | pub scroll_history: ScrollHistory, 83 | pub menu_visibility: Visibility, 84 | pub in_prerendering: bool, 85 | } 86 | 87 | // ------ Page ------ 88 | 89 | #[derive(Clone, Copy, Eq, PartialEq)] 90 | pub enum Page { 91 | Home, 92 | About, 93 | NotFound, 94 | } 95 | 96 | impl Page { 97 | pub fn init(mut url: Url) -> Self { 98 | let (page, title) = match url.remaining_path_parts().as_slice() { 99 | [] => (Self::Home, TITLE_SUFFIX.to_owned()), 100 | [ABOUT] => (Self::About, format!("About - {}", TITLE_SUFFIX)), 101 | _ => (Self::NotFound, format!("404 - {}", TITLE_SUFFIX)), 102 | }; 103 | document().set_title(&title); 104 | page 105 | } 106 | } 107 | 108 | // ------ ------ 109 | // Urls 110 | // ------ ------ 111 | 112 | struct_urls!(); 113 | impl<'a> Urls<'a> { 114 | pub fn home(self) -> Url { 115 | self.base_url() 116 | } 117 | 118 | pub fn about(self) -> Url { 119 | self.base_url().add_path_part(ABOUT) 120 | } 121 | } 122 | 123 | // ------ ------ 124 | // Update 125 | // ------ ------ 126 | 127 | pub enum Msg { 128 | UrlChanged(subs::UrlChanged), 129 | ScrollToTop, 130 | Scrolled, 131 | ToggleMenu, 132 | HideMenu, 133 | } 134 | 135 | pub fn update(msg: Msg, model: &mut Model, _: &mut impl Orders) { 136 | match msg { 137 | Msg::UrlChanged(subs::UrlChanged(url)) => { 138 | model.page = Page::init(url); 139 | }, 140 | Msg::ScrollToTop => window().scroll_to_with_scroll_to_options( 141 | web_sys::ScrollToOptions::new().top(0.), 142 | ), 143 | Msg::Scrolled => { 144 | // Some browsers use `document.body.scrollTop` 145 | // and other ones `document.documentElement.scrollTop`. 146 | let mut position = body().scroll_top(); 147 | if position == 0 { 148 | position = document() 149 | .document_element() 150 | .expect("get document element") 151 | .scroll_top() 152 | } 153 | *model.scroll_history.push_back() = position; 154 | }, 155 | Msg::ToggleMenu => model.menu_visibility.toggle(), 156 | Msg::HideMenu => { 157 | model.menu_visibility = Hidden; 158 | }, 159 | } 160 | } 161 | 162 | // ------ ------ 163 | // View 164 | // ------ ------ 165 | 166 | // Notes: 167 | // - \u{00A0} is the non-breaking space 168 | // - https://codepoints.net/U+00A0 169 | // 170 | // - "▶\u{fe0e}" - \u{fe0e} is the variation selector, it prevents ▶ to change to emoji in some browsers 171 | // - https://codepoints.net/U+FE0E 172 | 173 | pub fn view(model: &Model) -> impl IntoNodes { 174 | div![ 175 | C![ 176 | IF!(not(model.in_prerendering) => C.fade_in), 177 | C.min_h_screen, 178 | C.flex, 179 | C.flex_col, 180 | ], 181 | match model.page { 182 | Page::Home => page::home::view(&model.base_url), 183 | Page::About => page::about::view(), 184 | Page::NotFound => page::not_found::view(), 185 | }, 186 | page::partial::header::view(model), 187 | page::partial::footer::view(), 188 | ] 189 | } 190 | 191 | pub fn image_src(image: &str) -> String { 192 | format!("{}/{}", IMAGES_PATH, image) 193 | } 194 | 195 | pub fn asset_path(asset: &str) -> String { 196 | format!("{}/{}", STATIC_PATH, asset) 197 | } 198 | 199 | // ------ ------ 200 | // Start 201 | // ------ ------ 202 | 203 | #[wasm_bindgen(start)] 204 | pub fn run() { 205 | log!("Starting app..."); 206 | 207 | App::start("app", init, update, view); 208 | 209 | log!("App started."); 210 | } 211 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | // [...range(1,5,2)] => [1,3,5] 2 | function* range(start, end, step) { 3 | if(start > end) return; 4 | yield start; 5 | yield* range(start + step, end, step); 6 | }; 7 | 8 | // For NodeJS < 12 9 | Object.fromEntries = Object.fromEntries || ((iterable) => { 10 | return [...iterable].reduce((obj, [key, val]) => { 11 | obj[key] = val 12 | return obj 13 | }, {}) 14 | }); 15 | 16 | module.exports = { 17 | theme: { 18 | screens: { 19 | 'sm': '569px', 20 | // => @media (min-width: 569px) { ... } 21 | 22 | 'md': '769px', 23 | // => @media (min-width: 769px) { ... } 24 | 25 | 'lg': '1025px', 26 | // => @media (min-width: 1025px) { ... } 27 | 28 | 'xl': '1701px', 29 | // => @media (min-width: 1701px) { ... } 30 | }, 31 | fontFamily: { 32 | display: ['Metropolis', 'sans-serif'], 33 | body: ['Inter', 'sans-serif'], 34 | monospace: ['Courier New', 'monospace'], 35 | ordinary: ['Arial', 'sans-serif'], 36 | sans: ['-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 37 | 'Noto Sans', 'sans-serif', 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'] 38 | }, 39 | fontSize: (() => { 40 | return Object.fromEntries([ 41 | ...range(15, 35, 1), 42 | ...range(40, 60, 5), 43 | ...range(70, 120, 10) 44 | ].map(i => [i, `${i}px`])) 45 | })(), 46 | colors: { 47 | black: "#000", 48 | gray: { 49 | 1: 'hsl(210, 36%, 96%)', 50 | 2: 'hsl(212, 33%, 89%)', 51 | 3: 'hsl(210, 31%, 80%)', 52 | 4: 'hsl(211, 27%, 70%)', 53 | 5: 'hsl(209, 23%, 60%)', 54 | 6: 'hsl(210, 22%, 49%)', 55 | 7: 'hsl(209, 28%, 39%)', 56 | 8: 'hsl(209, 34%, 30%)', 57 | 9: 'hsl(211, 39%, 23%)', 58 | 10: 'hsl(209, 61%, 16%)', 59 | }, 60 | blue: { 61 | 1: 'hsl(205, 79%, 92%)', 62 | 2: 'hsl(205, 97%, 85%)', 63 | 3: 'hsl(205, 84%, 74%)', 64 | 4: 'hsl(205, 74%, 65%)', 65 | 5: 'hsl(205, 65%, 55%)', 66 | 6: 'hsl(205, 67%, 45%)', 67 | 7: 'hsl(205, 76%, 39%)', 68 | 8: 'hsl(205, 82%, 33%)', 69 | 9: 'hsl(205, 87%, 29%)', 70 | 10: 'hsl(205, 100%, 21%)', 71 | }, 72 | yellow: { 73 | 1: 'hsl(49, 100%, 96%)', 74 | 2: 'hsl(48, 100%, 88%)', 75 | 3: 'hsl(48, 95%, 76%)', 76 | 4: 'hsl(48, 94%, 68%)', 77 | 5: 'hsl(44, 92%, 63%)', 78 | 6: 'hsl(42, 87%, 55%)', 79 | 7: 'hsl(36, 77%, 49%)', 80 | 8: 'hsl(29, 80%, 44%)', 81 | 9: 'hsl(22, 82%, 39%)', 82 | 10: 'hsl(15, 86%, 30%)', 83 | }, 84 | }, 85 | opacity: (() => { 86 | return Object.fromEntries([ 87 | ...range(0, 100, 10), 88 | ].map(i => [i, i / 100])) 89 | })(), 90 | extend: { 91 | boxShadow: { 92 | '2xl-above': '0 25px 50px 15px rgba(0, 0, 0, 0.25), 0 10px 10px 10px rgba(0, 0, 0, 0.25)', 93 | 'glow': '0 0 5px 2px hsl(205, 97%, 85%)' 94 | }, 95 | margin: { 96 | '-10vh': '-10vh', 97 | '10vw': '10vw', 98 | '-30': '-7.5rem', 99 | '-80': '-20rem', 100 | '-92': '-23rem', 101 | '-120': '-30rem', 102 | '-260px': '-260px', 103 | '-545px': '-545px', 104 | '-670px': '-670px', 105 | '-820px': '-820px', 106 | '-1230px': '-1230px', 107 | '38': '9.5rem', 108 | '72': '18rem', 109 | '96': '24rem', 110 | '108': '27rem', 111 | '132': '33rem', 112 | '310px': '310px', 113 | '790px': '790px', 114 | '1290px': '1290px', 115 | '1310px': '1310px', 116 | '1760px': '1760px', 117 | '2340px': '2340px', 118 | '2840px': '2840px', 119 | '3040px': '3040px', 120 | '3870px': '3870px', 121 | '5030px': '5030px', 122 | '6070px': '6070px', 123 | }, 124 | padding: { 125 | '84': '21rem', 126 | '96': '24rem', 127 | }, 128 | inset: { 129 | '1/2': '50%', 130 | 'full': '100%', 131 | '-full': '-100%', 132 | '-50vw': '-50vw', 133 | }, 134 | width: { 135 | '36': '9rem', 136 | '76': '19rem', 137 | 'xs': '20rem', 138 | '96': '24rem', 139 | '100': '25rem', 140 | 'md': '28rem', 141 | '120': '30rem', 142 | '132': '33rem', 143 | '204': '51rem', 144 | '216': '54rem', 145 | '236': '59rem', 146 | '70px': '70px', 147 | '265px': '265px', 148 | '385px': '385px', 149 | '520px': '520px', 150 | '570px': '570px', 151 | '750px': '750px', 152 | '860px': '860px', 153 | '900px': '900px', 154 | '1090px': '1090px', 155 | '1240px': '1240px', 156 | '1300px': '1300px', 157 | '1640px': '1640px', 158 | '2460px': '2460px', 159 | '2560px': '2560px', 160 | '50vh': '50vh', 161 | '50vw': '50vw', 162 | }, 163 | maxWidth: { 164 | 'none': 'none', 165 | '8xl': '88rem', 166 | '400': '100rem', 167 | }, 168 | height: { 169 | '18': '4.5rem', 170 | '72': '18rem', 171 | '3px': '3px', 172 | '300px': '300px', 173 | '320px': '320px', 174 | '360px': '360px', 175 | '420px': '420px', 176 | '550px': '550px', 177 | '570px': '570px', 178 | '580px': '580px', 179 | '600px': '600px', 180 | '690px': '690px', 181 | '790px': '790px', 182 | '860px': '860px', 183 | '890px': '890px', 184 | '930px': '930px', 185 | '980px': '980px', 186 | '1090px': '1090px', 187 | '1160px': '1160px', 188 | '1240px': '1240px', 189 | '1300px': '1300px', 190 | '1340px': '1340px', 191 | '1420px': '1420px', 192 | '1580px': '1580px', 193 | '2330px': '2330px', 194 | '2360px': '2360px', 195 | '2560px': '2560px', 196 | '3670px': '3670px', 197 | }, 198 | borderRadius: { 199 | '28px': '28px', 200 | '45px': '45px', 201 | '55px': '55px', 202 | '90px': '90px', 203 | '110px': '110px', 204 | '140px': '140px', 205 | '260px': '260px', 206 | '330px': '330px', 207 | } 208 | } 209 | }, 210 | variants: {}, 211 | plugins: [] 212 | } 213 | -------------------------------------------------------------------------------- /favicons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 72 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Seed Quickstart with Webpack 2 | 3 | [![Netlify Status](https://api.netlify.com/api/v1/badges/745c7b1d-5894-4f58-be28-e730a11e1ff4/deploy-status)](https://app.netlify.com/sites/quickstart-webpack/deploys) 4 | 5 | 6 | > I want to write fast, reliable and efficient web apps. Quickly. \ 7 | And I like Rust and documentation. 8 | 9 | --- 10 | 11 | **!!! New Rust-only quickstart in development! => [Seeder](https://github.com/MartinKavik/seeder) !!!** 12 | 13 | --- 14 | 15 | ~~**LIVE DEMO**: quickstart-webpack.seed-rs.org~~ 16 | 17 | Main components: 18 | 19 | - **Seed** - Rust framework, inspired by Elm. [Seed's Awesome list](https://github.com/seed-rs/awesome-seed-rs). 20 | - **[Tailwind CSS](https://tailwindcss.com/)** - CSS framework. All CSS classes in your project are typed for safe use in Rust code. Unused classes are automatically deleted for much smaller bundle size. 21 | - **[Webpack](https://webpack.js.org/)** - Bundler. Auto-reload on code change, dev-server accessible from mobile phones, prerendering for static websites... and many more useful features are prepared for you in this quickstart. 22 | - Why Webpack instead of Rust-only build pipeline? - [Wiki](https://github.com/seed-rs/seed-quickstart-webpack/wiki/Why-Webpack) 23 | - **Production-ready starter project** - Example project is based on the website with several pages, favicons, nice fonts, meta tags for social media, buttons for scrolling to top, header which is hidden on scrolling, etc. It can be prerendered, but it also contains loading screen. 24 | For more complex project (based on another quickstart) see [seed-rs-realworld](https://github.com/seed-rs/seed-rs-realworld). 25 | - **Production-ready configuration** - Project is linted, compiled, prerendered and deployed in CI pipeline (see `.github/workflows/main.yml` and `netlify.toml`). Linters are very strict. 26 | 27 | --- 28 | 29 | # Zero to Hero 30 | 31 | > How to create your new app, modify it and deploy it - step by step guide. 32 | 33 | ## 1. Create a new project 34 | 35 | I want to show you how to create, build and host your website for free, so we will need a public GitHub repository. 36 | 37 | 1. The simplest way how to do it is to click on the green button **Use this template** on the GitHub [profile](https://github.com/seed-rs/seed-quickstart-webpack) of this quickstart. 38 | 39 | 1. Make sure Git doesn't automatically convert your newlines to CLRF because linters don't like it. 40 | - Run `$ git config --global core.autocrlf` in your terminal and it should return `input` or `false`. See [Git docs](https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration) for more info. 41 | 42 | 1. Clone your new repository to your local machine. I use [GitKraken](https://www.gitkraken.com/), but you are probably better developer than me - use your favorite terminal. 43 | 44 | ## 2. Install / check required tools 45 | 46 | 1. Make sure you have basic tools installed: 47 | 48 | - [Yarn](https://yarnpkg.com/lang/en/docs/install) - run `$ yarn -v` in terminal. It should output something like `1.22.4` 49 | - [Node.js](https://nodejs.org) - `$ node -v` => `v12.13.0` 50 | - [Rust](https://www.rust-lang.org/tools/install) - `$ rustc -V` => `rustc 1.43.1 (8d69840ab 2020-05-04)` 51 | - Rust target `wasm` - `$ rustup target list` => `.. wasm32-unknown-unknown (installed) ..` 52 | - Install: `$ rustup target add wasm32-unknown-unknown` 53 | 54 | 1. Platform-specific tools like `ssl` and `pkg-config`: 55 | - Follow recommendations in build errors (during the next chapter). 56 | - _Note_: Don't hesitate to write a tutorial and create PR or write a Wiki page for your platform. 57 | 58 | 1. These tools are required by some commands: 59 | 60 | - [wasm-pack](https://rustwasm.github.io/wasm-pack/) 61 | 62 | - Check: `$ wasm-pack -V` => `wasm-pack 0.9.1` 63 | - Install: `$ cargo install wasm-pack` 64 | 65 | - [cargo-make](https://sagiegurari.github.io/cargo-make/) 66 | 67 | - Check: `$ cargo make -V` => `cargo-make 0.30.7` 68 | - Install: `$ cargo install cargo-make` 69 | 70 | - [nightly rustfmt](https://github.com/rust-lang/rustfmt#on-the-nightly-toolchain) 71 | - Check: `$ cargo +nightly fmt -- -V` => `rustfmt 1.4.14-nightly (a5cb5d26 2020-04-14)` 72 | - Install: 73 | 1. `$ rustup toolchain install nightly` 74 | 2. `$ rustup component add rustfmt --toolchain nightly` 75 | 76 | ## 3. Prepare your project for work 77 | 78 | 1. Open terminal in your project 79 | 1. Install Webpack and other dependencies - `$ yarn` 80 | 1. Try to start dev-server - `$ yarn start` - and then open [localhost:8000](http://localhost:8000) in a browser. 81 | 1. Stop server (try `Ctrl+c`). 82 | 1. Try to lint your project - `$ cargo make verify_only` - you shouldn't see any errors. 83 | 1. Modify files like `LICENCE`, `README.md` and `Cargo.toml` as you wish and push changes into GitHub. 84 | 85 | ## 4. Write your website 86 | 87 | 1. Open project in your favorite IDE. I use [IntelliJ](https://www.jetbrains.com/idea/download) or [VS Code](https://code.visualstudio.com/). 88 | 1. Run `$ yarn start` in terminal. 89 | 1. Open [localhost:8000](http://localhost:8000) in a browser. 90 | 1. You can open it also in your mobile phone: 91 | 1. Make sure your dev-server aka computer is in the same network as your phone. 92 | 1. Find out your local IP address. Use e.g. this online tool: https://www.whatismybrowser.com/detect/what-is-my-local-ip-address. 93 | 1. Open URL with found IP address and default port (e.g. `192.168.1.5:8000`) on your phone. 94 | 95 | _Note_: You don't have to follow all steps below - reuse starter project code as you need. 96 | 97 | ### Header 98 | 99 | 1. Open `src/page/partial/header.rs` in your IDE. 100 | 1. Delete function `header_visibility`. 101 | 1. Write a new body for function `view`. 102 | 103 | ### Footer 104 | 105 | 1. Open `src/page/partial/footer.rs` in your IDE. 106 | 1. Write a new body for function `view`. 107 | 108 | ### 404 109 | 110 | 1. Open `src/page/not_found.rs` in your IDE. 111 | 1. Write a new body for function `view`. 112 | 113 | ### Home page 114 | 115 | 1. Open `src/page/home.rs` in your IDE. 116 | 1. Write a new body for function `view`. 117 | 118 | ### About page 119 | 120 | 1. Open `src/page/about.rs` in your IDE. 121 | 1. Write a new body for function `view`. 122 | 123 | ### App core 124 | 125 | 1. Open `src/lib.rs` in your IDE. 126 | 1. Change `TITLE_SUFFIX` value. 127 | 1. Delete `MAIL_TO_KAVIK` and `MAIL_TO_HELLWEB`. 128 | 1. Write a new body for function `view`. 129 | 130 | ### Favicons 131 | 132 | 1. Delete or replace files in `/favicons`. 133 | 1. Open `static/templates/favicons.hbs` in your IDE. 134 | 1. Delete content or update it. 135 | - _Note_: Templates are written in [Handlebars](https://handlebarsjs.com/). 136 | 137 | ### Loading page 138 | 139 | 1. Open `static/templates/loading_page.hbs` in your IDE. 140 | 1. Delete content or update it. 141 | 142 | ### Social media & basic settings 143 | 144 | 1. Open `static/templates/social_media.hbs` in your IDE. 145 | 1. Delete content or update it. 146 | 147 | ### Basic HTML 148 | 149 | 1. Open `static/index.hbs` in your IDE. 150 | 1. Update content. 151 | 152 | ### Fonts 153 | 154 | 1. Delete or replace files and directories in `static/fonts`. 155 | 1. Open `/css/fonts.css` in your IDE. 156 | 1. Delete content or update it. 157 | 158 | ### Images & other files 159 | 160 | 1. Delete or replace files in `static/images`. 161 | 1. Delete `static/Martin_Kavik_resume.pdf`. 162 | 163 | ### TailwindCSS 164 | 165 | 1. Open `tailwind.config.js` in your IDE. 166 | 1. Update content or replace it with the default one: 167 | 168 | ```js 169 | module.exports = { 170 | theme: {}, 171 | variants: {}, 172 | plugins: [] 173 | }; 174 | ``` 175 | 176 | ### Custom CSS 177 | 178 | 1. Open `/css/custom.css` in your IDE. 179 | 1. Delete content or update it. 180 | 181 | ## 5. Prepare your project for deploy 182 | 183 | How to format, lint and test your project. 184 | 185 | And how to setup Github Actions with deploy into Netlify. 186 | 187 | ### Formatter & Linter 188 | 189 | 1. Format: `$ cargo make fmt` (it overwrites files) or only `$ cargo make fmt_check` 190 | 1. You can modify format settings in: 191 | - `rustfmt.toml` 192 | - `Makefile.toml` - tasks `fmt` and `fmt_check` 193 | 1. Lint: `$ cargo make clippy` 194 | 1. You can modify linter settings in: 195 | - `Makefile.toml` - task `clippy` 196 | 197 | ### Testing 198 | 199 | 1. Run `$ cargo make test_h firefox` for headless testing in Firefox. 200 | - There are more similar commands - see `Makefile.toml` 201 | - _Note_: There is only one test in this project (`tests/test.rs`), see [seed-rs-realworld](https://github.com/seed-rs/seed-rs-realworld) for more examples. 202 | 1. If you want to test prerendered website: 203 | 1. `$ yarn build:prerender` 204 | 1. `$ yarn serve:dist` 205 | 1. Open [localhost:8000](http://localhost:8000) in a browser. 206 | 1. _Tip_: Always test it also in production environment because e.g. routing is a little bit different among servers. 207 | 1. **Always run `$ cargo make verify`** before push to make sure CI pipeline will accept your code. 208 | - It'll format your code, lint it and start headless tests in Firefox. 209 | - You can change its behaviour in `Makefile.tom` - task `verify` (similar task `verify_only` is used in CI). 210 | 211 | ### Netlify 212 | 213 | 1. Create a new [Netlify](https://www.netlify.com/) site. 214 | 1. _[Optional]_ Change site name or/and use your own domain. 215 | 1. _[Optional]_ Turn on HTTPS. 216 | 1. _[Optional]_ Add badge to project's `/README.md` (Site detail > `Settings` > `General` > `Status badges`). 217 | 1. Note somewhere **Site id** (Site detail > `Settings` > `General` > _API ID_) 218 | 1. Create and note somewhere **Access token** (Click on your avatar > `User settings` > `Applications` > `New access token` > Name it for instance `GitHub`) 219 | 1. _[Optional]_ Adjust `/netlify.toml` to suit your needs. [Netlify docs](https://www.netlify.com/docs/netlify-toml-reference/). 220 | 221 | ### Github Actions 222 | 223 | 1. Open your GitHub repository in your favorite browser. 224 | 1. Click on `Settings` and then on `Secrets`. 225 | 1. Add _secret_ `NETLIFY_SITE_ID` and set it's value to **Site id**. 226 | 1. Add _secret_ `NETLIFY_ACCESS_TOKEN` and set it's value to **Access token**. 227 | 1. Click on `Actions` in the side menu and make sure that `Actions` are enabled. 228 | 1. _[Optional]_ Modify `/.github/workflows/main.yml`. 229 | - Replace `yarn build:prerender` with `yarn build:release` if you don't want to prerender pages. 230 | 1. _[Optional]_ Push your code and switch to tab `Actions` to check that everything works. 231 | 232 | ### Manual Deployment 233 | 234 | 1. Run `yarn build:realease`. 235 | 1. Check if build works by running `yarn serve:dist` and view in a browser. 236 | 1. Deploy the contents of the `dist` directory to a web server. 237 | 238 | ### Travis CI 239 | 240 |
241 | Content (this guide and related config file are not maintained) 242 | 243 | 1. Sync your [TravisCI](https://travis-ci.org/) account with your GitHub one. 244 | 1. Find repository with your app in [your list](https://travis-ci.org/account/repositories) and click on `Settings`. 245 | 1. Add _Environment Variable_ `NETLIFY_SITE_ID` and set it's value to **Site id**. 246 | 1. Add _Environment Variable_ `NETLIFY_ACCESS_TOKEN` and set it's value to **Access token**. 247 | 1. Switch to tab `Current` and click `Activate repository`. 248 | 1. _[Optional]_ Add badge to project's `/README.md` (Repository detail > Click on badge next to the rep. name > `IMAGE URL` change to `MARKDOWN`) 249 | 1. _[Optional]_ Modify `/.travis.yml`. 250 | - Replace `yarn build:prerender` with `yarn build:release` if you don't want to prerender pages. 251 | - _Tip:_ If jobs don't want to start after push, check Repository detail > `More options` > `Requests`. 252 | 253 |
254 | 255 | ## 6. Add your project to Awesome list 256 | 257 | 1. Create PR or issue in [awesome-seed-rs](https://github.com/seed-rs/awesome-seed-rs). 258 | 259 | --- 260 | 261 | # Used in projects 262 | 263 | - ~~seed-rs/seed-rs.org~~ 264 | - [MartinKavik/kavik.cz](https://github.com/MartinKavik/kavik.cz) 265 | - _[create PR or Issue]_ 266 | 267 | # Contributing 268 | 269 | - Improved documentation, fixed typos, updated dependencies, ... - create Issue or PR. 270 | - Ideas, bugs, questions, ... - create Issue. 271 | 272 | _Note_: Please squash commits and rebase before creating PR. Thanks! 273 | 274 | --- 275 | 276 | ## Other Seed projects 277 | 278 | - [seed-rs/awesome-seed-rs](https://github.com/seed-rs/awesome-seed-rs) 279 | -------------------------------------------------------------------------------- /src/page/partial/header.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | asset_path, 3 | generated::css_classes::C, 4 | image_src, Model, Msg, Page, ScrollHistory, Urls, 5 | Visibility::{self, *}, 6 | }; 7 | use seed::{prelude::*, *}; 8 | 9 | fn header_visibility( 10 | menu_visibility: Visibility, 11 | scroll_history: &ScrollHistory, 12 | ) -> Visibility { 13 | let menu_is_visible = menu_visibility == Visible; 14 | // You can go higher on the mobile phones. 15 | let at_the_top_or_higher = *scroll_history.back().unwrap_or(&0) <= 0; 16 | let scrolling_up = scroll_history.front() >= scroll_history.back(); 17 | 18 | if menu_is_visible || at_the_top_or_higher || scrolling_up { 19 | return Visible; 20 | } 21 | Hidden 22 | } 23 | 24 | #[allow(clippy::too_many_lines)] 25 | pub fn view(model: &Model) -> Vec> { 26 | let show_header = 27 | header_visibility(model.menu_visibility, &model.scroll_history) 28 | == Visible; 29 | nodes![ 30 | // Header background and line container 31 | IF!(show_header => 32 | div![ 33 | C![ 34 | C.fixed, 35 | C.top_0 36 | C.inset_x_0, 37 | C.h_16, 38 | // sm__ 39 | C.sm__h_24, 40 | ], 41 | // Header background 42 | div![C![C.absolute, C.inset_0, C.bg_gray_1, C.opacity_90]], 43 | // Bottom header line 44 | div![ 45 | C![ 46 | C.absolute, 47 | C.bottom_0, 48 | C.ml_12, 49 | C.w_3of5, 50 | C.h_px, 51 | // sm__ 52 | C.sm__ml_0, 53 | C.sm__w_full, 54 | C.sm__h_3px 55 | C.sm__flex, 56 | C.sm__justify_center, 57 | // md__ 58 | C.md___ml_30, 59 | ], 60 | div![C![ 61 | C.h_full, 62 | C.bg_gray_2, 63 | // sm__ 64 | C.sm__ml_6, 65 | C.sm__w_48, 66 | IF!(model.page == Page::Home => C.sm__bg_yellow_6), 67 | ],], 68 | div![C![ 69 | C.hidden, 70 | // sm__ 71 | C.sm__block, 72 | C.sm__h_full, 73 | C.sm__bg_gray_2, 74 | C.sm__w_24, 75 | IF!(model.page == Page::About => C.sm__bg_yellow_6), 76 | ],] 77 | ], 78 | ] 79 | ), 80 | // Photo 1 81 | IF!(model.page == Page::About => 82 | div![ 83 | C![ 84 | C.absolute, 85 | C.top_0, 86 | C.inset_x_0, 87 | C.mt_6, 88 | C.flex, 89 | C.justify_center 90 | // sm__ 91 | C.sm__mt_10, 92 | // md__ 93 | C.md__mt_8, 94 | ], 95 | img![ 96 | C![ 97 | C.w_xs, 98 | C.h_full, 99 | C.object_contain, 100 | // sm__ 101 | C.sm__w_100, 102 | // lg 103 | C.lg__w_570px, 104 | ], 105 | attrs! { 106 | At::Src => image_src("photo_1.png") 107 | } 108 | ], 109 | ] 110 | ), 111 | // Menu 112 | IF!(model.menu_visibility == Visible => 113 | div![ 114 | C![ 115 | C.fixed, 116 | C.w_screen, 117 | C.bg_gray_1, 118 | C.opacity_90, 119 | C.h_screen, 120 | // md__ 121 | C.md__hidden, 122 | ], 123 | div![ 124 | C![C.w_56, C.mx_auto, C.flex, C.max_h_full,], 125 | ul![ 126 | C![ 127 | C.mt_20, 128 | C.w_full, 129 | C.font_semibold, 130 | C.text_gray_10, 131 | C.flex, 132 | C.flex_col, 133 | C.mb_12, 134 | C.overflow_y_auto, 135 | // sm__ 136 | C.sm__mt_24, 137 | C.sm__text_21, 138 | ], 139 | li![ 140 | C![ 141 | C.block, 142 | C.h_full, 143 | C.border_l_4, 144 | C.border_r_4, 145 | if model.page == Page::Home { 146 | C.border_yellow_6 147 | } else { 148 | C.border_gray_2 149 | }, 150 | C.w_full, 151 | // sm__ 152 | C.sm__hidden, 153 | ], 154 | a![ 155 | C![ 156 | C.pl_8, 157 | C.h_full, 158 | C.flex, 159 | C.items_center, 160 | C.hover__text_yellow_7, 161 | C.outline_none, 162 | C.py_6, 163 | ], 164 | attrs! { 165 | At::Href => Urls::new(&model.base_url).home() 166 | }, 167 | ev(Ev::Click, |_| Msg::ScrollToTop), 168 | ev(Ev::Click, |_| Msg::HideMenu), 169 | "Home & Projects" 170 | ] 171 | ], 172 | li![ 173 | C![ 174 | C.block, 175 | C.h_full, 176 | C.border_l_4, 177 | C.border_r_4, 178 | if model.page == Page::About { 179 | C.border_yellow_6 180 | } else { 181 | C.border_gray_2 182 | }, 183 | C.w_full, 184 | // sm__ 185 | C.sm__hidden, 186 | ], 187 | a![ 188 | C![ 189 | C.pl_8, 190 | C.h_full, 191 | C.flex, 192 | C.items_center, 193 | C.hover__text_yellow_7, 194 | C.outline_none, 195 | C.py_6, 196 | ], 197 | attrs! { 198 | At::Href => Urls::new(&model.base_url).about() 199 | }, 200 | ev(Ev::Click, |_| Msg::ScrollToTop), 201 | ev(Ev::Click, |_| Msg::HideMenu), 202 | "About" 203 | ] 204 | ], 205 | li![ 206 | C![C.block, C.h_full, C.w_full,], 207 | a![ 208 | C![ 209 | C.pl_8, 210 | C.h_full, 211 | C.flex, 212 | C.items_center, 213 | C.hover__text_yellow_7, 214 | C.py_6, 215 | // sm__ 216 | C.sm__py_8, 217 | C.sm__pl_0, 218 | C.sm__justify_center, 219 | ], 220 | attrs! { 221 | At::Href => asset_path("Martin_Kavik_resume.pdf") 222 | }, 223 | ev(Ev::Click, |_| Msg::HideMenu), 224 | "Resume", 225 | span![C![C.text_gray_5,], ".pdf"] 226 | ] 227 | ], 228 | li![ 229 | C![C.block, C.h_full, C.w_full,], 230 | a![ 231 | C![ 232 | C.pl_8, 233 | C.h_full, 234 | C.flex, 235 | C.items_center, 236 | C.hover__text_yellow_7, 237 | C.py_6, 238 | // sm__ 239 | C.sm__py_8, 240 | C.sm__pl_0, 241 | C.sm__justify_center, 242 | ], 243 | attrs! { 244 | At::Href => "https://github.com/MartinKavik" 245 | }, 246 | ev(Ev::Click, |_| Msg::HideMenu), 247 | "GitHub", 248 | img![ 249 | C![ 250 | C.inline 251 | C.mb_3, 252 | C.w_3, 253 | // sm__ 254 | C.sm__mb_5, 255 | C.sm__ml_px, 256 | C.sm__w_4, 257 | ], 258 | attrs! { 259 | At::Src => image_src("link_arrow.svg") 260 | } 261 | ] 262 | ] 263 | ], 264 | ], 265 | ] 266 | ] 267 | ), 268 | // Header 269 | IF!(show_header => 270 | header![ 271 | C![ 272 | C.fixed, 273 | C.top_0 274 | C.inset_x_0, 275 | ], 276 | // Header controls container 277 | div![ 278 | C![ 279 | C.mx_8 280 | C.h_16, 281 | C.flex, 282 | C.justify_between, 283 | C.items_center, 284 | // sm__ 285 | C.sm__h_24, 286 | ], 287 | // Logo 288 | a![ 289 | attrs! { 290 | At::Href => Urls::new(&model.base_url).home() 291 | }, 292 | ev(Ev::Click, |_| Msg::ScrollToTop), 293 | ev(Ev::Click, |_| Msg::HideMenu), 294 | img![ 295 | C![ 296 | C.h_6, 297 | // sm__ 298 | C.sm__h_10, 299 | C.sm__w_70px, 300 | ], 301 | attrs! { 302 | At::Src => image_src("logo.svg") 303 | } 304 | ], 305 | ], 306 | // Links 307 | ul![ 308 | C![ 309 | C.hidden, 310 | // sm__ 311 | C.sm___mt_px, 312 | C.sm__text_21, 313 | C.sm__font_semibold, 314 | C.sm__text_gray_10, 315 | C.sm__flex, 316 | C.sm__items_center, 317 | C.sm__h_full, 318 | ], 319 | li![ 320 | C![ 321 | // sm__ 322 | C.sm__block, 323 | C.sm__h_full, 324 | ], 325 | a![ 326 | C![ 327 | // sm__ 328 | C.sm__h_full, 329 | C.sm__flex, 330 | C.sm__items_center, 331 | C.sm__hover__text_yellow_7, 332 | C.sm__outline_none, 333 | ], 334 | attrs! { 335 | At::Href => Urls::new(&model.base_url).home() 336 | }, 337 | ev(Ev::Click, |_| Msg::ScrollToTop), 338 | ev(Ev::Click, |_| Msg::HideMenu), 339 | "Home & Projects" 340 | ] 341 | ], 342 | li![ 343 | C![ 344 | // sm__ 345 | C.sm__block, 346 | C.sm__ml_8 347 | C.sm__h_full, 348 | ], 349 | a![ 350 | C![ 351 | // sm__ 352 | C.sm__h_full, 353 | C.sm__flex, 354 | C.sm__items_center, 355 | C.sm__hover__text_yellow_7, 356 | C.sm__outline_none, 357 | ], 358 | attrs! { 359 | At::Href => Urls::new(&model.base_url).about() 360 | }, 361 | ev(Ev::Click, |_| Msg::ScrollToTop), 362 | ev(Ev::Click, |_| Msg::HideMenu), 363 | "About" 364 | ] 365 | ], 366 | li![ 367 | C![ 368 | C.hidden, 369 | // md__ 370 | C.md__block, 371 | C.md__ml_12, 372 | C.md__h_full, 373 | ], 374 | a![ 375 | C![ 376 | // md__ 377 | C.md__h_full, 378 | C.md__flex, 379 | C.md__items_center, 380 | C.md__hover__text_yellow_7, 381 | ], 382 | attrs! { 383 | At::Href => asset_path("Martin_Kavik_resume.pdf") 384 | }, 385 | "Resume", 386 | span![ 387 | C![ 388 | // md__ 389 | C.md__text_gray_5, 390 | ], 391 | ".pdf" 392 | ] 393 | ] 394 | ], 395 | li![ 396 | C![ 397 | C.hidden, 398 | // md__ 399 | C.md__block, 400 | C.md__ml_8, 401 | C.md__h_full, 402 | ], 403 | a![ 404 | C![ 405 | // md__ 406 | C.md__h_full, 407 | C.md__flex, 408 | C.md__items_center, 409 | C.md__hover__text_yellow_7, 410 | ], 411 | attrs! { 412 | At::Href => "https://github.com/MartinKavik" 413 | }, 414 | "GitHub", 415 | img![ 416 | C![ 417 | // md__ 418 | C.md__inline 419 | C.md__mb_5, 420 | C.md__ml_px, 421 | C.md__w_4, 422 | ], 423 | attrs! { 424 | At::Src => image_src("link_arrow.svg") 425 | } 426 | ] 427 | ] 428 | ], 429 | ], 430 | // Hamburger 431 | div![ 432 | C![ 433 | IF!(not(model.in_prerendering) => C.cursor_pointer), 434 | // md__ 435 | C.md__hidden, 436 | ], 437 | ev(Ev::Click, |_| Msg::ToggleMenu), 438 | img![ 439 | id!("hamburger"), 440 | C![ 441 | C.h_8, 442 | C.w_12, 443 | // sm__ 444 | C.sm__h_10 445 | C.sm__w_16, 446 | ], 447 | if model.in_prerendering { 448 | attrs! { 449 | At::Src => image_src("loading.svg") 450 | } 451 | } else { 452 | attrs! { 453 | At::Src => if model.menu_visibility == Visible { 454 | image_src("cross.svg") 455 | } else { 456 | image_src("hamburger.svg") 457 | } 458 | } 459 | } 460 | ] 461 | ], 462 | // Spacer 463 | div![C![ 464 | C.hidden, 465 | // md__ 466 | C.md__block, 467 | ],], 468 | ], 469 | // Bottom header line 470 | div![ 471 | C![ 472 | C.absolute, 473 | C.top_0, 474 | C.ml_12, 475 | C.w_3of5, 476 | C.h_px, 477 | // sm__ 478 | C.sm__ml_0, 479 | C.sm__w_full, 480 | C.sm__h_3px 481 | C.sm__flex, 482 | C.sm__justify_center, 483 | // md__ 484 | C.md___ml_30, 485 | ], 486 | div![C![ 487 | C.h_full, 488 | C.bg_gray_2, 489 | // sm__ 490 | C.sm__ml_6, 491 | C.sm__w_48, 492 | IF!(model.page == Page::Home => C.sm__bg_yellow_6), 493 | ],], 494 | div![C![ 495 | C.hidden, 496 | // sm__ 497 | C.sm__block, 498 | C.sm__h_full, 499 | C.sm__bg_gray_2, 500 | C.sm__w_24, 501 | IF!(model.page == Page::About => C.sm__bg_yellow_6), 502 | ],] 503 | ], 504 | ] 505 | ), 506 | ] 507 | } 508 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "autocfg" 5 | version = "1.0.0" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" 8 | 9 | [[package]] 10 | name = "base-x" 11 | version = "0.2.6" 12 | source = "registry+https://github.com/rust-lang/crates.io-index" 13 | checksum = "1b20b618342cf9891c292c4f5ac2cde7287cc5c87e87e9c769d617793607dec1" 14 | 15 | [[package]] 16 | name = "bitflags" 17 | version = "1.2.1" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 20 | 21 | [[package]] 22 | name = "bumpalo" 23 | version = "3.1.2" 24 | source = "registry+https://github.com/rust-lang/crates.io-index" 25 | checksum = "5fb8038c1ddc0a5f73787b130f4cc75151e96ed33e417fde765eb5a81e3532f4" 26 | 27 | [[package]] 28 | name = "cfg-if" 29 | version = "0.1.10" 30 | source = "registry+https://github.com/rust-lang/crates.io-index" 31 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 32 | 33 | [[package]] 34 | name = "console_error_panic_hook" 35 | version = "0.1.6" 36 | source = "registry+https://github.com/rust-lang/crates.io-index" 37 | checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211" 38 | dependencies = [ 39 | "cfg-if", 40 | "wasm-bindgen", 41 | ] 42 | 43 | [[package]] 44 | name = "cookie" 45 | version = "0.14.2" 46 | source = "registry+https://github.com/rust-lang/crates.io-index" 47 | checksum = "1373a16a4937bc34efec7b391f9c1500c30b8478a701a4f44c9165cc0475a6e0" 48 | dependencies = [ 49 | "percent-encoding", 50 | "time", 51 | "version_check 0.9.2", 52 | ] 53 | 54 | [[package]] 55 | name = "dbg" 56 | version = "1.0.4" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "4677188513e0e9d7adced5997cf9a1e7a3c996c994f90093325c5332c1a8b221" 59 | dependencies = [ 60 | "version_check 0.1.5", 61 | ] 62 | 63 | [[package]] 64 | name = "discard" 65 | version = "1.0.4" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" 68 | 69 | [[package]] 70 | name = "enclose" 71 | version = "1.1.8" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "1056f553da426e9c025a662efa48b52e62e0a3a7648aa2d15aeaaf7f0d329357" 74 | 75 | [[package]] 76 | name = "fixed-vec-deque" 77 | version = "0.1.9" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "14c0bc0a5a14538da76b4127910be3eca0df0fb8fd6dc893fe620ecf583dda71" 80 | 81 | [[package]] 82 | name = "futures" 83 | version = "0.3.6" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "5d8e3078b7b2a8a671cb7a3d17b4760e4181ea243227776ba83fd043b4ca034e" 86 | dependencies = [ 87 | "futures-channel", 88 | "futures-core", 89 | "futures-executor", 90 | "futures-io", 91 | "futures-sink", 92 | "futures-task", 93 | "futures-util", 94 | ] 95 | 96 | [[package]] 97 | name = "futures-channel" 98 | version = "0.3.6" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | checksum = "a7a4d35f7401e948629c9c3d6638fb9bf94e0b2121e96c3b428cc4e631f3eb74" 101 | dependencies = [ 102 | "futures-core", 103 | "futures-sink", 104 | ] 105 | 106 | [[package]] 107 | name = "futures-core" 108 | version = "0.3.6" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "d674eaa0056896d5ada519900dbf97ead2e46a7b6621e8160d79e2f2e1e2784b" 111 | 112 | [[package]] 113 | name = "futures-executor" 114 | version = "0.3.6" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "cc709ca1da6f66143b8c9bec8e6260181869893714e9b5a490b169b0414144ab" 117 | dependencies = [ 118 | "futures-core", 119 | "futures-task", 120 | "futures-util", 121 | ] 122 | 123 | [[package]] 124 | name = "futures-io" 125 | version = "0.3.6" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "5fc94b64bb39543b4e432f1790b6bf18e3ee3b74653c5449f63310e9a74b123c" 128 | 129 | [[package]] 130 | name = "futures-macro" 131 | version = "0.3.6" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | checksum = "f57ed14da4603b2554682e9f2ff3c65d7567b53188db96cb71538217fc64581b" 134 | dependencies = [ 135 | "proc-macro-hack", 136 | "proc-macro2", 137 | "quote", 138 | "syn", 139 | ] 140 | 141 | [[package]] 142 | name = "futures-sink" 143 | version = "0.3.6" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "0d8764258ed64ebc5d9ed185cf86a95db5cac810269c5d20ececb32e0088abbd" 146 | 147 | [[package]] 148 | name = "futures-task" 149 | version = "0.3.6" 150 | source = "registry+https://github.com/rust-lang/crates.io-index" 151 | checksum = "4dd26820a9f3637f1302da8bceba3ff33adbe53464b54ca24d4e2d4f1db30f94" 152 | dependencies = [ 153 | "once_cell", 154 | ] 155 | 156 | [[package]] 157 | name = "futures-util" 158 | version = "0.3.6" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "8a894a0acddba51a2d49a6f4263b1e64b8c579ece8af50fa86503d52cd1eea34" 161 | dependencies = [ 162 | "futures-channel", 163 | "futures-core", 164 | "futures-io", 165 | "futures-macro", 166 | "futures-sink", 167 | "futures-task", 168 | "memchr", 169 | "pin-project", 170 | "pin-utils", 171 | "proc-macro-hack", 172 | "proc-macro-nested", 173 | "slab", 174 | ] 175 | 176 | [[package]] 177 | name = "getopts" 178 | version = "0.2.21" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" 181 | dependencies = [ 182 | "unicode-width", 183 | ] 184 | 185 | [[package]] 186 | name = "getrandom" 187 | version = "0.1.14" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" 190 | dependencies = [ 191 | "cfg-if", 192 | "libc", 193 | "wasi", 194 | "wasm-bindgen", 195 | ] 196 | 197 | [[package]] 198 | name = "gloo-events" 199 | version = "0.1.1" 200 | source = "registry+https://github.com/rust-lang/crates.io-index" 201 | checksum = "088514ec8ef284891c762c88a66b639b3a730134714692ee31829765c5bc814f" 202 | dependencies = [ 203 | "wasm-bindgen", 204 | "web-sys", 205 | ] 206 | 207 | [[package]] 208 | name = "gloo-file" 209 | version = "0.1.0" 210 | source = "registry+https://github.com/rust-lang/crates.io-index" 211 | checksum = "8f9fecfe46b5dc3cc46f58e98ba580cc714f2c93860796d002eb3527a465ef49" 212 | dependencies = [ 213 | "futures-channel", 214 | "gloo-events", 215 | "js-sys", 216 | "wasm-bindgen", 217 | "web-sys", 218 | ] 219 | 220 | [[package]] 221 | name = "gloo-timers" 222 | version = "0.2.1" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" 225 | dependencies = [ 226 | "futures-channel", 227 | "futures-core", 228 | "js-sys", 229 | "wasm-bindgen", 230 | "web-sys", 231 | ] 232 | 233 | [[package]] 234 | name = "hashbrown" 235 | version = "0.9.1" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" 238 | 239 | [[package]] 240 | name = "indexmap" 241 | version = "1.6.0" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" 244 | dependencies = [ 245 | "autocfg", 246 | "hashbrown", 247 | ] 248 | 249 | [[package]] 250 | name = "itoa" 251 | version = "0.4.4" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" 254 | 255 | [[package]] 256 | name = "js-sys" 257 | version = "0.3.45" 258 | source = "registry+https://github.com/rust-lang/crates.io-index" 259 | checksum = "ca059e81d9486668f12d455a4ea6daa600bd408134cd17e3d3fb5a32d1f016f8" 260 | dependencies = [ 261 | "wasm-bindgen", 262 | ] 263 | 264 | [[package]] 265 | name = "kavik_cz" 266 | version = "0.1.0" 267 | dependencies = [ 268 | "fixed-vec-deque", 269 | "seed", 270 | "wasm-bindgen-test", 271 | "web-sys", 272 | ] 273 | 274 | [[package]] 275 | name = "lazy_static" 276 | version = "1.4.0" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 279 | 280 | [[package]] 281 | name = "libc" 282 | version = "0.2.66" 283 | source = "registry+https://github.com/rust-lang/crates.io-index" 284 | checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" 285 | 286 | [[package]] 287 | name = "log" 288 | version = "0.4.8" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 291 | dependencies = [ 292 | "cfg-if", 293 | ] 294 | 295 | [[package]] 296 | name = "memchr" 297 | version = "2.3.3" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" 300 | 301 | [[package]] 302 | name = "once_cell" 303 | version = "1.3.1" 304 | source = "registry+https://github.com/rust-lang/crates.io-index" 305 | checksum = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b" 306 | 307 | [[package]] 308 | name = "percent-encoding" 309 | version = "2.1.0" 310 | source = "registry+https://github.com/rust-lang/crates.io-index" 311 | checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 312 | 313 | [[package]] 314 | name = "pin-project" 315 | version = "0.4.27" 316 | source = "registry+https://github.com/rust-lang/crates.io-index" 317 | checksum = "2ffbc8e94b38ea3d2d8ba92aea2983b503cd75d0888d75b86bb37970b5698e15" 318 | dependencies = [ 319 | "pin-project-internal", 320 | ] 321 | 322 | [[package]] 323 | name = "pin-project-internal" 324 | version = "0.4.27" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | checksum = "65ad2ae56b6abe3a1ee25f15ee605bacadb9a764edaba9c2bf4103800d4a1895" 327 | dependencies = [ 328 | "proc-macro2", 329 | "quote", 330 | "syn", 331 | ] 332 | 333 | [[package]] 334 | name = "pin-utils" 335 | version = "0.1.0" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 338 | 339 | [[package]] 340 | name = "ppv-lite86" 341 | version = "0.2.6" 342 | source = "registry+https://github.com/rust-lang/crates.io-index" 343 | checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" 344 | 345 | [[package]] 346 | name = "proc-macro-hack" 347 | version = "0.5.11" 348 | source = "registry+https://github.com/rust-lang/crates.io-index" 349 | checksum = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" 350 | dependencies = [ 351 | "proc-macro2", 352 | "quote", 353 | "syn", 354 | ] 355 | 356 | [[package]] 357 | name = "proc-macro-nested" 358 | version = "0.1.3" 359 | source = "registry+https://github.com/rust-lang/crates.io-index" 360 | checksum = "369a6ed065f249a159e06c45752c780bda2fb53c995718f9e484d08daa9eb42e" 361 | 362 | [[package]] 363 | name = "proc-macro2" 364 | version = "1.0.24" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" 367 | dependencies = [ 368 | "unicode-xid", 369 | ] 370 | 371 | [[package]] 372 | name = "pulldown-cmark" 373 | version = "0.8.0" 374 | source = "registry+https://github.com/rust-lang/crates.io-index" 375 | checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" 376 | dependencies = [ 377 | "bitflags", 378 | "getopts", 379 | "memchr", 380 | "unicase", 381 | ] 382 | 383 | [[package]] 384 | name = "quote" 385 | version = "1.0.2" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" 388 | dependencies = [ 389 | "proc-macro2", 390 | ] 391 | 392 | [[package]] 393 | name = "rand" 394 | version = "0.7.3" 395 | source = "registry+https://github.com/rust-lang/crates.io-index" 396 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 397 | dependencies = [ 398 | "getrandom", 399 | "libc", 400 | "rand_chacha", 401 | "rand_core", 402 | "rand_hc", 403 | "rand_pcg", 404 | ] 405 | 406 | [[package]] 407 | name = "rand_chacha" 408 | version = "0.2.2" 409 | source = "registry+https://github.com/rust-lang/crates.io-index" 410 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 411 | dependencies = [ 412 | "ppv-lite86", 413 | "rand_core", 414 | ] 415 | 416 | [[package]] 417 | name = "rand_core" 418 | version = "0.5.1" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 421 | dependencies = [ 422 | "getrandom", 423 | ] 424 | 425 | [[package]] 426 | name = "rand_hc" 427 | version = "0.2.0" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 430 | dependencies = [ 431 | "rand_core", 432 | ] 433 | 434 | [[package]] 435 | name = "rand_pcg" 436 | version = "0.2.1" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" 439 | dependencies = [ 440 | "rand_core", 441 | ] 442 | 443 | [[package]] 444 | name = "rustc_version" 445 | version = "0.2.3" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 448 | dependencies = [ 449 | "semver", 450 | ] 451 | 452 | [[package]] 453 | name = "ryu" 454 | version = "1.0.2" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" 457 | 458 | [[package]] 459 | name = "scoped-tls" 460 | version = "1.0.0" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" 463 | 464 | [[package]] 465 | name = "seed" 466 | version = "0.8.0" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "3b599be9cc57456f4b7fc99b8abfb154d4819f7b6c147e80be5580663dad4536" 469 | dependencies = [ 470 | "console_error_panic_hook", 471 | "cookie", 472 | "dbg", 473 | "enclose", 474 | "futures", 475 | "gloo-file", 476 | "gloo-timers", 477 | "indexmap", 478 | "js-sys", 479 | "pulldown-cmark", 480 | "rand", 481 | "serde", 482 | "serde_json", 483 | "uuid", 484 | "version_check 0.9.2", 485 | "wasm-bindgen", 486 | "wasm-bindgen-futures", 487 | "web-sys", 488 | ] 489 | 490 | [[package]] 491 | name = "semver" 492 | version = "0.9.0" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 495 | dependencies = [ 496 | "semver-parser", 497 | ] 498 | 499 | [[package]] 500 | name = "semver-parser" 501 | version = "0.7.0" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 504 | 505 | [[package]] 506 | name = "serde" 507 | version = "1.0.117" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" 510 | dependencies = [ 511 | "serde_derive", 512 | ] 513 | 514 | [[package]] 515 | name = "serde_derive" 516 | version = "1.0.117" 517 | source = "registry+https://github.com/rust-lang/crates.io-index" 518 | checksum = "cbd1ae72adb44aab48f325a02444a5fc079349a8d804c1fc922aed3f7454c74e" 519 | dependencies = [ 520 | "proc-macro2", 521 | "quote", 522 | "syn", 523 | ] 524 | 525 | [[package]] 526 | name = "serde_json" 527 | version = "1.0.59" 528 | source = "registry+https://github.com/rust-lang/crates.io-index" 529 | checksum = "dcac07dbffa1c65e7f816ab9eba78eb142c6d44410f4eeba1e26e4f5dfa56b95" 530 | dependencies = [ 531 | "itoa", 532 | "ryu", 533 | "serde", 534 | ] 535 | 536 | [[package]] 537 | name = "sha1" 538 | version = "0.6.0" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" 541 | 542 | [[package]] 543 | name = "slab" 544 | version = "0.4.2" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 547 | 548 | [[package]] 549 | name = "standback" 550 | version = "0.2.8" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "47e4b8c631c998468961a9ea159f064c5c8499b95b5e4a34b77849d45949d540" 553 | 554 | [[package]] 555 | name = "stdweb" 556 | version = "0.4.20" 557 | source = "registry+https://github.com/rust-lang/crates.io-index" 558 | checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" 559 | dependencies = [ 560 | "discard", 561 | "rustc_version", 562 | "stdweb-derive", 563 | "stdweb-internal-macros", 564 | "stdweb-internal-runtime", 565 | "wasm-bindgen", 566 | ] 567 | 568 | [[package]] 569 | name = "stdweb-derive" 570 | version = "0.5.3" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" 573 | dependencies = [ 574 | "proc-macro2", 575 | "quote", 576 | "serde", 577 | "serde_derive", 578 | "syn", 579 | ] 580 | 581 | [[package]] 582 | name = "stdweb-internal-macros" 583 | version = "0.2.9" 584 | source = "registry+https://github.com/rust-lang/crates.io-index" 585 | checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" 586 | dependencies = [ 587 | "base-x", 588 | "proc-macro2", 589 | "quote", 590 | "serde", 591 | "serde_derive", 592 | "serde_json", 593 | "sha1", 594 | "syn", 595 | ] 596 | 597 | [[package]] 598 | name = "stdweb-internal-runtime" 599 | version = "0.1.5" 600 | source = "registry+https://github.com/rust-lang/crates.io-index" 601 | checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" 602 | 603 | [[package]] 604 | name = "syn" 605 | version = "1.0.46" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "5ad5de3220ea04da322618ded2c42233d02baca219d6f160a3e9c87cda16c942" 608 | dependencies = [ 609 | "proc-macro2", 610 | "quote", 611 | "unicode-xid", 612 | ] 613 | 614 | [[package]] 615 | name = "time" 616 | version = "0.2.15" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "e1330829d2e6c06771eeae476be12ff1aa9eb5e29ca718a431ab27168efde6c1" 619 | dependencies = [ 620 | "cfg-if", 621 | "libc", 622 | "standback", 623 | "stdweb", 624 | "time-macros", 625 | "version_check 0.9.2", 626 | "winapi", 627 | ] 628 | 629 | [[package]] 630 | name = "time-macros" 631 | version = "0.1.0" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "9ae9b6e9f095bc105e183e3cd493d72579be3181ad4004fceb01adbe9eecab2d" 634 | dependencies = [ 635 | "proc-macro-hack", 636 | "time-macros-impl", 637 | ] 638 | 639 | [[package]] 640 | name = "time-macros-impl" 641 | version = "0.1.1" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "e5c3be1edfad6027c69f5491cf4cb310d1a71ecd6af742788c6ff8bced86b8fa" 644 | dependencies = [ 645 | "proc-macro-hack", 646 | "proc-macro2", 647 | "quote", 648 | "standback", 649 | "syn", 650 | ] 651 | 652 | [[package]] 653 | name = "unicase" 654 | version = "2.6.0" 655 | source = "registry+https://github.com/rust-lang/crates.io-index" 656 | checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 657 | dependencies = [ 658 | "version_check 0.9.2", 659 | ] 660 | 661 | [[package]] 662 | name = "unicode-width" 663 | version = "0.1.7" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" 666 | 667 | [[package]] 668 | name = "unicode-xid" 669 | version = "0.2.0" 670 | source = "registry+https://github.com/rust-lang/crates.io-index" 671 | checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 672 | 673 | [[package]] 674 | name = "uuid" 675 | version = "0.8.1" 676 | source = "registry+https://github.com/rust-lang/crates.io-index" 677 | checksum = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" 678 | dependencies = [ 679 | "rand", 680 | ] 681 | 682 | [[package]] 683 | name = "version_check" 684 | version = "0.1.5" 685 | source = "registry+https://github.com/rust-lang/crates.io-index" 686 | checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" 687 | 688 | [[package]] 689 | name = "version_check" 690 | version = "0.9.2" 691 | source = "registry+https://github.com/rust-lang/crates.io-index" 692 | checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" 693 | 694 | [[package]] 695 | name = "wasi" 696 | version = "0.9.0+wasi-snapshot-preview1" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 699 | 700 | [[package]] 701 | name = "wasm-bindgen" 702 | version = "0.2.68" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "1ac64ead5ea5f05873d7c12b545865ca2b8d28adfc50a49b84770a3a97265d42" 705 | dependencies = [ 706 | "cfg-if", 707 | "serde", 708 | "serde_json", 709 | "wasm-bindgen-macro", 710 | ] 711 | 712 | [[package]] 713 | name = "wasm-bindgen-backend" 714 | version = "0.2.68" 715 | source = "registry+https://github.com/rust-lang/crates.io-index" 716 | checksum = "f22b422e2a757c35a73774860af8e112bff612ce6cb604224e8e47641a9e4f68" 717 | dependencies = [ 718 | "bumpalo", 719 | "lazy_static", 720 | "log", 721 | "proc-macro2", 722 | "quote", 723 | "syn", 724 | "wasm-bindgen-shared", 725 | ] 726 | 727 | [[package]] 728 | name = "wasm-bindgen-futures" 729 | version = "0.4.18" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "b7866cab0aa01de1edf8b5d7936938a7e397ee50ce24119aef3e1eaa3b6171da" 732 | dependencies = [ 733 | "cfg-if", 734 | "js-sys", 735 | "wasm-bindgen", 736 | "web-sys", 737 | ] 738 | 739 | [[package]] 740 | name = "wasm-bindgen-macro" 741 | version = "0.2.68" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038" 744 | dependencies = [ 745 | "quote", 746 | "wasm-bindgen-macro-support", 747 | ] 748 | 749 | [[package]] 750 | name = "wasm-bindgen-macro-support" 751 | version = "0.2.68" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe" 754 | dependencies = [ 755 | "proc-macro2", 756 | "quote", 757 | "syn", 758 | "wasm-bindgen-backend", 759 | "wasm-bindgen-shared", 760 | ] 761 | 762 | [[package]] 763 | name = "wasm-bindgen-shared" 764 | version = "0.2.68" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "1d649a3145108d7d3fbcde896a468d1bd636791823c9921135218ad89be08307" 767 | 768 | [[package]] 769 | name = "wasm-bindgen-test" 770 | version = "0.3.18" 771 | source = "registry+https://github.com/rust-lang/crates.io-index" 772 | checksum = "34d1cdc8b98a557f24733d50a1199c4b0635e465eecba9c45b214544da197f64" 773 | dependencies = [ 774 | "console_error_panic_hook", 775 | "js-sys", 776 | "scoped-tls", 777 | "wasm-bindgen", 778 | "wasm-bindgen-futures", 779 | "wasm-bindgen-test-macro", 780 | ] 781 | 782 | [[package]] 783 | name = "wasm-bindgen-test-macro" 784 | version = "0.3.18" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "e8fb9c67be7439ee8ab1b7db502a49c05e51e2835b66796c705134d9b8e1a585" 787 | dependencies = [ 788 | "proc-macro2", 789 | "quote", 790 | ] 791 | 792 | [[package]] 793 | name = "web-sys" 794 | version = "0.3.45" 795 | source = "registry+https://github.com/rust-lang/crates.io-index" 796 | checksum = "4bf6ef87ad7ae8008e15a355ce696bed26012b7caa21605188cfd8214ab51e2d" 797 | dependencies = [ 798 | "js-sys", 799 | "wasm-bindgen", 800 | ] 801 | 802 | [[package]] 803 | name = "winapi" 804 | version = "0.3.8" 805 | source = "registry+https://github.com/rust-lang/crates.io-index" 806 | checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 807 | dependencies = [ 808 | "winapi-i686-pc-windows-gnu", 809 | "winapi-x86_64-pc-windows-gnu", 810 | ] 811 | 812 | [[package]] 813 | name = "winapi-i686-pc-windows-gnu" 814 | version = "0.4.0" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 817 | 818 | [[package]] 819 | name = "winapi-x86_64-pc-windows-gnu" 820 | version = "0.4.0" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 823 | -------------------------------------------------------------------------------- /src/page/about.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | asset_path, generated::css_classes::C, image_src, Msg, MAIL_TO_KAVIK, 3 | }; 4 | use seed::{prelude::*, *}; 5 | 6 | #[allow(clippy::too_many_lines)] 7 | pub fn view() -> Node { 8 | div![ 9 | C![ 10 | C.flex_grow, 11 | ], 12 | // Photo section 13 | section![ 14 | C![ 15 | C.w_screen, 16 | C.h_690px, 17 | C.bg_blue_10, 18 | // sm__ 19 | C.sm__h_790px, 20 | // lg__ 21 | C.lg__h_1420px, 22 | ], 23 | // Small photo background container 24 | div![ 25 | C![ 26 | C.absolute, 27 | C.top_0, 28 | C.inset_x_0, 29 | C.flex, 30 | C.justify_center, 31 | // sm__ 32 | C.sm__hidden, 33 | ], 34 | // Small photo background 35 | div![ 36 | C![ 37 | C.w_xs, 38 | C.h_300px, 39 | C.bg_gray_1, 40 | ] 41 | ], 42 | ], 43 | // Large photo background 44 | div![ 45 | C![ 46 | C.absolute, 47 | C.top_0, 48 | C.inset_x_0, 49 | C.h_320px, 50 | C.rounded_bl_140px, 51 | C.bg_gray_1, 52 | // sm__ 53 | C.sm__h_420px, 54 | // lg__ 55 | C.lg__h_600px, 56 | C.lg__rounded_bl_330px, 57 | ], 58 | ], 59 | // Gear 60 | img![ 61 | C![ 62 | C.absolute 63 | C.left_full, 64 | C._ml_40, 65 | C._mt_56, 66 | C.w_md, 67 | C.blur, 68 | // sm__ 69 | C.sm___mt_64, 70 | C.sm__w_750px, 71 | ], 72 | attrs!{ 73 | At::Src => image_src("gear.svg") 74 | } 75 | ], 76 | ], 77 | // Developer section 78 | section![ 79 | C![ 80 | C.relative, 81 | C._mt_260px, 82 | C.rounded_tr_140px, 83 | C.bg_gray_1, 84 | C.overflow_x_hidden, 85 | // lg__ 86 | C.lg___mt_670px, 87 | C.lg__rounded_tr_330px, 88 | ], 89 | div![ 90 | C![ 91 | C.relative, 92 | C.mx_auto, 93 | C.max_w_400, 94 | C.pb_84, 95 | // sm__ 96 | C.pb_96 97 | ], 98 | // Right background 99 | div![ 100 | C![ 101 | C.absolute, 102 | C.right_0, 103 | C.inset_y_0, 104 | C.w_76, 105 | C.bg_yellow_4 106 | // sm__ 107 | C.sm__w_132, 108 | // lg__ 109 | C.lg__w_236, 110 | ] 111 | ], 112 | // Extended background 113 | div![ 114 | C![ 115 | C.absolute, 116 | C._right_50vw, 117 | C.inset_y_0, 118 | C.w_50vw, 119 | C.bg_yellow_4, 120 | ] 121 | ], 122 | // I, developer 123 | h2![ 124 | C![ 125 | C.relative, 126 | C.mb_16, 127 | C.pt_32, 128 | C.text_center, 129 | C.font_monospace, 130 | C.font_bold, 131 | C.text_40, 132 | C.text_blue_10, 133 | // sm__ 134 | C.sm__mb_24, 135 | C.sm__pt_40, 136 | C.sm__text_70, 137 | // lg__ 138 | C.lg__mb_32, 139 | C.lg__pt_64, 140 | C.lg__text_120, 141 | ], 142 | "I, developer" 143 | ], 144 | ul![ 145 | C![ 146 | C.relative, 147 | C.text_gray_8, 148 | ], 149 | li![ 150 | C![ 151 | C.w_76, 152 | C.pl_2, 153 | C.pr_5, 154 | C.py_10, 155 | C.bg_gray_1, 156 | C.flex, 157 | C.flex_nowrap, 158 | // sm__ 159 | C.sm__pl_4, 160 | C.sm__py_16, 161 | C.sm__w_132, 162 | // lg__ 163 | C.lg__pl_10, 164 | C.lg__py_32, 165 | C.lg__w_236, 166 | ], 167 | div![ 168 | C![ 169 | C.text_blue_6, 170 | C.mr_1, 171 | // sm__ 172 | C.sm__mr_2, 173 | // lg__ 174 | C.lg__mr_3, 175 | ], 176 | "▶\u{fe0e}" 177 | ], 178 | div![ 179 | "I was working as a ", 180 | span![ 181 | C![ 182 | C.font_bold, 183 | ], 184 | "backend" 185 | ], 186 | " developer in a bank and for some startups and agencies last years." 187 | ] 188 | ], 189 | li![ 190 | C![ 191 | C.flex, 192 | C.justify_end 193 | ], 194 | div![ 195 | C![ 196 | C.w_76, 197 | C.pl_2, 198 | C.pr_5, 199 | C.py_10, 200 | C.flex, 201 | C.flex_nowrap, 202 | // sm__ 203 | C.sm__pl_4, 204 | C.sm__py_16, 205 | C.sm__w_132, 206 | // lg__ 207 | C.lg__pl_10, 208 | C.lg__py_32, 209 | C.lg__pr_10, 210 | C.lg__w_236, 211 | ], 212 | div![ 213 | C![ 214 | C.text_blue_6, 215 | C.mr_1, 216 | // sm__ 217 | C.sm__mr_2, 218 | // lg__ 219 | C.lg__mr_3, 220 | ], 221 | "▶\u{fe0e}" 222 | ], 223 | div![ 224 | "I'm also coming back to ", 225 | span![ 226 | C![ 227 | C.font_bold, 228 | ], 229 | "frontend" 230 | ], 231 | " because it's finally possible to write reliable web apps. And I want to make more use of my ", 232 | span![ 233 | C![ 234 | C.font_bold, 235 | ], 236 | "artistic" 237 | ], 238 | " self." 239 | ] 240 | ] 241 | ], 242 | li![ 243 | C![ 244 | C.w_76, 245 | C.pl_2, 246 | C.pr_4, 247 | C.py_10, 248 | C.flex, 249 | C.flex_nowrap, 250 | C.bg_gray_1 251 | // sm__ 252 | C.sm__pl_4, 253 | C.sm__py_16, 254 | C.sm__w_132, 255 | // lg__ 256 | C.lg__pl_10, 257 | C.lg__py_32, 258 | C.lg__pr_10, 259 | C.lg__w_236, 260 | ], 261 | div![ 262 | C![ 263 | C.text_blue_6, 264 | C.mr_1, 265 | // sm__ 266 | C.sm__mr_2, 267 | // lg__ 268 | C.lg__mr_3, 269 | ], 270 | "▶\u{fe0e}" 271 | ], 272 | div![ 273 | "People make mistakes.", 274 | br![], 275 | "That's why I setup linters, formatters and CI pipelines as ", 276 | span![ 277 | C![ 278 | C.font_bold, 279 | ], 280 | "strict" 281 | ], 282 | " as possible and I want to write in ", 283 | span![ 284 | C![ 285 | C.font_bold, 286 | ], 287 | "Rust" 288 | ], 289 | ".", 290 | br![], 291 | "Ideal tools \"bully\" me and don't have any configuration options." 292 | ] 293 | ], 294 | li![ 295 | C![ 296 | C.flex, 297 | C.justify_end 298 | ], 299 | div![ 300 | C![ 301 | C.w_76, 302 | C.pl_2, 303 | C.pr_5, 304 | C.py_10, 305 | C.flex, 306 | C.flex_nowrap, 307 | // sm__ 308 | C.sm__pl_4, 309 | C.sm__py_16, 310 | C.sm__w_132, 311 | // lg__ 312 | C.lg__pl_10, 313 | C.lg__py_32, 314 | C.lg__pr_10, 315 | C.lg__w_236, 316 | ], 317 | div![ 318 | C![ 319 | C.text_blue_6, 320 | C.mr_1, 321 | // sm__ 322 | C.sm__mr_2, 323 | // lg__ 324 | C.lg__mr_3, 325 | ], 326 | "▶\u{fe0e}" 327 | ], 328 | div![ 329 | "I often learn from ", 330 | a![ 331 | attrs!{ 332 | At::Href => "https://www.packtpub.com/" 333 | }, 334 | C![ 335 | C.underline, 336 | C.underline_yellow_7 337 | ], 338 | "packtpub.com" 339 | ], 340 | ".", 341 | br![], 342 | "And I recommend to read book ", 343 | a![ 344 | attrs!{ 345 | At::Href => "https://fsharpforfunandprofit.com/books/" 346 | }, 347 | C![ 348 | C.underline, 349 | C.underline_yellow_7 350 | ], 351 | "Domain Modeling Made Functional" 352 | ], 353 | "." 354 | ] 355 | ] 356 | ], 357 | ] 358 | ] 359 | ], 360 | // Designer section 361 | section![ 362 | C![ 363 | C.relative, 364 | C._mt_260px, 365 | C.h_1160px, 366 | C.pt_px, 367 | C.rounded_tr_140px, 368 | C.bg_blue_10, 369 | C.overflow_hidden, 370 | // sm__ 371 | C.sm__h_1580px, 372 | // lg__ 373 | C.lg__h_2360px, 374 | C.lg__rounded_tr_330px, 375 | ], 376 | // Circles 377 | div![ 378 | C![ 379 | C.absolute, 380 | C.left_1of2, 381 | C._mt_12, 382 | C._ml_545px, 383 | C.w_1090px, 384 | C.h_1090px, 385 | C.opacity_10, 386 | // sm__ 387 | C.sm___ml_820px, 388 | C.sm__w_1640px, 389 | C.sm__h_1580px, 390 | // lg__ 391 | C.lg___ml_1230px, 392 | C.lg__w_2460px, 393 | C.lg__h_2330px, 394 | ], 395 | div![ 396 | C![ 397 | C.absolute, 398 | C.left_0, 399 | C.bottom_0, 400 | C.w_570px, 401 | C.h_570px, 402 | C.rounded_full, 403 | C.border_yellow_4, 404 | C.border_2 405 | // sm__ 406 | C.sm__w_860px, 407 | C.sm__h_860px, 408 | // lg__ 409 | C.lg__w_1300px, 410 | C.lg__h_1300px, 411 | ] 412 | ], 413 | div![ 414 | C![ 415 | C.absolute, 416 | C.right_0, 417 | C.top_0, 418 | C.w_570px, 419 | C.h_570px, 420 | C.rounded_full, 421 | C.border_yellow_4, 422 | C.border_2, 423 | // sm__ 424 | C.sm__w_860px, 425 | C.sm__h_860px, 426 | // lg__ 427 | C.lg__w_1300px, 428 | C.lg__h_1300px, 429 | ] 430 | ], 431 | ], 432 | // I, designer 433 | div![ 434 | C![ 435 | C.relative, 436 | C.mt_32, 437 | C.h_24, 438 | C.bg_blue_10, 439 | C.flex, 440 | C.items_center, 441 | C.justify_center, 442 | // sm__ 443 | C.sm__mt_48, 444 | C.sm__h_40, 445 | // lg__ 446 | C.lg__mt_64, 447 | C.lg__h_56, 448 | ], 449 | h2![ 450 | C![ 451 | C.text_center, 452 | C.font_display, 453 | C.font_semibold, 454 | C.text_40, 455 | C.text_yellow_4, 456 | // sm__ 457 | C.sm__text_70, 458 | // lg__ 459 | C.lg__text_120, 460 | ], 461 | "I, designer" 462 | ], 463 | ], 464 | ul![ 465 | C![ 466 | C.relative, 467 | C.mt_16, 468 | C.max_w_md, 469 | C.mx_auto, 470 | C.pl_1, 471 | C.text_blue_1, 472 | C.flex, 473 | C.flex_col, 474 | // sm__ 475 | C.sm__mt_24, 476 | C.sm__max_w_3xl, 477 | C.sm__pl_5, 478 | C.sm__pr_2, 479 | // lg__ 480 | C.lg__mt_40, 481 | C.lg__max_w_400, 482 | C.lg__pl_16, 483 | C.lg__pr_12, 484 | ], 485 | li![ 486 | C![ 487 | C.w_76, 488 | C.flex, 489 | C.flex_nowrap 490 | // sm__ 491 | C.sm__w_132, 492 | // lg__ 493 | C.lg__w_236, 494 | ], 495 | div![ 496 | C![ 497 | C.text_yellow_4, 498 | C.mr_1, 499 | // sm__ 500 | C.sm__mr_2, 501 | // lg__ 502 | C.lg__mr_4, 503 | ], 504 | "▶\u{fe0e}" 505 | ], 506 | div![ 507 | "I've designed logos, my resume and this website in ", 508 | span![ 509 | C![ 510 | C.font_bold, 511 | ], 512 | "Affinity Designer" 513 | ], 514 | "." 515 | ] 516 | ], 517 | li![ 518 | C![ 519 | C.flex, 520 | C.justify_end, 521 | ], 522 | div![ 523 | C![ 524 | C.mt_16, 525 | C.ml_5, 526 | C.w_64, 527 | C.flex, 528 | C.flex_nowrap, 529 | // sm__ 530 | C.sm__mt_24, 531 | C.sm__ml_8, 532 | C.sm__w_md, 533 | // lg__ 534 | C.lg__mt_48, 535 | C.lg__ml_16, 536 | C.lg__w_236, 537 | ], 538 | div![ 539 | C![ 540 | C.text_yellow_4, 541 | C.mr_1, 542 | // sm__ 543 | C.sm__mr_2, 544 | // lg__ 545 | C.lg__mr_4, 546 | ], 547 | "▶\u{fe0e}" 548 | ], 549 | div![ 550 | "I'll use ", 551 | span![ 552 | C![ 553 | C.font_bold, 554 | ], 555 | "Figma" 556 | ], 557 | " for my next website design." 558 | ] 559 | ] 560 | ], 561 | li![ 562 | C![ 563 | C.mt_16, 564 | C.w_76, 565 | C.flex, 566 | C.flex_nowrap, 567 | // sm__ 568 | C.sm__mt_24, 569 | C.sm__w_132, 570 | // lg__ 571 | C.lg__mt_48, 572 | C.lg__w_236, 573 | ], 574 | div![ 575 | C![ 576 | C.text_yellow_4, 577 | C.mr_1, 578 | // sm__ 579 | C.sm__mr_2, 580 | // lg__ 581 | C.lg__mr_4, 582 | ], 583 | "▶\u{fe0e}" 584 | ], 585 | div![ 586 | "I have some experience with ", 587 | span![ 588 | C![ 589 | C.font_bold, 590 | ], 591 | "Adobe XD" 592 | ], 593 | ", ", 594 | span![ 595 | C![ 596 | C.font_bold, 597 | ], 598 | "Krita" 599 | ], 600 | " and ", 601 | span![ 602 | C![ 603 | C.font_bold, 604 | ], 605 | "Rhino3D" 606 | ], 607 | "." 608 | ] 609 | ], 610 | li![ 611 | C![ 612 | C.flex, 613 | C.justify_end, 614 | ], 615 | div![ 616 | C![ 617 | C.mt_16, 618 | C.ml_6, 619 | C.w_76, 620 | C.flex, 621 | C.flex_nowrap, 622 | // sm__ 623 | C.sm__mt_24, 624 | C.sm__ml_8, 625 | C.sm__w_md, 626 | // lg__ 627 | C.lg__mt_48, 628 | C.lg__ml_16, 629 | C.lg__w_236, 630 | ], 631 | div![ 632 | C![ 633 | C.text_yellow_4, 634 | C.mr_1, 635 | // sm__ 636 | C.sm__mr_2, 637 | // lg__ 638 | C.lg__mr_4, 639 | ], 640 | "▶\u{fe0e}" 641 | ], 642 | div![ 643 | "I recommend to check ", 644 | a![ 645 | attrs!{ 646 | At::Href => "https://refactoringui.com/" 647 | }, 648 | C![ 649 | C.underline, 650 | C.underline_yellow_7 651 | ], 652 | "refactoringui.com" 653 | ], 654 | ". I've bought their book and I use their ", 655 | a![ 656 | attrs!{ 657 | At::Href => "https://tailwindcss.com/" 658 | }, 659 | C![ 660 | C.underline, 661 | C.underline_yellow_7 662 | ], 663 | "TailwindCSS" 664 | ], 665 | " in my projects." 666 | ] 667 | ] 668 | ], 669 | ] 670 | ], 671 | // Human section 672 | section![ 673 | C![ 674 | C.relative, 675 | C._mt_260px, 676 | C.h_1580px, 677 | C.pt_px, 678 | C.rounded_tr_140px, 679 | C.bg_blue_6, 680 | C.overflow_hidden, 681 | C.flex, 682 | C.flex_col, 683 | C.items_center, 684 | // sm__ 685 | C.sm__h_2330px, 686 | // lg__ 687 | C.lg__h_3670px, 688 | C.lg__rounded_tr_330px, 689 | ], 690 | // I, human 691 | h2![ 692 | C![ 693 | C.mt_24, 694 | C.font_ordinary, 695 | C.font_bold, 696 | C.text_40, 697 | C.text_blue_2, 698 | // sm__ 699 | C.sm__mt_48, 700 | C.sm__text_70, 701 | // lg__ 702 | C.lg__mt_64, 703 | C.lg__text_120, 704 | ], 705 | "I, human" 706 | ], 707 | // Personal life 708 | div![ 709 | C![ 710 | C.relative, 711 | C.mt_20, 712 | C.pt_3, 713 | C.pb_16, 714 | C.px_12, 715 | C.bg_blue_10, 716 | C.rounded_tr_110px, 717 | // sm__ 718 | C.sm__mt_40, 719 | C.sm__pb_32 720 | // lg__ 721 | C.lg__mt_56, 722 | C.lg__pb_48, 723 | C.lg__rounded_tr_260px, 724 | ], 725 | // Extended background 726 | div![ 727 | C![ 728 | C.absolute, 729 | C.left_0, 730 | C.inset_y_0, 731 | C._left_50vw, 732 | C.w_50vw, 733 | C.bg_blue_10, 734 | ] 735 | ], 736 | // Content container 737 | div![ 738 | C![ 739 | C.w_xs, 740 | C.relative, 741 | // sm__ 742 | C.sm__w_132, 743 | // lg__ 744 | C.lg__w_236, 745 | ], 746 | h3![ 747 | C![ 748 | C.ml_8, 749 | C.mt_8, 750 | C.font_display, 751 | C.font_thin, 752 | C.text_35, 753 | C.text_blue_3, 754 | // sm__ 755 | C.sm__mt_16, 756 | C.sm__text_60 757 | // lg__ 758 | C.lg__mt_32, 759 | C.lg__text_90 760 | ], 761 | "Personal life" 762 | ], 763 | ul![ 764 | C![ 765 | C.mt_8, 766 | C.ml_1, 767 | C.text_blue_1, 768 | // sm__ 769 | C.sm__mt_12, 770 | // lg__ 771 | C.lg__mt_24, 772 | ], 773 | li![ 774 | C![ 775 | C.flex, 776 | C.flex_nowrap 777 | ], 778 | div![ 779 | C![ 780 | C.text_yellow_4, 781 | C.mr_1, 782 | // sm__ 783 | C.sm__mr_2 784 | // lg__ 785 | C.lg__mr_4 786 | ], 787 | "▶\u{fe0e}" 788 | ], 789 | div![ 790 | "I'm INTJ. When I'm not ", 791 | span![ 792 | C![ 793 | C.font_bold, 794 | ], 795 | "creating" 796 | ], 797 | " something, I usually read or go to gym." 798 | ] 799 | ], 800 | li![ 801 | C![ 802 | C.mt_10, 803 | C.flex, 804 | C.flex_nowrap, 805 | // sm__ 806 | C.sm__mt_16, 807 | // lg__ 808 | C.lg__mt_24, 809 | ], 810 | div![ 811 | C![ 812 | C.text_yellow_4, 813 | C.mr_1, 814 | // sm__ 815 | C.sm__mr_2 816 | // lg__ 817 | C.lg__mr_4 818 | ], 819 | "▶\u{fe0e}" 820 | ], 821 | div![ 822 | "I like to spend my vacation at the cottage - hiking, cycling, driving, etc." 823 | ] 824 | ] 825 | ] 826 | ] 827 | ], 828 | // Work life 829 | div![ 830 | C![ 831 | C.relative, 832 | C.mt_12, 833 | C.pt_3, 834 | C.pb_16, 835 | C.px_12, 836 | C.bg_blue_10, 837 | C.rounded_tl_110px, 838 | // sm__ 839 | C.sm__mt_24, 840 | C.sm__pb_32, 841 | // lg__ 842 | C.lg__mt_56, 843 | C.lg__pb_48, 844 | C.lg__rounded_tl_260px, 845 | ], 846 | // Extended background 847 | div![ 848 | C![ 849 | C.absolute, 850 | C._right_50vw, 851 | C.inset_y_0, 852 | C.w_50vw, 853 | C.bg_blue_10, 854 | ] 855 | ], 856 | // Content container 857 | div![ 858 | C![ 859 | C.relative, 860 | C.w_xs, 861 | // sm__ 862 | C.sm__w_132, 863 | // lg__ 864 | C.lg__w_236, 865 | ], 866 | h3![ 867 | C![ 868 | C.mt_8, 869 | C.mr_8, 870 | C.text_right, 871 | C.font_display, 872 | C.font_thin, 873 | C.text_35, 874 | C.text_blue_3, 875 | // sm__ 876 | C.sm__mt_16, 877 | C.sm__text_60, 878 | // lg__ 879 | C.lg__mt_32, 880 | C.lg__text_90 881 | ], 882 | "Work life" 883 | ], 884 | ul![ 885 | C![ 886 | C.mt_8, 887 | C.ml_1, 888 | C.text_blue_1, 889 | // sm__ 890 | C.sm__mt_12, 891 | // lg__ 892 | C.lg__mt_24, 893 | ], 894 | li![ 895 | C![ 896 | C.flex, 897 | C.flex_nowrap 898 | ], 899 | div![ 900 | C![ 901 | C.text_yellow_4, 902 | C.mr_1, 903 | // sm__ 904 | C.sm__mr_2 905 | // lg__ 906 | C.lg__mr_4 907 | ], 908 | "▶\u{fe0e}" 909 | ], 910 | div![ 911 | "I'm ", 912 | span![ 913 | C![ 914 | C.font_bold, 915 | ], 916 | "more productive" 917 | ], 918 | " when I'm working ", 919 | span![ 920 | C![ 921 | C.font_bold, 922 | ], 923 | "remotely" 924 | ], 925 | "." 926 | ] 927 | ], 928 | li![ 929 | C![ 930 | C.mt_10, 931 | C.flex, 932 | C.flex_nowrap, 933 | // sm__ 934 | C.sm__mt_16 935 | // lg__ 936 | C.lg__mt_24, 937 | ], 938 | div![ 939 | C![ 940 | C.text_yellow_4, 941 | C.mr_1, 942 | // sm__ 943 | C.sm__mr_2, 944 | // lg__ 945 | C.lg__mr_4 946 | ], 947 | "▶\u{fe0e}" 948 | ], 949 | div![ 950 | "I like to ", 951 | span![ 952 | C![ 953 | C.font_bold, 954 | ], 955 | "help" 956 | ], 957 | " people (not only on GitHub) and to mentor juniors." 958 | ] 959 | ], 960 | li![ 961 | C![ 962 | C.mt_10, 963 | C.flex, 964 | C.flex_nowrap, 965 | // sm__ 966 | C.sm__mt_16, 967 | // lg__ 968 | C.lg__mt_24, 969 | ], 970 | div![ 971 | C![ 972 | C.text_yellow_4, 973 | C.mr_1, 974 | // sm__ 975 | C.sm__mr_2, 976 | // lg__ 977 | C.lg__mr_4, 978 | ], 979 | "▶\u{fe0e}" 980 | ], 981 | div![ 982 | "I'd rather think about your project for free in a gym than sit and wait for ideas.", 983 | br![], 984 | "I also recommend to read ", 985 | a![ 986 | attrs!{ 987 | At::Href => "https://medium.com/@jsonpify/you-dont-need-standup-9a74782517c1" 988 | }, 989 | C![ 990 | C.underline, 991 | C.underline_yellow_7 992 | ], 993 | "You don’t need standup" 994 | ], 995 | "." 996 | ] 997 | ] 998 | ] 999 | ] 1000 | ] 1001 | ], 1002 | // Did you know section 1003 | section![ 1004 | C![ 1005 | C.relative, 1006 | C._mt_260px, 1007 | C.h_580px, 1008 | C.pt_px, 1009 | C.rounded_tr_140px, 1010 | C.bg_gray_1, 1011 | C.overflow_hidden, 1012 | C.flex, 1013 | C.flex_col, 1014 | C.items_center, 1015 | // sm__ 1016 | C.sm__h_980px, 1017 | // lg__ 1018 | C.lg__h_1340px, 1019 | C.lg__rounded_tr_330px, 1020 | ], 1021 | h2![ 1022 | C![ 1023 | C.mt_32, 1024 | C.mb_16, 1025 | C.font_display, 1026 | C.font_semibold, 1027 | C.text_40, 1028 | C.text_gray_5, 1029 | // sm__ 1030 | C.sm__mt_56, 1031 | C.sm__mb_32, 1032 | C.sm__text_70, 1033 | // lg__ 1034 | C.lg__mt_64, 1035 | C.lg__mb_40, 1036 | C.lg__text_120, 1037 | ], 1038 | "Did you know..." 1039 | ], 1040 | ul![ 1041 | C![ 1042 | C.ml_12, 1043 | C.w_xs, 1044 | C.text_gray_8, 1045 | // sm__ 1046 | C.sm__w_md, 1047 | // lg__ 1048 | C.lg__ml_32, 1049 | C.lg__w_236, 1050 | ], 1051 | li![ 1052 | C![ 1053 | C.flex, 1054 | C.flex_nowrap 1055 | ], 1056 | div![ 1057 | C![ 1058 | C.text_blue_6, 1059 | C.mr_1, 1060 | // sm__ 1061 | C.sm__mr_2, 1062 | // lg__ 1063 | C.lg__mr_4, 1064 | ], 1065 | "▶\u{fe0e}" 1066 | ], 1067 | div![ 1068 | "I programmed a real football cannon." 1069 | ] 1070 | ], 1071 | li![ 1072 | C![ 1073 | C.mt_10, 1074 | C.flex, 1075 | C.flex_nowrap 1076 | // sm__ 1077 | C.sm__mt_20 1078 | // lg__ 1079 | C.lg__mt_32 1080 | ], 1081 | div![ 1082 | C![ 1083 | C.text_blue_6, 1084 | C.mr_1, 1085 | // sm__ 1086 | C.sm__mr_2, 1087 | // lg__ 1088 | C.lg__mr_4, 1089 | ], 1090 | "▶\u{fe0e}" 1091 | ], 1092 | div![ 1093 | "I jumped off a plane", 1094 | br![], 1095 | "and a bridge." 1096 | ] 1097 | ], 1098 | ] 1099 | ], 1100 | // Want to meet section 1101 | section![ 1102 | C![ 1103 | C.relative, 1104 | C.h_690px, 1105 | C.bg_blue_10, 1106 | C.rounded_br_140px, 1107 | C.flex, 1108 | C.flex_col, 1109 | C.items_center, 1110 | // sm__ 1111 | C.sm__h_930px, 1112 | // lg__ 1113 | C.lg__h_1340px, 1114 | C.lg__rounded_br_330px, 1115 | ], 1116 | div![ 1117 | C![ 1118 | C.relative, 1119 | C._mt_6, 1120 | C.flex, 1121 | C.justify_center, 1122 | // sm__ 1123 | C.sm___mt_10 1124 | // lg__ 1125 | C.lg___mt_20 1126 | ], 1127 | img![ 1128 | C![ 1129 | C.relative, 1130 | C.block, 1131 | C.ml_10vw, 1132 | C.w_265px, 1133 | C.object_contain, 1134 | C.h_full, 1135 | // sm__ 1136 | C.sm__w_385px, 1137 | // lg__ 1138 | C.lg__w_520px, 1139 | ], 1140 | attrs!{ 1141 | At::Src => image_src("photo_2.jpg"), 1142 | } 1143 | ], 1144 | ], 1145 | ul![ 1146 | C![ 1147 | C.mt_16, 1148 | C.w_xs, 1149 | C.text_blue_1, 1150 | // sm__ 1151 | C.sm__mt_24, 1152 | C.sm__w_132, 1153 | C.sm__pl_2, 1154 | // lg__ 1155 | C.lg__mt_32, 1156 | C.lg__w_236, 1157 | C.lg__pl_6 1158 | ], 1159 | li![ 1160 | C![ 1161 | C.flex, 1162 | C.flex_nowrap 1163 | ], 1164 | div![ 1165 | C![ 1166 | C.text_yellow_4, 1167 | C.mr_1, 1168 | // sm__ 1169 | C.sm__mr_2, 1170 | // lg__ 1171 | C.lg__mr_4, 1172 | ], 1173 | "▶\u{fe0e}" 1174 | ], 1175 | div![ 1176 | "Want to meet somewhere in ", 1177 | span![ 1178 | C![ 1179 | C.font_bold 1180 | ], 1181 | "Prague" 1182 | ], 1183 | "?", 1184 | br![], 1185 | "Is there good coffee, tea, sushi or some spicy food? Ok! ", 1186 | a![ 1187 | attrs!{ 1188 | At::Href => MAIL_TO_KAVIK, 1189 | }, 1190 | C![ 1191 | C.underline, 1192 | C.underline_yellow_7, 1193 | ], 1194 | "martin@kavik.cz" 1195 | ] 1196 | ] 1197 | ], 1198 | ] 1199 | ], 1200 | // Resume section 1201 | section![ 1202 | C![ 1203 | C.flex, 1204 | C.flex_col, 1205 | C.justify_center, 1206 | C.items_center, 1207 | ], 1208 | // Download my resume 1209 | a![ 1210 | attrs!{ 1211 | At::Href => asset_path("Martin_Kavik_resume.pdf") 1212 | }, 1213 | C![ 1214 | C.mt_24, 1215 | C.text_19, 1216 | C.text_gray_10, 1217 | C.flex, 1218 | C.whitespace_nowrap, 1219 | C.md__hover__text_yellow_7, 1220 | // sm__ 1221 | C.sm__mt_32, 1222 | C.sm__text_29, 1223 | // lg__ 1224 | C.lg__mt_48, 1225 | C.lg__text_45, 1226 | ], 1227 | "Download my\u{00A0}", 1228 | span![ 1229 | C![ 1230 | C.font_semibold 1231 | ], 1232 | "Resume" 1233 | ], 1234 | span![ 1235 | C![ 1236 | C.font_semibold, 1237 | C.text_gray_5 1238 | ], 1239 | ".pdf" 1240 | ], 1241 | img![ 1242 | C![ 1243 | C._mt_1, 1244 | C.ml_1, 1245 | C.w_12, 1246 | // sm__ 1247 | C.sm__w_16, 1248 | // lg__ 1249 | C.lg__ml_3, 1250 | C.lg__w_24, 1251 | ], 1252 | attrs!{ 1253 | At::Src => image_src("download.svg") 1254 | } 1255 | ], 1256 | ], 1257 | // My GitHub profile 1258 | a![ 1259 | attrs!{ 1260 | At::Href => "https://github.com/MartinKavik" 1261 | }, 1262 | C![ 1263 | C.mt_16, 1264 | C.mb_20, 1265 | C.flex, 1266 | C.items_center, 1267 | C.justify_center, 1268 | C.text_19, 1269 | C.text_gray_10, 1270 | C.md__hover__text_yellow_7, 1271 | // sm__ 1272 | C.sm__mt_24, 1273 | C.sm__mb_32, 1274 | C.sm__text_29, 1275 | // lg__ 1276 | C.lg__mt_40, 1277 | C.lg__mb_40 1278 | C.lg__text_45, 1279 | ], 1280 | "Go to my\u{00A0}", 1281 | span![ 1282 | C![ 1283 | C.font_semibold 1284 | ], 1285 | "GitHub" 1286 | ], 1287 | "\u{00A0}profile", 1288 | img![ 1289 | C![ 1290 | C._mt_4, 1291 | C.w_4, 1292 | // sm__ 1293 | C.sm__w_5, 1294 | // lg__ 1295 | C.lg___mt_10, 1296 | C.lg__w_8, 1297 | ], 1298 | attrs!{ 1299 | At::Src => image_src("link_arrow.svg") 1300 | } 1301 | ], 1302 | ] 1303 | ], 1304 | ] 1305 | } 1306 | --------------------------------------------------------------------------------