17 | Practicalli Amazon Web Services is in early stage of development 18 |
19 | 20 |21 | Try use the Search bar at the top of the page 22 |
23 | 38 | 39 | {% endblock %} 40 | -------------------------------------------------------------------------------- /docs/tools/amazon-linux.md: -------------------------------------------------------------------------------- 1 | # Amazon Linux 2 | 3 | {align=right loading=lazy style="height:150px;width:150px"} 4 | 5 | [Amazon Linux 2](https://aws.amazon.com/amazon-linux-2/){target=_blank} is a Linux operating system from Amazon Web Services (AWS). It provides a security-focused, stable, and high-performance execution environment to develop and run cloud applications. Amazon Linux 2 is provided at no additional charge. AWS provides ongoing security and maintenance updates for Amazon Linux 2. 6 | 7 | 8 | ## Benefits 9 | 10 | * Amazon Linux is provides at no additional charge 11 | * tuned for enhanced performance with support for the latest Amazon EC2 instance capabilities 12 | * includes packages that help ease integration with other AWS Services 13 | * a virtual machine and container image for on-premises development and testing 14 | * avoid environment issues affecting development by building, testing and integrating on the same Linux distribution used in the production environment 15 | * long-term support without compromising access to the latest versions of popular software packages 16 | * a growing community of Technology Partners applications from Independent Software Vendors (ISVs) 17 | -------------------------------------------------------------------------------- /docs/tools/docker/index.md: -------------------------------------------------------------------------------- 1 | # Docker 2 | 3 | Docker provides a relatively straightforward container service and had a very wide range of pre-made container images. 4 | 5 | Docker works best on Linux, although should run on MacOSX and Windows, perhaps with a bit of encouragement. 6 | 7 | Docker images can be pulled onto a local development environment and used or customised as needed. 8 | 9 | ## Docker compose 10 | 11 | [Deploy applications on Amazon ECS using Docker Compose](https://aws.amazon.com/blogs/containers/deploy-applications-on-amazon-ecs-using-docker-compose/){target=_blank .md-button} 12 | 13 | 14 | ## Building Apps Locally 15 | 16 | 17 | ### Leiningen project 18 | 19 | ```docker 20 | FROM clojure:openjdk-8-lein-slim-buster 21 | 22 | RUN apt-get update 23 | 24 | WORKDIR /app 25 | 26 | COPY project.clj . 27 | 28 | # We need to fetch all dependencies as otherwise the `lein compile` command will download them anyway 29 | RUN lein with-profile dev deps 30 | RUN lein with-profile test deps 31 | 32 | COPY . . 33 | 34 | RUN lein compile 35 | 36 | CMD lein with-profile prod run -m practicalli.game-statistics.core 37 | ``` 38 | 39 | ### Database 40 | 41 | ```docker 42 | CREATE ROLE gameadmin LOGIN SUPERUSER PASSWORD 'TrustNo1'; 43 | CREATE DATABASE game-stats 44 | WITH 45 | OWNER = practicalli; 46 | ``` 47 | -------------------------------------------------------------------------------- /overrides/partials/palette.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 37 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | :memo: Description 2 | 3 | 4 | :white_check_mark: Checklist 5 | 6 | - [ ] Commits should be cryptographically signed (SSH or GPG) 7 | 8 | 9 | ## Practicalli Guidelines 10 | 11 | Please follow these guidelines when submitting a pull request 12 | 13 | - refer to all relevant issues, using `#` followed by the issue number (or paste full link to the issue) 14 | - PR should contain the smallest possible change 15 | - PR should contain a very specific change 16 | - PR should contain only a single commit (squash your commits locally if required) 17 | - Avoid multiple changes across multiple files (raise an issue so we can discuss) 18 | - Avoid a long list of spelling or grammar corrections. These take too long to review and cherry pick. 19 | 20 | ## Submitting articles 21 | 22 | [Create an issue using the article template](https://github.com/practicalli/blog-content/issues/new?assignees=&labels=article&template=article.md&title=Suggested+article+title), 23 | providing as much detail as possible. 24 | 25 | ## Website design 26 | 27 | Suggestions about website design changes are most welcome, especially in terms of usability and accessibility. 28 | 29 | Please raise an issue so we can discuss changes first, especially changes related to aesthetics. 30 | 31 | ## Review process 32 | 33 | All pull requests are reviewed by @practicalli-johnny and feedback provided, usually the same day but please be patient. 34 | -------------------------------------------------------------------------------- /.github/workflows/changelog-check.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # Check CHANGELOG.md file updated for every pull request 3 | 4 | name: Changelog Check 5 | on: 6 | pull_request: 7 | paths-ignore: 8 | - "README.md" 9 | types: [opened, synchronize, reopened, ready_for_review, labeled, unlabeled] 10 | 11 | jobs: 12 | changelog: 13 | name: Changelog Update Check 14 | runs-on: ubuntu-latest 15 | steps: 16 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 17 | - run: echo "🐧 Job running on ${{ runner.os }} server" 18 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 19 | 20 | # Git Checkout 21 | - name: Checkout Code 22 | uses: actions/checkout@v4 23 | with: 24 | fetch-depth: 0 25 | sparse-checkout: | 26 | docs 27 | overrides 28 | .github 29 | CHANGELOG.md 30 | - run: echo "🐙 Sparse Checkout of ${{ github.repository }} repository to the CI runner." 31 | 32 | # Changelog Enforcer 33 | - name: Changelog Enforcer 34 | uses: dangoslen/changelog-enforcer@v3 35 | with: 36 | changeLogPath: "CHANGELOG.md" 37 | skipLabels: "skip-changelog-check" 38 | 39 | # Summary and status 40 | - run: echo "🎨 Changelog Enforcer quality checks completed" 41 | - run: echo "🍏 Job status is ${{ job.status }}." 42 | -------------------------------------------------------------------------------- /.github/workflows/scheduled-version-check.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # ------------------------------------------ 3 | # Scheduled check of versions 4 | # - use as non-urgent report on versions 5 | # - Uses POSIX Cron syntax 6 | # - Minute [0,59] 7 | # - Hour [0,23] 8 | # - Day of the month [1,31] 9 | # - Month of the year [1,12] 10 | # - Day of the week ([0,6] with 0=Sunday) 11 | # 12 | # Using liquidz/anta to check: 13 | # - GitHub workflows 14 | # - deps.edn 15 | # ------------------------------------------ 16 | 17 | name: "Scheduled Version Check" 18 | on: 19 | schedule: 20 | # - cron: "0 4 * * *" # at 04:04:04 ever day 21 | # - cron: "0 4 * * 5" # at 04:04:04 ever Friday 22 | - cron: "0 4 1 * *" # at 04:04:04 on first day of month 23 | workflow_dispatch: # Run manually via GitHub Actions Workflow page 24 | 25 | jobs: 26 | scheduled-version-check: 27 | name: "Scheduled Version Check" 28 | runs-on: ubuntu-latest 29 | steps: 30 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 31 | - run: echo "🐧 Job running on ${{ runner.os }} server" 32 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 33 | 34 | - name: Checkout Code 35 | uses: actions/checkout@v4 36 | with: 37 | fetch-depth: 0 38 | sparse-checkout: | 39 | .github 40 | - run: echo "🐙 ${{ github.repository }} repository sparse-checkout to the CI runner." 41 | - name: "Antq Check versions" 42 | uses: liquidz/antq-action@main 43 | with: 44 | excludes: "" 45 | skips: "boot clojure-cli pom shadow-cljs leiningen" 46 | 47 | # Summary 48 | - run: echo "🎨 library versions checked with liquidz/antq" 49 | - run: echo "🍏 Job status is ${{ job.status }}." 50 | -------------------------------------------------------------------------------- /.github/workflows/publish-book.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Publish Book 3 | on: 4 | # Manually trigger workflow 5 | workflow_dispatch: 6 | 7 | # Run work flow conditional on linter workflow success 8 | workflow_run: 9 | workflows: 10 | - "MegaLinter" 11 | paths: 12 | - "docs/**" 13 | - "includes/**" 14 | - "overrides/**" 15 | - "mkdocs.yaml" 16 | branches: 17 | - main 18 | types: 19 | - completed 20 | 21 | permissions: 22 | contents: write 23 | 24 | jobs: 25 | publish-book: 26 | name: MkDocs Publish 27 | runs-on: ubuntu-latest 28 | steps: 29 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 30 | - run: echo "🐧 Job running on ${{ runner.os }} server" 31 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 32 | 33 | - name: Checkout Code 34 | uses: actions/checkout@v4 35 | with: 36 | fetch-depth: 0 37 | sparse-checkout: | 38 | docs 39 | includes 40 | overrides 41 | - run: echo "🐙 ${{ github.repository }} repository sparse-checkout to the CI runner." 42 | 43 | - name: Setup Python 44 | uses: actions/setup-python@v5 45 | with: 46 | python-version: 3.x 47 | 48 | - name: Cache 49 | uses: actions/cache@v4 50 | with: 51 | key: ${{ github.ref }} 52 | path: .cache 53 | 54 | - run: pip install mkdocs-material mkdocs-callouts mkdocs-glightbox mkdocs-git-revision-date-localized-plugin mkdocs-redirects pillow cairosvg 55 | - run: mkdocs gh-deploy --force 56 | - run: echo "🐙 ." 57 | 58 | # Summary and status 59 | - run: echo "🎨 MkDocs Publish Book workflow completed" 60 | - run: echo "🍏 Job status is ${{ job.status }}." 61 | -------------------------------------------------------------------------------- /docs/tools/docker/localstack.md: -------------------------------------------------------------------------------- 1 | # Local stack 2 | 3 | {align=right loading=lazy style="height:150px;width:150px"} 4 | 5 | [LocalStack](https://github.com/localstack/localstack) is a cloud service emulator that runs in a single container on your laptop or in your CI environment. With LocalStack, you can run your AWS applications or Lambdas entirely on your local machine without connecting to a remote cloud provider! Whether you are testing complex CDK applications or Terraform configurations, or just beginning to learn about AWS services, LocalStack helps speed up and simplify your testing and development workflow. 6 | 7 | LocalStack supports a growing number of AWS services, like AWS Lambda, S3, Dynamodb, Kinesis, SQS, SNS, and many more! The Pro version of LocalStack supports additional APIs and advanced features. You can find a comprehensive list of supported APIs on our ballot_box_with_check Feature Coverage page. 8 | 9 | LocalStack also provides additional features to make your life as a cloud developer easier! Check out LocalStack's Cloud Developer Tools for more information. 10 | 11 | 12 | === "LocalStack CLI" 13 | Start localstack in a Docker image using the LocalStack cli 14 | 15 | ```shell 16 | % localstack start -d 17 | ``` 18 | 19 | The output should look similar to 20 | 21 | ```shell 22 | / / ____ _________ _/ / ___// /_____ ______/ /__ 23 | / / / __ \/ ___/ __ `/ /\__ \/ __/ __ `/ ___/ //_/ 24 | / /___/ /_/ / /__/ /_/ / /___/ / /_/ /_/ / /__/ ,< 25 | /_____/\____/\___/\__,_/_//____/\__/\__,_/\___/_/|_| 26 | 27 | 💻 LocalStack CLI 1.4.0 28 | 29 | [20:22:20] starting LocalStack in Docker mode 🐳 30 | [20:22:21] detaching 31 | ``` 32 | 33 | === "Docker" 34 | 35 | ```shell 36 | docker run --rm -it -p 4566:4566 -p 4510-4559:4510-4559 localstack/localstack 37 | ``` 38 | -------------------------------------------------------------------------------- /.github/workflows/scheduled-stale-check.yaml: -------------------------------------------------------------------------------- 1 | # ---------------------------------------- 2 | # Scheduled stale issue & pull request check 3 | # 4 | # Adds 'stale' label after a set piece of time, 5 | # then closes stale issues & pull requests a short period after 6 | # 7 | # Using "Close Stale Issues" action 8 | # https://github.com/marketplace/actions/close-stale-issues 9 | # ---------------------------------------- 10 | 11 | name: 'Scheduled stale check' 12 | on: 13 | workflow_dispatch: 14 | schedule: 15 | - cron: "0 1 1 * *" # at 01:00 on first day of month 16 | 17 | jobs: 18 | stale: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 22 | - run: echo "🐧 Job running on ${{ runner.os }} server" 23 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 24 | 25 | - uses: actions/stale@v9 26 | with: 27 | stale-issue-message: 'After 30 days with no activity, the issue was automatically marked stale. Remove stale label or add a comment to prevent the issue being closed in 5 days.' 28 | stale-pr-message: 'After 45 days with no activity, the Pull Request was automatically marked stale. Remove stale label or comment to prevent the PR being closed in 10 days.' 29 | close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.' 30 | close-pr-message: 'This PR was closed because it has been stalled for 10 days with no activity.' 31 | days-before-issue-stale: 30 32 | days-before-pr-stale: 45 33 | days-before-issue-close: 5 34 | days-before-pr-close: 10 35 | start-date: '2025-04-05T00:00:00Z' # only affect issues/PRs from date created (ISO 8601 or RFC 2822 format) 36 | any-of-labels: 'future,keep' # labels to keep 37 | exempt-issue-assignees: 'practicalli-johnny' 38 | exempt-pr-assignees: 'practicalli-johnny' 39 | 40 | # Summary 41 | - run: echo "🎨 Issues & Pull Request checked with actions/stale" 42 | - run: echo "🍏 Job status is ${{ job.status }}." 43 | -------------------------------------------------------------------------------- /.github/workflows/megalinter.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | # MegaLinter GitHub Action configuration file 3 | # More info at https://megalinter.io 4 | # All variables described in https://megalinter.io/latest/configuration/ 5 | 6 | name: MegaLinter 7 | on: 8 | workflow_dispatch: 9 | pull_request: 10 | branches: [main] 11 | push: 12 | branches: [main] 13 | 14 | # Run Linters in parallel 15 | # Cancel running job if new job is triggered 16 | concurrency: 17 | group: "${{ github.ref }}-${{ github.workflow }}" 18 | cancel-in-progress: true 19 | 20 | jobs: 21 | megalinter: 22 | name: MegaLinter 23 | runs-on: ubuntu-latest 24 | steps: 25 | - run: echo "🚀 Job automatically triggered by ${{ github.event_name }}" 26 | - run: echo "🐧 Job running on ${{ runner.os }} server" 27 | - run: echo "🐙 Using ${{ github.ref }} branch from ${{ github.repository }} repository" 28 | 29 | # Git Checkout 30 | - name: Checkout Code 31 | uses: actions/checkout@v4 32 | with: 33 | fetch-depth: 0 34 | sparse-checkout: | 35 | docs 36 | overrides 37 | .github 38 | - run: echo "🐙 Sparse Checkout of ${{ github.repository }} repository to the CI runner." 39 | 40 | # MegaLinter Configuration 41 | - name: MegaLinter Run 42 | id: ml 43 | ## latest release of major version 44 | uses: oxsecurity/megalinter/flavors/documentation@v8 45 | env: 46 | # ADD CUSTOM ENV VARIABLES OR DEFINE IN MEGALINTER_CONFIG file 47 | MEGALINTER_CONFIG: .github/config/megalinter.yaml 48 | 49 | GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" # report individual linter status 50 | # Validate all source when push on main, else just the git diff with live. 51 | VALIDATE_ALL_CODEBASE: >- 52 | ${{ github.event_name == 'push' && github.ref == 'refs/heads/main'}} 53 | 54 | # Upload MegaLinter artifacts 55 | - name: Archive production artifacts 56 | if: ${{ success() }} || ${{ failure() }} 57 | uses: actions/upload-artifact@v4 58 | with: 59 | name: MegaLinter reports 60 | path: | 61 | megalinter-reports 62 | mega-linter.log 63 | 64 | # Summary and status 65 | - run: echo "🎨 MegaLinter quality checks completed" 66 | - run: echo "🍏 Job status is ${{ job.status }}." 67 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # ------------------------------------------ 2 | # Practicalli: Makefile 3 | # 4 | # Consistent set of targets to support local book development 5 | # ------------------------------------------ 6 | 7 | # .PHONY: ensures target used rather than matching file name 8 | # https://makefiletutorial.com/#phony 9 | .PHONY: all clean docs lint pre-commit-check test 10 | 11 | # ------- Makefile Variables --------- # 12 | # run help if no target specified 13 | .DEFAULT_GOAL := help 14 | SHELL := /usr/bin/zsh 15 | 16 | # Column the target description is printed from 17 | HELP-DESCRIPTION-SPACING := 24 18 | 19 | # Tool Commands 20 | MEGALINTER_RUNNER := npx mega-linter-runner --flavor documentation --env "'MEGALINTER_CONFIG=.github/config/megalinter.yaml'" --env "'VALIDATE_ALL_CODEBASE=true'" --remove-container 21 | MKDOCS_SERVER := mkdocs serve --dev-addr localhost:7777 22 | 23 | # Makefile file and directory name wildcard 24 | EDN-FILES := $(wildcard *.edn) 25 | # ------------------------------------ # 26 | 27 | # ------ Quality Checks ------------ # 28 | pre-commit-check: lint 29 | 30 | lint: ## Run MegaLinter with custom configuration (node.js required) 31 | $(info --------- MegaLinter Runner ---------) 32 | $(MEGALINTER_RUNNER) 33 | 34 | lint-fix: ## Run MegaLinter with custom configuration (node.js required) 35 | $(info --------- MegaLinter Runner ---------) 36 | $(MEGALINTER_RUNNER) --fix 37 | 38 | lint-clean: ## Clean MegaLinter report information 39 | $(info --------- MegaLinter Clean Reports ---------) 40 | - rm -rf ./megalinter-reports 41 | 42 | megalinter-upgrade: ## Upgrade MegaLinter config to latest version 43 | $(info --------- MegaLinter Upgrade Config ---------) 44 | npx mega-linter-runner@latest --upgrade 45 | # ------------------------------------ # 46 | 47 | # --- Documentation Generation ------ # 48 | python-venv: ## Enable Python Virtual Environment for MkDocs 49 | $(info --------- Mkdocs Local Server ---------) 50 | source ~/.local/venv/bin/activate 51 | 52 | docs: ## Build and run mkdocs in local server (python venv) 53 | $(info --------- Mkdocs Local Server ---------) 54 | source ~/.local/venv/bin/activate && $(MKDOCS_SERVER) 55 | 56 | docs-changed: ## Build only changed files and run mkdocs in local server (python venv) 57 | $(info --------- Mkdocs Local Server ---------) 58 | source ~/.local/venv/bin/activate && $(MKDOCS_SERVER) --dirtyreload 59 | 60 | docs-build: ## Build mkdocs (python venv) 61 | $(info --------- Mkdocs Local Server ---------) 62 | source ~/.local/venv/bin/activate && mkdocs build 63 | # ------------------------------------ # 64 | 65 | # ------------ Help ------------------ # 66 | # Source: https://nedbatchelder.com/blog/201804/makefile_help_target.html 67 | 68 | help: ## Describe available tasks in Makefile 69 | @grep '^[a-zA-Z]' $(MAKEFILE_LIST) | \ 70 | sort | \ 71 | awk -F ':.*?## ' 'NF==2 {printf "\033[36m %-$(HELP-DESCRIPTION-SPACING)s\033[0m %s\n", $$1, $$2}' 72 | # ------------------------------------ # 73 | -------------------------------------------------------------------------------- /overrides/partials/header.html: -------------------------------------------------------------------------------- 1 | 2 | {% set class = "md-header" %} {% if "navigation.tabs.sticky" in features %} {% 3 | set class = class ~ " md-header--shadow md-header--lifted" %} {% elif 4 | "navigation.tabs" not in features %} {% set class = class ~ " md-header--shadow" 5 | %} {% endif %} 6 | 7 | 8 |
79 | This work is licensed under a Creative Commons Attribution 4.0 ShareAlike License (including images & stylesheets).
80 |
27 | This work is licensed under a Creative Commons Attribution 4.0 ShareAlike License (including images & stylesheets).
28 | 35 | 36 |
37 | 38 | ??? HINT "Evaluate Clojure in a Terminal UI REPL" 39 | Entering expressions at the REPL prompt evaluates the expression immediately, returning the result directly underneath 40 | {loading=lazy} 41 | {loading=lazy} 42 | 43 | ## Rich Comment blocks - living documentation 44 | 45 | The `(comment ,,,)` function wraps code that is only run directly by the developer using a [Clojure aware editor](https://practical.li/clojure/clojure-editors/){target=_blank}. 46 | 47 | Expressions in rich comment blocks can represent how to use the functions that make up the namespace API. For example, starting/restarting the system, updating the database, etc. Expressions provide examples of calling functions with typical arguments and make a project more accessible and easier to work with. 48 | 49 | !!! EXAMPLE "Clojure Rich Comment to manage a service" 50 | ```clojure 51 | (ns practicalli.gameboard.service) 52 | 53 | (defn app-server-start [port] ,,,) 54 | (defn app-server-start [] ,,,) 55 | (defn app-server-restart [] ,,,) 56 | 57 | (defn -main 58 | "Start the service using system components" 59 | [& options] ,,,) 60 | 61 | (comment 62 | (-main) 63 | (app-server-start 8888) 64 | (app-server-stop) 65 | (app-server-restart 8888) 66 | 67 | (System/getenv "PORT") 68 | (def environment (System/getenv)) 69 | (def system-properties (System/getProperties)) 70 | ) ; End of rich comment block 71 | ``` 72 | 73 | Rich comment blocks are very useful for rapidly iterating over different design decisions by including the same function but with different implementations. Hide [clj-kondo linter](https://practical.li/clojure/clojure-cli/install/code-analysis.html){target=_blank} warnings for redefined vars (`def`, `defn`) when using this approach. 74 | 75 | ```clojure 76 | ;; Rich comment block with redefined vars ignored 77 | #_{:clj-kondo/ignore [:redefined-var]} 78 | (comment 79 | (defn value-added-tax [] 80 | ;; algorithm design - first idea) 81 | 82 | (defn value-added-tax [] 83 | ;; algorithm design - second idea) 84 | 85 | ) ;; End of rich comment block 86 | ``` 87 | 88 | The "Rich" in the name is an honourary mention to Rich Hickey, the author and benevolent dictator of Clojure design. 89 | 90 | ## Design Journal 91 | 92 | A journal of design decisions makes the code easier to understand and maintain. Code examples of design decisions and alternative design discussions are captured, reducing the time spent revisiting those discussions. 93 | 94 | Journals simplify the developer on-boarding processes as the journey through design decisions are already documented. 95 | 96 | A Design Journal is usually created in a separate namespace, although it may start as a rich comment at the bottom of a namespace. 97 | 98 | A journal should cover the following aspects 99 | 100 | * Relevant expressions use to test assumptions about design options. 101 | * Examples of design choices not taken and discussions why (saves repeating the same design discussions) 102 | * Expressions that can be evaluated to explain how a function or parts of a function work 103 | 104 | The design journal can be used to create meaningful documentation for the project very easily and should prevent time spent on repeating the same conversations. 105 | 106 | !!! HINT "Example design journal" 107 | [Design journal for TicTacToe game using Reagent, ClojureScript and Scalable Vector Graphics](https://github.com/practicalli-john/tictactoe-reagent/blob/master/src/tictactoe_reagent/core.cljs#L124){target=_blank} 108 | 109 | ## Viewing data structures 110 | 111 | Pretty print shows the structure of results from function calls in a human-friendly form, making it easier for a developer to parse and more likely to notice incorrect results. 112 | 113 | Tools to view and navigate code 114 | 115 | * [:fontawesome-solid-book-open: Cider inspector](https://practical.li/spacemacs/evaluating-clojure/inspect/){target=_blank} is an effective way to navigate nested data and page through large data sets. 116 | * [:fontawesome-solid-book-open: Portal Inspector](https://practical.li/clojure/clojure-tools/data-inspector/portal){target=_blank} to visualise many kinds of data in many different forms. 117 | 118 |  119 | 120 | 121 | ## Code Style and idiomatic Clojure 122 | 123 | Clojure aware editors should automatically apply formatting that follows the [:globe_with_meridians: Clojure Style guide](https://github.com/bbatsov/clojure-style-guide){target=_blank}. 124 | 125 | Live linting with [clj-kondo](:fontawesome-brands-github:209 | 210 |
211 | -------------------------------------------------------------------------------- /docs/introduction/writing-tips.md: -------------------------------------------------------------------------------- 1 | # Writing tips for MkDocs 2 | 3 | Making the docs more engaging using the [mkdocs-material theme reference guide](https://squidfunk.github.io/mkdocs-material/reference/){target=_blank} 4 | 5 | ??? INFO "Configuring Colors" 6 | [Material for MkDocs - Changing the colors](https://squidfunk.github.io/mkdocs-material/setup/changing-the-colors/){target=_blank} lists the primary and accent colors available. 7 | 8 | [HSL Color Picker](https://hslpicker.com/) for codes to modify the theme style, overriding colors in `docs/assets/stylesheets/extra.css` 9 | 10 | ## Hypertext links 11 | 12 | Links open in the same browser window/tab by default. 13 | 14 | Add `{target=_blank}` to the end of a link to configure opening in a new tab 15 | 16 | ```markdown 17 | [link text](url){target=_blank} 18 | ``` 19 | 20 | ## Buttons 21 | 22 | Convert any link into a button by adding `{.md-button}` class names to end of the markdown for a link, which uses `.md-button-primary` by default. Include `target=_blank` for buttons with links to external sites. 23 | 24 | ```markdown 25 | [link text](http://practical.li/blog){.md-button target=_blank} 26 | ``` 27 | 28 | Or specify a different class 29 | 30 | ```markdown 31 | [link text](http://practical.li/blog){.md-button .md-button-primary} 32 | ``` 33 | 34 | Add an icon to the button 35 | 36 | [:fontawesome-brands-github: Practicalli Issues](http://practical.li/blog){ .md-button .md-button-primary } 37 | [:octicons-heart-fill-24: Practicalli Blog](http://practical.li/blog){ .md-button .md-button-primary } 38 | 39 | ```markdown 40 | [:fontawesome-brands-github: Practicalli Issues](http://practical.li/blog){ .md-button .md-button-primary } 41 | [:octicons-heart-fill-24: Practicalli Blog](http://practical.li/blog){ .md-button .md-button-primary } 42 | ``` 43 | 44 | [Search all supported icons](https://squidfunk.github.io/mkdocs-material/reference/icons-emojis/){target=_blank .md-button} 45 | 46 | ## YouTube video 47 | 48 | Use an iframe element to include a YouTube video, wrapping in a paragraph tag with center alignment to place the video in a centered horizontal position 49 | 50 | ```html 51 |52 | 53 |
54 | ``` 55 | 56 | > mkdocs material does not have direct support for adding a YouTube video via markdown. 57 | 58 | ## Admonitions 59 | 60 | [Supported admonition types](https://squidfunk.github.io/mkdocs-material/reference/admonitions/#supported-types) 61 | 62 | !!! NOTE 63 | Use `!!!` followed by `NOTE` 64 | 65 | !!! NOTE "Adding a title" 66 | Use `!!!` followed by `NOTE` and a `"title in double quotes"` 67 | 68 | !!! NOTE "" 69 | Shh, no title bar just the text... 70 | Use `!!!` followed by `NOTE` and a `""` empty double quotes 71 | 72 | !!! ABSTRACT 73 | Use `!!!` followed by `ABSTRACT` 74 | 75 | !!! INFO 76 | Use `!!!` followed by `INFO` 77 | 78 | !!! TIP 79 | Use `!!!` followed by `TIP` 80 | 81 | !!! SUCCESS 82 | Use `!!!` followed by `SUCCESS` 83 | 84 | !!! QUESTION 85 | Use `!!!` followed by `QUESTION` 86 | 87 | !!! WARNING 88 | Use `!!!` followed by `WARNING` 89 | 90 | !!! FAILURE 91 | Use `!!!` followed by `FAILURE` 92 | 93 | !!! DANGER 94 | Use `!!!` followed by `DANGER` 95 | 96 | !!! BUG 97 | Use `!!!` followed by `BUG` 98 | 99 | !!! EXAMPLE 100 | Use `!!!` followed by `EXAMPLE` 101 | 102 | !!! QUOTE 103 | Use `!!!` followed by `QUOTE` 104 | 105 | ### Collapsing admonitions 106 | 107 | ??? NOTE 108 | Collapse those admonitions using `???` instead of `!!!` 109 | 110 | ??? NOTE "Replace with a title" 111 | Use `???` followed by `NOTE` and a `"title in double quotes"` 112 | 113 | ???+ NOTE "Expanded by default" 114 | Use `???+`, note the `+` character, followed by `NOTE` and a `"title in double quotes"` 115 | 116 | ### Inline blocks 117 | 118 | Inline blocks of text to make a very specific callout within text 119 | 120 | !!! info inline 121 | 122 | Lorem ipsum dolor sit amet, consectetur 123 | adipiscing elit. Nulla et euismod nulla. 124 | Curabitur feugiat, tortor non consequat 125 | finibus, justo purus auctor massa, nec 126 | semper lorem quam in massa. 127 | 128 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. 129 | 130 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. 131 | 132 | Adding something to then end of text is probably my favourite 133 | 134 | !!! info inline end 135 | 136 | Lorem ipsum dolor sit amet, consectetur 137 | adipiscing elit. Nulla et euismod nulla. 138 | Curabitur feugiat, tortor non consequat 139 | finibus, justo purus auctor massa, nec 140 | semper lorem quam in massa. 141 | 142 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. 143 | 144 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa. 145 | 146 | ## Code blocks 147 | 148 | Code blocks include a copy icon automatically 149 | 150 | Syntax highlighting in code blocks 151 | 152 | ```clojure 153 | (defn my-function ; Write a simple function 154 | "With a lovely doc-string" 155 | [arguments] 156 | (map inc [1 2 3])) 157 | ``` 158 | 159 | Give the code block a title using `title=""` after the backtics and language name 160 | 161 | ```clojure title="src/practicalli/gameboard.clj" 162 | (defn my-function 163 | "With a lovely doc-string" 164 | [arguments] 165 | (map inc [1 2 3])) 166 | ``` 167 | 168 | We all like line numbers, especially when you can set the starting line 169 | 170 | ```clojure linenums="42" title="src/practicalli/gameboard.clj" 171 | (defn my-function 172 | "With a lovely doc-string" 173 | [arguments] 174 | (map inc [1 2 3])) 175 | ``` 176 | 177 | Add `linenums=42` to start line numbers from 42 onward 178 | 179 | ```shell 180 | clojure linenums="42" title="src/practicalli/gameboard.clj" 181 | ``` 182 | 183 | ### Annotations 184 | 185 | Annotations in a code block help to highlight important aspects. Use the comment character for the language followed by a space and a number in brackets 186 | 187 | For example, in a shell code block, use `# (1)` where 1 is the number of the annotation 188 | 189 | Use a number after the code block to add the text for the annotation, e.g. `1.`. Ensure there is a space between the code block and the annotation text. 190 | 191 | ```shell 192 | ls -la $HOME/Downloads # (1) 193 | ``` 194 | 195 | 1. :woman_raising_hand: I'm a code annotation! I can contain `code`, __formatted text__, images, ... basically anything that can be written in Markdown. 196 | 197 | 198 | Code blocks with annotation, add `!` after the annotation number to suppress the `#` character 199 | 200 | ```clojure 201 | (defn helper-function 202 | "Doc-string with description of function purpose" ; (1)! 203 | [data] 204 | (merge {:fish 1} data) 205 | ) 206 | ``` 207 | 208 | 1. Always include a doc-string in every function to describe the purpose of that function, identifying why it was added and what its value is. 209 | 210 | GitHub action example with multiple annotations 211 | 212 | ```yaml 213 | name: ci # (1)! 214 | on: 215 | push: 216 | branches: 217 | - master # (2)! 218 | - main 219 | permissions: 220 | contents: write 221 | jobs: 222 | deploy: 223 | runs-on: ubuntu-latest 224 | steps: 225 | - uses: actions/checkout@v3 226 | - uses: actions/setup-python@v4 227 | with: 228 | python-version: 3.x 229 | - run: pip install mkdocs-material # (3)! 230 | - run: mkdocs gh-deploy --force 231 | ``` 232 | 233 | 1. You can change the name to your liking. 234 | 235 | 2. At some point, GitHub renamed `master` to `main`. If your default branch 236 | is named `master`, you can safely remove `main`, vice versa. 237 | 238 | 3. This is the place to install further [MkDocs plugins] or Markdown 239 | extensions with `pip` to be used during the build: 240 | 241 | ```shell 242 | pip install \ 243 | mkdocs-material \ 244 | mkdocs-awesome-pages-plugin \ 245 | ... 246 | ``` 247 | 248 | ### Highlight lines in code blocks 249 | 250 | Add highlight line meta data to a code block after the opening backticks and code block language. 251 | 252 | `hl_lines="2"` highlights line 2 in the codeblock 253 | 254 | ```clojure hl_lines="4 5 6" 255 | (defn my-function 256 | "With a lovely doc-string" 257 | [arguments] 258 | (map 259 | inc 260 | [1 2 3])) 261 | ``` 262 | 263 | ### Embed external files 264 | 265 | `--8<--` in a code block inserts code from a source code file or other text file 266 | 267 | Specify a local file from the root of the book project (the directory containing mkdocs.yml) 268 | 269 | ??? EXAMPLE "Scheduled Version Check GitHub Workflow from source code file" 270 | ```yaml title="scheduled version check" 271 | --8<-- ".github/workflows/scheduled-version-check.yaml" 272 | ``` 273 | 274 | ??? EXAMPLE "Practicalli Project Templates" 275 | ```markdown title="Emacs project configuration - .dir-locals.el" 276 | --8<-- "https://raw.githubusercontent.com/practicalli/project-templates/main/.dir-locals.el" 277 | ``` 278 | 279 | !!! HINT "Code example reuse" 280 | Use an embedded local or external file (URL) when the same content is required in more than one place in the book. 281 | 282 | An effective way of sharing code and configuration mutliple times in a book or across multiple books. 283 | 284 | ## Content tabs 285 | 286 | Create in page tabs that can also be 287 | 288 | Setting up a project 289 | 290 | === "Clojure CLI" 291 | ```shell 292 | clojure -T:project/new :template app :name practicalli/gameboard 293 | ``` 294 | 295 | === "Leiningen" 296 | ```shell 297 | lein new app practicalli/gameboard 298 | ``` 299 | 300 | Or nest the content tabs in an admonition 301 | 302 | !!! INFO "Run a terminal REPL" 303 | 304 | === "Clojure CLI" 305 | ```shell 306 | clojure -T:repl/rebel 307 | ``` 308 | 309 | 310 | === "Leiningen" 311 | ```shell 312 | lein repl 313 | ``` 314 | 315 | ## Diagrams 316 | 317 | Neat flow diagrams 318 | 319 | [Diagrams - Material for MkDocs](https://squidfunk.github.io/mkdocs-material/reference/diagrams/){target=_blank .md-button} 320 | 321 | ```mermaid 322 | graph LR 323 | A[Start] --> B{Error?}; 324 | B -->|Yes| C[Hmm...]; 325 | C --> D[Debug]; 326 | D --> B; 327 | B ---->|No| E[Yay!]; 328 | ``` 329 | 330 | UML Sequence Diagrams 331 | 332 | ```mermaid 333 | sequenceDiagram 334 | Alice->>John: Hello John, how are you? 335 | loop Healthcheck 336 | John->>John: Fight against hypochondria 337 | end 338 | Note right of John: Rational thoughts! 339 | John-->>Alice: Great! 340 | John->>Bob: How about you? 341 | Bob-->>John: Jolly good! 342 | ``` 343 | 344 | state transition diagrams 345 | 346 | ```mermaid 347 | stateDiagram-v2 348 | state fork_state <