diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..5bf4860b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,26 @@ +root = true + +[*] +charset = utf-8 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +indent_size = 2 +indent_style = space +max_line_length = 100 # Please keep this in sync with bin/lesson_check.py! +trim_trailing_whitespace = false # keep trailing spaces in markdown - 2+ spaces are translated to a hard break (
) + +[*.r] +max_line_length = 80 + +[*.py] +indent_size = 4 +indent_style = space +max_line_length = 79 + +[*.sh] +end_of_line = lf + +[Makefile] +indent_style = tab diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100755 index 00000000..77d624ac --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,193 @@ +# Carpentries Workflows + +This directory contains workflows to be used for Lessons using the {sandpaper} +lesson infrastructure. Two of these workflows require R (`sandpaper-main.yaml` +and `pr-recieve.yaml`) and the rest are bots to handle pull request management. + +These workflows will likely change as {sandpaper} evolves, so it is important to +keep them up-to-date. To do this in your lesson you can do the following in your +R console: + +```r +# Install/Update sandpaper +options(repos = c(carpentries = "https://carpentries.r-universe.dev/", + CRAN = "https://cloud.r-project.org")) +install.packages("sandpaper") + +# update the workflows in your lesson +library("sandpaper") +update_github_workflows() +``` + +Inside this folder, you will find a file called `sandpaper-version.txt`, which +will contain a version number for sandpaper. This will be used in the future to +alert you if a workflow update is needed. + +What follows are the descriptions of the workflow files: + +## Deployment + +### 01 Build and Deploy (sandpaper-main.yaml) + +This is the main driver that will only act on the main branch of the repository. +This workflow does the following: + + 1. checks out the lesson + 2. provisions the following resources + - R + - pandoc + - lesson infrastructure (stored in a cache) + - lesson dependencies if needed (stored in a cache) + 3. builds the lesson via `sandpaper:::ci_deploy()` + +#### Caching + +This workflow has two caches; one cache is for the lesson infrastructure and +the other is for the the lesson dependencies if the lesson contains rendered +content. These caches are invalidated by new versions of the infrastructure and +the `renv.lock` file, respectively. If there is a problem with the cache, +manual invaliation is necessary. You will need maintain access to the repository +and you can either go to the actions tab and [click on the caches button to find +and invalidate the failing cache](https://github.blog/changelog/2022-10-20-manage-caches-in-your-actions-workflows-from-web-interface/) +or by setting the `CACHE_VERSION` secret to the current date (which will +invalidate all of the caches). + +## Updates + +### Setup Information + +These workflows run on a schedule and at the maintainer's request. Because they +create pull requests that update workflows/require the downstream actions to run, +they need a special repository/organization secret token called +`SANDPAPER_WORKFLOW` and it must have the `public_repo` and `workflow` scope. + +This can be an individual user token, OR it can be a trusted bot account. If you +have a repository in one of the official Carpentries accounts, then you do not +need to worry about this token being present because the Carpentries Core Team +will take care of supplying this token. + +If you want to use your personal account: you can go to + +to create a token. Once you have created your token, you should copy it to your +clipboard and then go to your repository's settings > secrets > actions and +create or edit the `SANDPAPER_WORKFLOW` secret, pasting in the generated token. + +If you do not specify your token correctly, the runs will not fail and they will +give you instructions to provide the token for your repository. + +### 02 Maintain: Update Workflow Files (update-workflow.yaml) + +The {sandpaper} repository was designed to do as much as possible to separate +the tools from the content. For local builds, this is absolutely true, but +there is a minor issue when it comes to workflow files: they must live inside +the repository. + +This workflow ensures that the workflow files are up-to-date. The way it work is +to download the update-workflows.sh script from GitHub and run it. The script +will do the following: + +1. check the recorded version of sandpaper against the current version on github +2. update the files if there is a difference in versions + +After the files are updated, if there are any changes, they are pushed to a +branch called `update/workflows` and a pull request is created. Maintainers are +encouraged to review the changes and accept the pull request if the outputs +are okay. + +This update is run ~~weekly or~~ on demand. + +### 03 Maintain: Update Pacakge Cache (update-cache.yaml) + +For lessons that have generated content, we use {renv} to ensure that the output +is stable. This is controlled by a single lockfile which documents the packages +needed for the lesson and the version numbers. This workflow is skipped in +lessons that do not have generated content. + +Because the lessons need to remain current with the package ecosystem, it's a +good idea to make sure these packages can be updated periodically. The +update cache workflow will do this by checking for updates, applying them in a +branch called `updates/packages` and creating a pull request with _only the +lockfile changed_. + +From here, the markdown documents will be rebuilt and you can inspect what has +changed based on how the packages have updated. + +## Pull Request and Review Management + +Because our lessons execute code, pull requests are a secruity risk for any +lesson and thus have security measures associted with them. **Do not merge any +pull requests that do not pass checks and do not have bots commented on them.** + +This series of workflows all go together and are described in the following +diagram and the below sections: + +![Graph representation of a pull request](https://carpentries.github.io/sandpaper/articles/img/pr-flow.dot.svg) + +### Pre Flight Pull Request Validation (pr-preflight.yaml) + +This workflow runs every time a pull request is created and its purpose is to +validate that the pull request is okay to run. This means the following things: + +1. The pull request does not contain modified workflow files +2. If the pull request contains modified workflow files, it does not contain + modified content files (such as a situation where @carpentries-bot will + make an automated pull request) +3. The pull request does not contain an invalid commit hash (e.g. from a fork + that was made before a lesson was transitioned from styles to use the + workbench). + +Once the checks are finished, a comment is issued to the pull request, which +will allow maintainers to determine if it is safe to run the +"Receive Pull Request" workflow from new contributors. + +### Recieve Pull Request (pr-recieve.yaml) + +**Note of caution:** This workflow runs arbitrary code by anyone who creates a +pull request. GitHub has safeguarded the token used in this workflow to have no +priviledges in the repository, but we have taken precautions to protect against +spoofing. + +The first step of this workflow is to check if it is valid (e.g. that no +workflow files have been modified). If there are workflow files that have been +modified, a comment is made that indicates that the workflow is not run. If +both a workflow file and lesson content is modified, an error will occurr. + +The second step (if valid) is to build the generated content from the pull +request. This builds the content and uploads three artifacts: + +1. The pull request number (pr) +2. A summary of changes after the rendering process (diff) +3. The rendered files (build) + +Because this workflow builds generated content, it follows the same general +process as the sandpaper-main workflow with the same caching mechanisms. + +The artifacts produced are used by the next workflow. + +### Comment on Pull Request (pr-comment.yaml) + +This workflow is triggered if the `pr-recieve.yaml` workflow is successful. +The steps in this workflow are: + +1. Test if the workflow is valid and comment the validity of the workflow to the + pull request. +2. If it is valid: create an orphan branch with two commits: the current state + of the repository and the proposed changes. +3. If it is valid: update the pull request comment with the summary of changes + +Importantly: if the pull request is invalid, the branch is not created so any +malicious code is not published. + +From here, the maintainer can request changes from the author and eventually +either merge or reject the PR. When this happens, if the PR was valid, the +preview branch needs to be deleted. + +### Send Close PR Signal (pr-close-signal.yaml) + +Triggered any time a pull request is closed. This emits an artifact that is the +pull request number for the next action + +### Remove Pull Request Branch (pr-post-remove-branch.yaml) + +Tiggered by `pr-close-signal.yaml`. This removes the temporary branch associated with +the pull request (if it was created). diff --git a/.github/workflows/pr-close-signal.yaml b/.github/workflows/pr-close-signal.yaml new file mode 100755 index 00000000..9c5a603e --- /dev/null +++ b/.github/workflows/pr-close-signal.yaml @@ -0,0 +1,23 @@ +name: "Bot: Send Close Pull Request Signal" + +on: + pull_request: + types: + [closed] + +jobs: + send-close-signal: + name: "Send closing signal" + runs-on: ubuntu-latest + if: ${{ github.event.action == 'closed' }} + steps: + - name: "Create PRtifact" + run: | + mkdir -p ./pr + printf ${{ github.event.number }} > ./pr/NUM + - name: Upload Diff + uses: actions/upload-artifact@v2 + with: + name: pr + path: ./pr + diff --git a/.github/workflows/pr-comment.yaml b/.github/workflows/pr-comment.yaml new file mode 100755 index 00000000..e5d542e4 --- /dev/null +++ b/.github/workflows/pr-comment.yaml @@ -0,0 +1,173 @@ +name: "Bot: Comment on the Pull Request" + +# read-write repo token +# access to secrets +on: + workflow_run: + workflows: ["Receive Pull Request"] + types: + - completed + +jobs: + # Pull requests are valid if: + # - they match the sha of the workflow run head commit + # - they are open + # - no .github files were committed + test-pr: + name: "Test if pull request is valid" + runs-on: ubuntu-latest + if: > + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' + outputs: + is_valid: ${{ steps.check-pr.outputs.VALID }} + payload: ${{ steps.check-pr.outputs.payload }} + number: ${{ steps.get-pr.outputs.NUM }} + msg: ${{ steps.check-pr.outputs.MSG }} + steps: + - name: 'Download PR artifact' + id: dl + uses: carpentries/actions/download-workflow-artifact@main + with: + run: ${{ github.event.workflow_run.id }} + name: 'pr' + + - name: "Get PR Number" + if: ${{ steps.dl.outputs.success == 'true' }} + id: get-pr + run: | + unzip pr.zip + echo "NUM=$(<./NR)" >> $GITHUB_OUTPUT + + - name: "Fail if PR number was not present" + id: bad-pr + if: ${{ steps.dl.outputs.success != 'true' }} + run: | + echo '::error::A pull request number was not recorded. The pull request that triggered this workflow is likely malicious.' + exit 1 + - name: "Get Invalid Hashes File" + id: hash + run: | + echo "json<> $GITHUB_OUTPUT + - name: "Check PR" + id: check-pr + if: ${{ steps.dl.outputs.success == 'true' }} + uses: carpentries/actions/check-valid-pr@main + with: + pr: ${{ steps.get-pr.outputs.NUM }} + sha: ${{ github.event.workflow_run.head_sha }} + invalid: ${{ fromJSON(steps.hash.outputs.json)[github.repository] }} + fail_on_error: true + + # Create an orphan branch on this repository with two commits + # - the current HEAD of the md-outputs branch + # - the output from running the current HEAD of the pull request through + # the md generator + create-branch: + name: "Create Git Branch" + needs: test-pr + runs-on: ubuntu-latest + if: ${{ needs.test-pr.outputs.is_valid == 'true' }} + env: + NR: ${{ needs.test-pr.outputs.number }} + steps: + - name: 'Checkout md outputs' + uses: actions/checkout@v3 + with: + ref: md-outputs + path: built + fetch-depth: 1 + + - name: 'Download built markdown' + id: dl + uses: carpentries/actions/download-workflow-artifact@main + with: + run: ${{ github.event.workflow_run.id }} + name: 'built' + + - if: ${{ steps.dl.outputs.success == 'true' }} + run: unzip built.zip + + - name: "Create orphan and push" + if: ${{ steps.dl.outputs.success == 'true' }} + run: | + cd built/ + git config --local user.email "actions@github.com" + git config --local user.name "GitHub Actions" + CURR_HEAD=$(git rev-parse HEAD) + git checkout --orphan md-outputs-PR-${NR} + git add -A + git commit -m "source commit: ${CURR_HEAD}" + ls -A | grep -v '^.git$' | xargs rm -r + cd .. + unzip -o -d built built.zip + cd built + git add -A + git commit --allow-empty -m "differences for PR #${NR}" + git push -u --force --set-upstream origin md-outputs-PR-${NR} + + # Comment on the Pull Request with a link to the branch and the diff + comment-pr: + name: "Comment on Pull Request" + needs: [test-pr, create-branch] + runs-on: ubuntu-latest + if: ${{ needs.test-pr.outputs.is_valid == 'true' }} + env: + NR: ${{ needs.test-pr.outputs.number }} + steps: + - name: 'Download comment artifact' + id: dl + uses: carpentries/actions/download-workflow-artifact@main + with: + run: ${{ github.event.workflow_run.id }} + name: 'diff' + + - if: ${{ steps.dl.outputs.success == 'true' }} + run: unzip ${{ github.workspace }}/diff.zip + + - name: "Comment on PR" + id: comment-diff + if: ${{ steps.dl.outputs.success == 'true' }} + uses: carpentries/actions/comment-diff@main + with: + pr: ${{ env.NR }} + path: ${{ github.workspace }}/diff.md + + # Comment if the PR is open and matches the SHA, but the workflow files have + # changed + comment-changed-workflow: + name: "Comment if workflow files have changed" + needs: test-pr + runs-on: ubuntu-latest + if: ${{ always() && needs.test-pr.outputs.is_valid == 'false' }} + env: + NR: ${{ github.event.workflow_run.pull_requests[0].number }} + body: ${{ needs.test-pr.outputs.msg }} + steps: + - name: 'Check for spoofing' + id: dl + uses: carpentries/actions/download-workflow-artifact@main + with: + run: ${{ github.event.workflow_run.id }} + name: 'built' + + - name: 'Alert if spoofed' + id: spoof + if: ${{ steps.dl.outputs.success == 'true' }} + run: | + echo 'body<> $GITHUB_ENV + echo '' >> $GITHUB_ENV + echo '## :x: DANGER :x:' >> $GITHUB_ENV + echo 'This pull request has modified workflows that created output. Close this now.' >> $GITHUB_ENV + echo '' >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV + + - name: "Comment on PR" + id: comment-diff + uses: carpentries/actions/comment-diff@main + with: + pr: ${{ env.NR }} + body: ${{ env.body }} + diff --git a/.github/workflows/pr-post-remove-branch.yaml b/.github/workflows/pr-post-remove-branch.yaml new file mode 100755 index 00000000..338230f8 --- /dev/null +++ b/.github/workflows/pr-post-remove-branch.yaml @@ -0,0 +1,30 @@ +name: "Bot: Remove Temporary PR Branch" + +on: + workflow_run: + workflows: ["Bot: Send Close Pull Request Signal"] + types: + - completed + +jobs: + delete: + name: "Delete branch from Pull Request" + runs-on: ubuntu-latest + if: > + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' + steps: + - name: 'Download artifact' + uses: carpentries/actions/download-workflow-artifact@main + with: + run: ${{ github.event.workflow_run.id }} + name: pr + - name: "Get PR Number" + id: get-pr + run: | + unzip pr.zip + echo "NUM=$(<./NUM)" >> $GITHUB_OUTPUT + - name: 'Remove branch' + uses: carpentries/actions/remove-branch@main + with: + pr: ${{ steps.get-pr.outputs.NUM }} diff --git a/.github/workflows/pr-preflight.yaml b/.github/workflows/pr-preflight.yaml new file mode 100755 index 00000000..496abcd1 --- /dev/null +++ b/.github/workflows/pr-preflight.yaml @@ -0,0 +1,37 @@ +name: "Pull Request Preflight Check" + +on: + pull_request_target: + branches: + ["main"] + types: + ["opened", "synchronize", "reopened"] + +jobs: + test-pr: + name: "Test if pull request is valid" + if: ${{ github.event.action != 'closed' }} + runs-on: ubuntu-latest + outputs: + is_valid: ${{ steps.check-pr.outputs.VALID }} + steps: + - name: "Get Invalid Hashes File" + id: hash + run: | + echo "json<> $GITHUB_OUTPUT + - name: "Check PR" + id: check-pr + uses: carpentries/actions/check-valid-pr@main + with: + pr: ${{ github.event.number }} + invalid: ${{ fromJSON(steps.hash.outputs.json)[github.repository] }} + fail_on_error: true + - name: "Comment result of validation" + id: comment-diff + if: ${{ always() }} + uses: carpentries/actions/comment-diff@main + with: + pr: ${{ github.event.number }} + body: ${{ steps.check-pr.outputs.MSG }} diff --git a/.github/workflows/pr-receive.yaml b/.github/workflows/pr-receive.yaml new file mode 100755 index 00000000..aad7ecbc --- /dev/null +++ b/.github/workflows/pr-receive.yaml @@ -0,0 +1,127 @@ +name: "Receive Pull Request" + +on: + pull_request: + types: + [opened, synchronize, reopened] + +jobs: + test-pr: + name: "Record PR number" + if: ${{ github.event.action != 'closed' }} + runs-on: ubuntu-latest + outputs: + is_valid: ${{ steps.check-pr.outputs.VALID }} + steps: + - name: "Record PR number" + id: record + if: ${{ always() }} + run: | + echo ${{ github.event.number }} > ${{ github.workspace }}/NR # 2022-03-02: artifact name fixed to be NR + - name: "Upload PR number" + id: upload + if: ${{ always() }} + uses: actions/upload-artifact@v2 + with: + name: pr + path: ${{ github.workspace }}/NR + - name: "Get Invalid Hashes File" + id: hash + run: | + echo "json<> $GITHUB_OUTPUT + - name: "echo output" + run: | + echo "${{ steps.hash.outputs.json }}" + - name: "Check PR" + id: check-pr + uses: carpentries/actions/check-valid-pr@main + with: + pr: ${{ github.event.number }} + invalid: ${{ fromJSON(steps.hash.outputs.json)[github.repository] }} + + build-md-source: + name: "Build markdown source files if valid" + needs: test-pr + runs-on: ubuntu-latest + if: ${{ needs.test-pr.outputs.is_valid == 'true' }} + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + RENV_PATHS_ROOT: ~/.local/share/renv/ + CHIVE: ${{ github.workspace }}/site/chive + PR: ${{ github.workspace }}/site/pr + MD: ${{ github.workspace }}/site/built + steps: + - name: "Check Out Main Branch" + uses: actions/checkout@v3 + + - name: "Check Out Staging Branch" + uses: actions/checkout@v3 + with: + ref: md-outputs + path: ${{ env.MD }} + + - name: "Set up R" + uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + install-r: false + + - name: "Set up Pandoc" + uses: r-lib/actions/setup-pandoc@v2 + + - name: "Setup Lesson Engine" + uses: carpentries/actions/setup-sandpaper@main + with: + cache-version: ${{ secrets.CACHE_VERSION }} + + - name: "Setup Package Cache" + uses: carpentries/actions/setup-lesson-deps@main + with: + cache-version: ${{ secrets.CACHE_VERSION }} + + - name: "Validate and Build Markdown" + id: build-site + run: | + sandpaper::package_cache_trigger(TRUE) + sandpaper::validate_lesson(path = '${{ github.workspace }}') + sandpaper:::build_markdown(path = '${{ github.workspace }}', quiet = FALSE) + shell: Rscript {0} + + - name: "Generate Artifacts" + id: generate-artifacts + run: | + sandpaper:::ci_bundle_pr_artifacts( + repo = '${{ github.repository }}', + pr_number = '${{ github.event.number }}', + path_md = '${{ env.MD }}', + path_pr = '${{ env.PR }}', + path_archive = '${{ env.CHIVE }}', + branch = 'md-outputs' + ) + shell: Rscript {0} + + - name: "Upload PR" + uses: actions/upload-artifact@v2 + with: + name: pr + path: ${{ env.PR }} + + - name: "Upload Diff" + uses: actions/upload-artifact@v2 + with: + name: diff + path: ${{ env.CHIVE }} + retention-days: 1 + + - name: "Upload Build" + uses: actions/upload-artifact@v2 + with: + name: built + path: ${{ env.MD }} + retention-days: 1 + + - name: "Teardown" + run: sandpaper::reset_site() + shell: Rscript {0} diff --git a/.github/workflows/sandpaper-main.yaml b/.github/workflows/sandpaper-main.yaml new file mode 100755 index 00000000..e17707ac --- /dev/null +++ b/.github/workflows/sandpaper-main.yaml @@ -0,0 +1,61 @@ +name: "01 Build and Deploy Site" + +on: + push: + branches: + - main + - master + schedule: + - cron: '0 0 * * 2' + workflow_dispatch: + inputs: + name: + description: 'Who triggered this build?' + required: true + default: 'Maintainer (via GitHub)' + reset: + description: 'Reset cached markdown files' + required: false + default: false + type: boolean +jobs: + full-build: + name: "Build Full Site" + runs-on: ubuntu-latest + permissions: + checks: write + contents: write + pages: write + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + RENV_PATHS_ROOT: ~/.local/share/renv/ + steps: + + - name: "Checkout Lesson" + uses: actions/checkout@v3 + + - name: "Set up R" + uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + install-r: false + + - name: "Set up Pandoc" + uses: r-lib/actions/setup-pandoc@v2 + + - name: "Setup Lesson Engine" + uses: carpentries/actions/setup-sandpaper@main + with: + cache-version: ${{ secrets.CACHE_VERSION }} + + - name: "Setup Package Cache" + uses: carpentries/actions/setup-lesson-deps@main + with: + cache-version: ${{ secrets.CACHE_VERSION }} + + - name: "Deploy Site" + run: | + reset <- "${{ github.event.inputs.reset }}" == "true" + sandpaper::package_cache_trigger(TRUE) + sandpaper:::ci_deploy(reset = reset) + shell: Rscript {0} diff --git a/.github/workflows/sandpaper-version.txt b/.github/workflows/sandpaper-version.txt new file mode 100644 index 00000000..1a46c7f1 --- /dev/null +++ b/.github/workflows/sandpaper-version.txt @@ -0,0 +1 @@ +0.10.8 diff --git a/.github/workflows/update-cache.yaml b/.github/workflows/update-cache.yaml new file mode 100755 index 00000000..69eb2c6d --- /dev/null +++ b/.github/workflows/update-cache.yaml @@ -0,0 +1,125 @@ +name: "03 Maintain: Update Package Cache" + +on: + workflow_dispatch: + inputs: + name: + description: 'Who triggered this build (enter github username to tag yourself)?' + required: true + default: 'monthly run' + schedule: + # Run every tuesday + - cron: '0 0 * * 2' + +jobs: + preflight: + name: "Preflight Check" + runs-on: ubuntu-latest + outputs: + ok: ${{ steps.check.outputs.ok }} + steps: + - id: check + run: | + if [[ ${{ github.event_name }} == 'workflow_dispatch' ]]; then + echo "ok=true" >> $GITHUB_OUTPUT + echo "Running on request" + # using single brackets here to avoid 08 being interpreted as octal + # https://github.com/carpentries/sandpaper/issues/250 + elif [ `date +%d` -le 7 ]; then + # If the Tuesday lands in the first week of the month, run it + echo "ok=true" >> $GITHUB_OUTPUT + echo "Running on schedule" + else + echo "ok=false" >> $GITHUB_OUTPUT + echo "Not Running Today" + fi + + check_renv: + name: "Check if We Need {renv}" + runs-on: ubuntu-latest + needs: preflight + if: ${{ needs.preflight.outputs.ok == 'true'}} + outputs: + needed: ${{ steps.renv.outputs.exists }} + steps: + - name: "Checkout Lesson" + uses: actions/checkout@v3 + - id: renv + run: | + if [[ -d renv ]]; then + echo "exists=true" >> $GITHUB_OUTPUT + fi + + check_token: + name: "Check SANDPAPER_WORKFLOW token" + runs-on: ubuntu-latest + needs: check_renv + if: ${{ needs.check_renv.outputs.needed == 'true' }} + outputs: + workflow: ${{ steps.validate.outputs.wf }} + repo: ${{ steps.validate.outputs.repo }} + steps: + - name: "validate token" + id: validate + uses: carpentries/actions/check-valid-credentials@main + with: + token: ${{ secrets.SANDPAPER_WORKFLOW }} + + update_cache: + name: "Update Package Cache" + needs: check_token + if: ${{ needs.check_token.outputs.repo== 'true' }} + runs-on: ubuntu-latest + env: + GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} + RENV_PATHS_ROOT: ~/.local/share/renv/ + steps: + + - name: "Checkout Lesson" + uses: actions/checkout@v3 + + - name: "Set up R" + uses: r-lib/actions/setup-r@v2 + with: + use-public-rspm: true + install-r: false + + - name: "Update {renv} deps and determine if a PR is needed" + id: update + uses: carpentries/actions/update-lockfile@main + with: + cache-version: ${{ secrets.CACHE_VERSION }} + + - name: Create Pull Request + id: cpr + if: ${{ steps.update.outputs.n > 0 }} + uses: peter-evans/create-pull-request@v4.2.0 + with: + token: ${{ secrets.SANDPAPER_WORKFLOW }} + delete-branch: true + branch: "update/packages" + commit-message: "[actions] update ${{ steps.update.outputs.n }} packages" + title: "Update ${{ steps.update.outputs.n }} packages" + body: | + :robot: This is an automated build + + This will update ${{ steps.update.outputs.n }} packages in your lesson with the following versions: + + ``` + ${{ steps.update.outputs.report }} + ``` + + :stopwatch: In a few minutes, a comment will appear that will show you how the output has changed based on these updates. + + If you want to inspect these changes locally, you can use the following code to check out a new branch: + + ```bash + git fetch origin update/packages + git checkout update/packages + ``` + + - Auto-generated by [create-pull-request][1] on ${{ steps.update.outputs.date }} + + [1]: https://github.com/peter-evans/create-pull-request + labels: "type: package cache" + draft: false diff --git a/.github/workflows/update-workflows.yaml b/.github/workflows/update-workflows.yaml new file mode 100755 index 00000000..8f2a4b10 --- /dev/null +++ b/.github/workflows/update-workflows.yaml @@ -0,0 +1,66 @@ +name: "02 Maintain: Update Workflow Files" + +on: + workflow_dispatch: + inputs: + name: + description: 'Who triggered this build (enter github username to tag yourself)?' + required: true + default: 'weekly run' + clean: + description: 'Workflow files/file extensions to clean (no wildcards, enter "" for none)' + required: false + default: '.yaml' + schedule: + # Run every Tuesday + - cron: '0 0 * * 2' + +jobs: + check_token: + name: "Check SANDPAPER_WORKFLOW token" + runs-on: ubuntu-latest + outputs: + workflow: ${{ steps.validate.outputs.wf }} + repo: ${{ steps.validate.outputs.repo }} + steps: + - name: "validate token" + id: validate + uses: carpentries/actions/check-valid-credentials@main + with: + token: ${{ secrets.SANDPAPER_WORKFLOW }} + + update_workflow: + name: "Update Workflow" + runs-on: ubuntu-latest + needs: check_token + if: ${{ needs.check_token.outputs.workflow == 'true' }} + steps: + - name: "Checkout Repository" + uses: actions/checkout@v3 + + - name: Update Workflows + id: update + uses: carpentries/actions/update-workflows@main + with: + clean: ${{ github.event.inputs.clean }} + + - name: Create Pull Request + id: cpr + if: "${{ steps.update.outputs.new }}" + uses: peter-evans/create-pull-request@v4.2.0 + with: + token: ${{ secrets.SANDPAPER_WORKFLOW }} + delete-branch: true + branch: "update/workflows" + commit-message: "[actions] update sandpaper workflow to version ${{ steps.update.outputs.new }}" + title: "Update Workflows to Version ${{ steps.update.outputs.new }}" + body: | + :robot: This is an automated build + + Update Workflows from sandpaper version ${{ steps.update.outputs.old }} -> ${{ steps.update.outputs.new }} + + - Auto-generated by [create-pull-request][1] on ${{ steps.update.outputs.date }} + + [1]: https://github.com/peter-evans/create-pull-request + labels: "type: template and tools" + draft: false diff --git a/.github/workflows/workbench-beta-phase.yml b/.github/workflows/workbench-beta-phase.yml new file mode 100644 index 00000000..2faa25d9 --- /dev/null +++ b/.github/workflows/workbench-beta-phase.yml @@ -0,0 +1,60 @@ +name: "Deploy to AWS" + +on: + workflow_run: + workflows: ["01 Build and Deploy Site"] + types: + - completed + workflow_dispatch: + +jobs: + preflight: + name: "Preflight Check" + runs-on: ubuntu-latest + outputs: + ok: ${{ steps.check.outputs.ok }} + folder: ${{ steps.check.outputs.folder }} + steps: + - id: check + run: | + if [[ -z "${{ secrets.DISTRIBUTION }}" || -z "${{ secrets.AWS_ACCESS_KEY_ID }}" || -z "${{ secrets.AWS_SECRET_ACCESS_KEY }}" ]]; then + echo ":information_source: No site configured" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo 'To deploy the preview on AWS, you need the `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY` and `DISTRIBUTION` secrets set up' >> $GITHUB_STEP_SUMMARY + else + echo "::set-output name=folder::"$(sed -E 's^.+/(.+)^\1^' <<< ${{ github.repository }}) + echo "::set-output name=ok::true" + fi + + full-build: + name: "Deploy to AWS" + needs: [preflight] + if: ${{ needs.preflight.outputs.ok }} + runs-on: ubuntu-latest + steps: + + - name: "Checkout site folder" + uses: actions/checkout@v3 + with: + ref: 'gh-pages' + path: 'source' + + - name: "Deploy to Bucket" + uses: jakejarvis/s3-sync-action@v0.5.1 + with: + args: --acl public-read --follow-symlinks --delete --exclude '.git/*' + env: + AWS_S3_BUCKET: preview.carpentries.org + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + SOURCE_DIR: 'source' + DEST_DIR: ${{ needs.preflight.outputs.folder }} + + - name: "Invalidate CloudFront" + uses: chetan/invalidate-cloudfront-action@master + env: + PATHS: /* + AWS_REGION: 'us-east-1' + DISTRIBUTION: ${{ secrets.DISTRIBUTION }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..b8ab7062 --- /dev/null +++ b/.gitignore @@ -0,0 +1,55 @@ +# sandpaper files +episodes/*html +site/* +!site/README.md + +# History files +.Rhistory +.Rapp.history +# Session Data files +.RData +# User-specific files +.Ruserdata +# Example code in package build process +*-Ex.R +# Output files from R CMD build +/*.tar.gz +# Output files from R CMD check +/*.Rcheck/ +# RStudio files +.Rproj.user/ +# produced vignettes +vignettes/*.html +vignettes/*.pdf +# OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 +.httr-oauth +# knitr and R markdown default cache directories +*_cache/ +/cache/ +# Temporary files created by R markdown +*.utf8.md +*.knit.md +# R Environment Variables +.Renviron +# pkgdown site +docs/ +# translation temp files +po/*~ +# renv detritus +renv/sandbox/ +*.pyc +*~ +.DS_Store +.ipynb_checkpoints +.sass-cache +.jekyll-cache/ +.jekyll-metadata +__pycache__ +_site +.Rproj.user +.bundle/ +.vendor/ +vendor/ +.docker-vendor/ +Gemfile.lock +.*history diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..f19b8049 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,13 @@ +--- +title: "Contributor Code of Conduct" +--- + +As contributors and maintainers of this project, +we pledge to follow the [The Carpentries Code of Conduct][coc]. + +Instances of abusive, harassing, or otherwise unacceptable behavior +may be reported by following our [reporting guidelines][coc-reporting]. + + +[coc-reporting]: https://docs.carpentries.org/topic_folders/policies/incident-reporting.html +[coc]: https://docs.carpentries.org/topic_folders/policies/code-of-conduct.html diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..de2e4e35 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,151 @@ +# Contributing + +[Software Carpentry][swc-site] and [Data Carpentry][dc-site] are open source projects, +and we welcome contributions of all kinds: +new lessons, +fixes to existing material, +bug reports, +and reviews of proposed changes are all welcome. + +## Contributor Agreement + +By contributing, +you agree that we may redistribute your work under [our license](LICENSE.md). +In exchange, +we will address your issues and/or assess your change proposal as promptly as we can, +and help you become a member of our community. +Everyone involved in [Software Carpentry][swc-site] and [Data Carpentry][dc-site] +agrees to abide by our [code of conduct](CONDUCT.md). + +## How to Contribute + +The easiest way to get started is to file an issue +to tell us about a spelling mistake, +some awkward wording, +or a factual error. +This is a good way to introduce yourself +and to meet some of our community members. + +1. If you do not have a [GitHub][github] account, + you can [send us comments by email][contact]. + However, + we will be able to respond more quickly if you use one of the other methods described below. + +2. If you have a [GitHub][github] account, + or are willing to [create one][github-join], + but do not know how to use Git, + you can report problems or suggest improvements by [creating an issue][issues]. + This allows us to assign the item to someone + and to respond to it in a threaded discussion. + +3. If you are comfortable with Git, + and would like to add or change material, + you can submit a pull request (PR). + Instructions for doing this are [included below](#using-github). + +## Where to Contribute + +1. If you wish to change this lesson, + please work in , + which can be viewed at . + +2. If you wish to change the example lesson, + please work in , + which documents the format of our lessons + and can be viewed at . + +3. If you wish to change the template used for workshop websites, + please work in . + The home page of that repository explains how to set up workshop websites, + while the extra pages in + provide more background on our design choices. + +4. If you wish to change CSS style files, tools, + or HTML boilerplate for lessons or workshops stored in `_includes` or `_layouts`, + please work in . + +## What to Contribute + +There are many ways to contribute, +from writing new exercises and improving existing ones +to updating or filling in the documentation +and submitting [bug reports][issues] +about things that don't work, aren't clear, or are missing. +If you are looking for ideas, +please see [the list of issues for this repository][issues], +or the issues for [Data Carpentry][dc-issues] +and [Software Carpentry][swc-issues] projects. + +Comments on issues and reviews of pull requests are just as welcome: +we are smarter together than we are on our own. +Reviews from novices and newcomers are particularly valuable: +it's easy for people who have been using these lessons for a while +to forget how impenetrable some of this material can be, +so fresh eyes are always welcome. + +## What *Not* to Contribute + +Our lessons already contain more material than we can cover in a typical workshop, +so we are usually *not* looking for more concepts or tools to add to them. +As a rule, +if you want to introduce a new idea, +you must (a) estimate how long it will take to teach +and (b) explain what you would take out to make room for it. +The first encourages contributors to be honest about requirements; +the second, to think hard about priorities. + +We are also not looking for exercises or other material that only run on one platform. +Our workshops typically contain a mixture of Windows, macOS, and Linux users; +in order to be usable, +our lessons must run equally well on all three. + +## Using GitHub + +If you choose to contribute via GitHub, +you may want to look at +[How to Contribute to an Open Source Project on GitHub][how-contribute]. +In brief: + +1. The published copy of the lesson is in the `gh-pages` branch of the repository + (so that GitHub will regenerate it automatically). + Please create all branches from that, + and merge the [master repository][repo]'s `gh-pages` branch into your `gh-pages` branch + before starting work. + Please do *not* work directly in your `gh-pages` branch, + since that will make it difficult for you to work on other contributions. + +2. We use [GitHub flow][github-flow] to manage changes: + 1. Create a new branch in your desktop copy of this repository for each significant change. + 2. Commit the change in that branch. + 3. Push that branch to your fork of this repository on GitHub. + 4. Submit a pull request from that branch to the [master repository][repo]. + 5. If you receive feedback, + make changes on your desktop and push to your branch on GitHub: + the pull request will update automatically. + +Each lesson has two maintainers who review issues and pull requests +or encourage others to do so. +The maintainers are community volunteers, +and have final say over what gets merged into the lesson. + +## Other Resources + +General discussion of [Software Carpentry][swc-site] and [Data Carpentry][dc-site] +happens on the [discussion mailing list][discuss-list], +which everyone is welcome to join. +You can also [reach us by email][contact]. + +[contact]: mailto:admin@software-carpentry.org +[dc-issues]: https://github.com/issues?q=user%3Adatacarpentry +[dc-lessons]: http://datacarpentry.org/lessons/ +[dc-site]: http://datacarpentry.org/ +[discuss-list]: http://lists.software-carpentry.org/listinfo/discuss +[github]: http://github.com +[github-flow]: https://guides.github.com/introduction/flow/ +[github-join]: https://github.com/join +[how-contribute]: https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github +[issues]: https://github.com/swcarpentry/shell-novice/issues/ +[repo]: https://github.com/swcarpentry/shell-novice/ +[swc-issues]: https://github.com/issues?q=user%3Aswcarpentry +[swc-lessons]: http://software-carpentry.org/lessons/ +[swc-site]: http://software-carpentry.org/ diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 00000000..b6f5f2ce --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,82 @@ +--- +title: "Licenses" +--- + +## Instructional Material + +All Software Carpentry, Data Carpentry, and Library Carpentry instructional material is +made available under the [Creative Commons Attribution +license][cc-by-human]. The following is a human-readable summary of +(and not a substitute for) the [full legal text of the CC BY 4.0 +license][cc-by-legal]. + +You are free: + +* to **Share**---copy and redistribute the material in any medium or format +* to **Adapt**---remix, transform, and build upon the material + +for any purpose, even commercially. + +The licensor cannot revoke these freedoms as long as you follow the +license terms. + +Under the following terms: + +* **Attribution**---You must give appropriate credit (mentioning that + your work is derived from work that is Copyright © Software + Carpentry and, where practical, linking to + http://software-carpentry.org/), provide a [link to the + license][cc-by-human], and indicate if changes were made. You may do + so in any reasonable manner, but not in any way that suggests the + licensor endorses you or your use. + +**No additional restrictions**---You may not apply legal terms or +technological measures that legally restrict others from doing +anything the license permits. With the understanding that: + +Notices: + +* You do not have to comply with the license for elements of the + material in the public domain or where your use is permitted by an + applicable exception or limitation. +* No warranties are given. The license may not give you all of the + permissions necessary for your intended use. For example, other + rights such as publicity, privacy, or moral rights may limit how you + use the material. + +## Software + +Except where otherwise noted, the example programs and other software +provided by Software Carpentry and Data Carpentry are made available under the +[OSI][osi]-approved +[MIT license][mit-license]. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +## Trademark + +"Software Carpentry" and "Data Carpentry" and their respective logos +are registered trademarks of [Community Initiatives][ci]. + +[cc-by-human]: https://creativecommons.org/licenses/by/4.0/ +[cc-by-legal]: https://creativecommons.org/licenses/by/4.0/legalcode +[mit-license]: https://opensource.org/licenses/mit-license.html +[ci]: http://communityin.org/ +[osi]: https://opensource.org diff --git a/README.md b/README.md index 6d08f6aa..1e7acbb1 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,25 @@ +> **ATTENTION** This is an experimental test of [The Carpentries Workbench](https://carpentries.github.io/workbench) lesson infrastructure. +> It was automatically converted from the source lesson via [the lesson transition script](https://github.com/carpentries/lesson-transition/). +> +> If anything seems off, please contact Zhian Kamvar [zkamvar@carpentries.org](mailto:zkamvar@carpentries.org) + # Building Websites with Jekyll and GitHub/GitLab [![Gitpod ready-to-code](https://img.shields.io/badge/Gitpod-ready--to--code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/carpentries-incubator/jekyll-pages-novice) [![DOI](https://zenodo.org/badge/268807168.svg)](https://zenodo.org/badge/latestdoi/268807168) - This lesson teaches the basics of creating, configuring, and updating a static website with GitHub Pages and Jekyll. The lesson is aimed at researchers and research software engineers who understand what a variable is and are familiar with the GitHub web interface. [Read more about the target audience and learning objectives on the lesson homepage](https://carpentries-incubator.github.io/jekyll-pages-novice/index.html). -## Development Status & Contributing +## Development Status \& Contributing The lesson is currently **open for beta testing**. If you would like to teach this lesson to your local audience, please get in touch with the lesson developers by -[opening a new issue on the lesson repository](https://github.com/carpentries-incubator/jekyll-pages-novice/issues/new) and adding a label `pilot` +[opening a new issue on the lesson repository](https://github.com/carpentries-incubator/jekyll-pages-novice/issues/new) and adding a label `pilot` or posting to the [`#jekyll-pages-lesson` Slack channel](https://swcarpentry.slack.com/archives/C0186GK56UC) -on [The Carpentries Slack](https://swc-slack-invite.herokuapp.com/). You can also let +on [The Carpentries Slack](https://swc-slack-invite.herokuapp.com/). You can also let The Carpentries know by submitting your workshop via the [The Carpentries Incubator website](https://carpentries-incubator.org/#workshops). We would love to help you prepare to teach the lesson and receive feedback on how it could be further improved, @@ -31,11 +35,11 @@ If you'd like to ask the maintainers anything, we'd love to hear from you! You c Current maintainers of this lesson are: -* [Renato Alves](https://github.com/unode) -* [Anne Fouilloux](https://github.com/annefou) -* [Toby Hodges](https://github.com/tobyhodges) -* [Aleksandra Nenadic](https://github.com/anenadic) -* [Sarah Stevens](https://github.com/sstevens2) +- [Renato Alves](https://github.com/unode) +- [Anne Fouilloux](https://github.com/annefou) +- [Toby Hodges](https://github.com/tobyhodges) +- [Aleksandra Nenadic](https://github.com/anenadic) +- [Sarah Stevens](https://github.com/sstevens2) ## Authors @@ -47,4 +51,4 @@ Please check the [contributing guidelines](CONTRIBUTING) if you would like to co To cite this lesson, please consult with [CITATION](CITATION). -[lesson-example]: https://carpentries.github.io/lesson-example + diff --git a/config.yaml b/config.yaml new file mode 100644 index 00000000..317305da --- /dev/null +++ b/config.yaml @@ -0,0 +1,88 @@ +#------------------------------------------------------------ +# Values for this lesson. +#------------------------------------------------------------ + +# Which carpentry is this (swc, dc, lc, or cp)? +# swc: Software Carpentry +# dc: Data Carpentry +# lc: Library Carpentry +# cp: Carpentries (to use for instructor training for instance) +# incubator: The Carpentries Incubator +carpentry: 'incubator' + +# Overall title for pages. +title: 'Building Websites With Jekyll and GitHub' + +# Date the lesson was created (YYYY-MM-DD, this is empty by default) +created: ~ + +# Comma-separated list of keywords for the lesson +keywords: 'software, data, lesson, The Carpentries' + +# Life cycle stage of the lesson +# possible values: pre-alpha, alpha, beta, stable +life_cycle: 'beta' + +# License of the lesson +license: 'CC-BY 4.0' + +# Link to the source repository for this lesson +source: 'https://github.com/fishtree-attempt/jekyll-pages-novice/' + +# Default branch of your lesson +branch: 'main' + +# Who to contact if there are any issues +contact: 'tobyhodges@carpentries.org' + +# Navigation ------------------------------------------------ +# +# Use the following menu items to specify the order of +# individual pages in each dropdown section. Leave blank to +# include all pages in the folder. +# +# Example ------------- +# +# episodes: +# - introduction.md +# - first-steps.md +# +# learners: +# - setup.md +# +# instructors: +# - instructor-notes.md +# +# profiles: +# - one-learner.md +# - another-learner.md + +# Order of episodes in your lesson +episodes: +- introduction.md +- markdown.md +- github-pages.md +- starting-jekyll.md +- includes.md +- layouts.md +- filters.md +- arrays.md +- wrap-up.md + +# Information for Learners +learners: + +# Information for Instructors +instructors: + +# Learner Profiles +profiles: + +# Customisation --------------------------------------------- +# +# This space below is where custom yaml items (e.g. pinning +# sandpaper and varnish versions) should live + + +url: https://preview.carpentries.org/jekyll-pages-novice +workbench-beta: 'true' diff --git a/episodes/arrays.md b/episodes/arrays.md index 63714bdd..63e8da73 100644 --- a/episodes/arrays.md +++ b/episodes/arrays.md @@ -1,22 +1,26 @@ --- -title: "Loops and Collections" +title: Loops and Collections teaching: 60 exercises: 20 -questions: -- "How do I work with variables containing multiple values in Jekyll?" -- "How do I add a list of blog posts to my site?" -- "How do I filter a list of values?" -objectives: -- "Define list and dictionary variables and extract values from those variables." -- "Configure a collection of pages within a site." -- "Create and automatically populate a list of pages in that collection." -keypoints: -- "Iterate over multiple values in a list with a for loop." -- "Collections are defined in a site's global configuration and populated in a corresponding folder." -- "Collections are presented by Jekyll as a list of page objects." --- -{% include base_path.html %} + + +::::::::::::::::::::::::::::::::::::::: objectives + +- Define list and dictionary variables and extract values from those variables. +- Configure a collection of pages within a site. +- Create and automatically populate a list of pages in that collection. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: questions + +- How do I work with variables containing multiple values in Jekyll? +- How do I add a list of blog posts to my site? +- How do I filter a list of values? + +:::::::::::::::::::::::::::::::::::::::::::::::::: Now we have learned how to substitute and format values stored in variables into pages on our site, how to include and re-use entire blocks of content, @@ -29,15 +33,14 @@ for a group website, we may wish to do something similar with research projects or profile pages for individual team members. Using what we already know about Markdown, -we _could_ write these lists by ourselves. +we *could* write these lists by ourselves. But this would be time-consuming and inefficient: we would have to manually adjust these listings every time we write a new post/start a new project/welcome a new team member to the group. Instead, we will learn about two more features of Jekyll, -_for loops_ and _collections_, +*for loops* and *collections*, which can be used to populate and update lists within pages automatically. - ## List Parameters and For Loops In addition to the single-value variable types we are already familiar with, @@ -49,7 +52,7 @@ and make use of this information throughout the website. To do so in YAML notation would look like this: -~~~ +```yaml team_members: - name: "Sarah Becker" @@ -63,8 +66,7 @@ team_members: name: "Albert Hamilton" role: editor start_date: "2017-12-01" -~~~ -{: .language-yaml} +``` This defines `team_members` as a list of 3 elements; each element is a dictionary with key-value pairs for name, role and date. @@ -77,116 +79,118 @@ The keys - `name`, `role`, and `start_date` - are identical for all entries in the list but the values differ from one team member to the next. -> ## YAML Syntax Is Flexible -> When browsing documentation and examples of YAML -> you will sometimes see lists represented slightly differently, -> with the first part of the entry value written on the same line -> as the `-`, e.g. -> -> ~~~ -> team_members: -> - name: "Sarah Becker" -> role: "project lead" -> start_date: "2016-02-01" -> - name: "Jane Smith" -> role: maintainer -> start_date: "2018-03-15" -> - name: "Albert Hamilton" -> role: editor -> start_date: "2017-12-01" -> ~~~ -> {: .language-yaml} -> -> This is also valid syntax and a little more compact, -> but we will place `-` on its own line in this lesson as -> [that syntax is described in the official YAML specification][yaml-lists]. -> -{: .callout } - -> ## Indentation in YAML -> Note that indentation level in YAML is important - -> it can be a cause of some not-so-obvious mistakes. -> Use online YAML code validators, -> such as [YAML Lint](http://www.yamllint.com/), -> to make sure your YAML is correctly formatted. -> -{: .callout} +:::::::::::::::::::::::::::::::::::::::: callout + +## YAML Syntax Is Flexible + +When browsing documentation and examples of YAML +you will sometimes see lists represented slightly differently, +with the first part of the entry value written on the same line +as the `-`, e.g. + +```yaml +team_members: + - name: "Sarah Becker" + role: "project lead" + start_date: "2016-02-01" + - name: "Jane Smith" + role: maintainer + start_date: "2018-03-15" + - name: "Albert Hamilton" + role: editor + start_date: "2017-12-01" +``` + +This is also valid syntax and a little more compact, +but we will place `-` on its own line in this lesson as +[that syntax is described in the official YAML specification][yaml-lists]. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::::: callout + +## Indentation in YAML + +Note that indentation level in YAML is important - +it can be a cause of some not-so-obvious mistakes. +Use online YAML code validators, +such as [YAML Lint](https://www.yamllint.com/), +to make sure your YAML is correctly formatted. + +:::::::::::::::::::::::::::::::::::::::::::::::::: Now that the `site.team_members` variable has been defined, we can insert it into any page on our site exactly as we have done before. -However, with list variables such as this, it is often preferable to _iterate_ +However, with list variables such as this, it is often preferable to *iterate* through the values so that we can handle and display each one individually. To do so we need a for loop, inside which we can define what we want to do to to each of the list's values. In Liquid syntax, loops are created by surrounding the loop body in `for`/`endfor` tags as: -~~~ +```source {% raw %}{% for thing in list %} [ This is the loop body. Do something with the "thing" variable here. ] {% endfor %}{% endraw %} -~~~ -{: .source } +``` Let's use a loop to access the information about the team and display it in `about.md`. 1. Modify `_config.yml` file and add the `team_members` parameter as defined above. The file should now look like: - - ~~~ - description: "This is an example website built while learning how to use Jekyll and GitHub Pages." - email: "team@carpentries.org" - twitter: "https://twitter.com/thecarpentries" - team_members: - - - name: "Sarah Becker" - role: "project lead" - start_date: "2016-02-01" - - - name: "Jane Smith" - role: maintainer - start_date: "2018-03-15" - - - name: "Albert Hamilton" - role: editor - start_date: "2017-12-01" - ~~~ - {: .language-yaml} + + ```yaml + description: "This is an example website built while learning how to use Jekyll and GitHub Pages." + email: "team@carpentries.org" + twitter: "https://twitter.com/thecarpentries" + team_members: + - + name: "Sarah Becker" + role: "project lead" + start_date: "2016-02-01" + - + name: "Jane Smith" + role: maintainer + start_date: "2018-03-15" + - + name: "Albert Hamilton" + role: editor + start_date: "2017-12-01" + ``` 2. In file `about.md`, add a new section for the team and - iterate over the values defined in parameter `site.team_members` in a loop to - display a table of the team members' names and roles. - The file now should look like: - - ~~~ - {% raw %}--- - layout: page - title: About - --- - - ## Project - - {{ site.description }} - - ## Funders - We gratefully acknowledge funding from the XYZ Founding Council, under grant number 'abc'. - - ## Team - - The following people are members of our research team: - {% for team_member in site.team_members %} - - {{ team_member.name }}, role: {{ team_member.role }} - {% endfor %} - - ## Cite us - - You can cite the project as: - - > *The Carpentries 2019 Annual Report. Zenodo. https://doi.org/10.5281/zenodo.3840372* - {% endraw %} - ~~~ - {: .language-markdown} - -![Rendered team members list in the 'about.md' page](../fig/team_members_list.png){: .image-with-shadow width="800px" } + iterate over the values defined in parameter `site.team_members` in a loop to + display a table of the team members' names and roles. + The file now should look like: + + ```markdown + {% raw %}--- + layout: page + title: About + --- + + ## Project + + {{ site.description }} + + ## Funders + We gratefully acknowledge funding from the XYZ Founding Council, under grant number 'abc'. + + ## Team + + The following people are members of our research team: + {% for team_member in site.team_members %} + - {{ team_member.name }}, role: {{ team_member.role }} + {% endfor %} + + ## Cite us + + You can cite the project as: + + > *The Carpentries 2019 Annual Report. Zenodo. https://doi.org/10.5281/zenodo.3840372* + {% endraw %} + ``` + +![](fig/team_members_list.png){alt="Rendered team members list in the 'about.md' page" .image-with-shadow width="800px" } ## Filtering a List @@ -199,10 +203,9 @@ that fulfil the criteria provided. For example, to filter only the project leads from the `team_members` list, we would write the filter like this: -~~~ +```source {% raw %}{{ site.team_members | where:"role", "project lead" }}{% endraw %} -~~~ -{: .source } +``` `where` returns a list, but we expect there will be only one lead defined for each project, @@ -210,10 +213,9 @@ and in such cases the best way to access this single value from the filtered list is with another filter, `first`. This filter returns the first entry in whichever list it is called on: -~~~ +```source {% raw %}{{ site.team_members | where:"role", "project lead" | first }}{% endraw %} -~~~ -{: .source } +``` ## Assigning Variables Within a Page @@ -224,11 +226,10 @@ but Liquid provides a way for us to create a new variable from the value returned by those filters. For this, we use the `assign` tag, e.g. -~~~ +```source {% raw %}{% assign lead = site.team_members | where:"role", "project lead" | first %} {{ lead.name }}{% endraw %} -~~~ -{: .source } +``` Use this `assign` tag whenever you need to create variables for use "on the fly" as you work with lists in your site. @@ -236,58 +237,68 @@ We will see another example of this when we investigate collections in the next section. 3. In file `index.md` add the team lead's name: + + ```markdown + # {% raw %}Building Websites in GitHub + + ## Description + {{ site.description }} + {% assign lead = site.team_members | where:"role", "project lead" | first %} + The project is led by {{ lead.name }}. + [See our full team](about#team) + + Have any questions about what we do? [We'd love to hear from you!](mailto:{{ site.email }}{% endraw %}) + ``` - ~~~ - # {% raw %}Building Websites in GitHub +Now, if we need to add, remove, or modify a team member, +we only need to update the list in `_config.yml` without editing the individual pages of our site. - ## Description - {{ site.description }} - {% assign lead = site.team_members | where:"role", "project lead" | first %} - The project is led by {{ lead.name }}. - [See our full team](about#team) +::::::::::::::::::::::::::::::::::::::: challenge - Have any questions about what we do? [We'd love to hear from you!](mailto:{{ site.email }}{% endraw %}) - ~~~ - {: .language-markdown} +## Exercise: Personnel Changes -Now, if we need to add, remove, or modify a team member, -we only need to update the list in `_config.yml` without editing the individual pages of our site. +Your project team has changed. The team lead has left and in her place is a new person: 'Tom Cat', who started on +'2020-10-01'. In addition, the team was expanded and a new developer called 'Alice Dauncey' joined on '2020-09-15'. +Update your website to reflect these team changes. + +::::::::::::::: solution + +## Solution + +Luckily, we keep all our global settings in `_config.yml` so all we have to do is update the values there. This saved us some work as for the team lead we would otherwise have to modify both `index.md` and `about.md`. + +For the new developer joining the team, we also only need to her information to `team_members` in `_config.yml` and our `for loop` from `about.md` will simply pick up the changes automatically. Magic! Our `_config.yml` file should now look like: + +```yaml +description: "This is an example website built while learning how to use Jekyll and GitHub Pages." +email: "team@carpentries.org" +twitter: "https://twitter.com/thecarpentries" +team_members: + - + name: "Tom Cat" + role: "project lead" + start_date: "2020-10-01" + - + name: "Jane Smith" + role: maintainer + start_date: "2018-03-15" + - + name: "Albert Hamilton" + role: editor + start_date: "2017-12-01" + - + name: "Alice Dauncey" + role: "developer" + start_date: "2020-09-15" +``` -> ## Exercise: Personnel Changes -> Your project team has changed. The team lead has left and in her place is a new person: 'Tom Cat', who started on -> '2020-10-01'. In addition, the team was expanded and a new developer called 'Alice Dauncey' joined on '2020-09-15'. -> Update your website to reflect these team changes. -> > ## Solution -> > Luckily, we keep all our global settings in `_config.yml` so all we have to do is update the values there. This saved us some work as for the team lead we would otherwise have to modify both `index.md` and `about.md`. -> > -> > For the new developer joining the team, we also only need to her information to `team_members` in `_config.yml` and our `for loop` from `about.md` will simply pick up the changes automatically. Magic! Our `_config.yml` file should now look like: -> > -> > ~~~ -> > description: "This is an example website built while learning how to use Jekyll and GitHub Pages." -> > email: "team@carpentries.org" -> > twitter: "https://twitter.com/thecarpentries" -> > team_members: -> > - -> > name: "Tom Cat" -> > role: "project lead" -> > start_date: "2020-10-01" -> > - -> > name: "Jane Smith" -> > role: maintainer -> > start_date: "2018-03-15" -> > - -> > name: "Albert Hamilton" -> > role: editor -> > start_date: "2017-12-01" -> > - -> > name: "Alice Dauncey" -> > role: "developer" -> > start_date: "2020-09-15" -> > ~~~ -> > {: .language-yaml} -> > Check the changes in your website. -> {: .solution} -{: .challenge} +Check the changes in your website. + + + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: ## Introducing Collections @@ -298,14 +309,14 @@ filters, and the global configuration of our site, to create a blog feed that automatically updates whenever we create a new post. -In [the _Working with Filters_ episode]({{ relative_root_path }}/filters/) we +In [the *Working with Filters* episode]({{ relative\_root\_path }}/filters/) we created a few blog posts, and would now like to display a list of these posts on a new page of the site. For this to work, we must tell Jekyll that the source files for these posts are related to each other i.e. that they all belong within a category, blog posts, that the other pages we have made so far do not. -The mechanism Jekyll provides to do this is called a _collection_: +The mechanism Jekyll provides to do this is called a *collection*: a defined set of files that should be accessible as a set. Once we have defined this collection of blog posts, it will be accessible to us as a list variable, @@ -318,15 +329,14 @@ First, we must tell Jekyll about the collection by adding a new block to the global configuration of the site. In `_config.yml`, we add the following lines: -~~~ +```yaml collections: blogposts: output: true -~~~ -{: .language-yaml } +``` Unlike the list of values we created for `team_members`, -the `collections` configuration is a [_nested mapping_][yaml-lists]: +the `collections` configuration is a [*nested mapping*][yaml-lists]: a set of key-value pairs where some of the values are themselves a set of key-value pairs. @@ -355,59 +365,62 @@ Once we have done that, we can check that the collection has been created correctly by trying to use it in a page. -> ## Why `output: true`? -> -> When creating our `blogposts` collection in `_config.yml` above, -> we configured it with the parameter `output: true`, -> to ensure the pages of the collection were rendered to HTML by Jekyll. -> -> The other use of collections is as a collection of "data" files, -> defining objects that can be used as a list of variables throughout the site. -> For example, to avoid swelling the `_config.yml` file every time -> our team welcomes a new member, -> we could have created an individual file for -> each of the members of our team, defined a collection, and looped through -> those members that way. -> To use the collection of files like this, -> we would keep the default value of `output`, `false`. -{: .callout } +:::::::::::::::::::::::::::::::::::::::: callout + +## Why `output: true`? + +When creating our `blogposts` collection in `_config.yml` above, +we configured it with the parameter `output: true`, +to ensure the pages of the collection were rendered to HTML by Jekyll. + +The other use of collections is as a collection of "data" files, +defining objects that can be used as a list of variables throughout the site. +For example, to avoid swelling the `_config.yml` file every time +our team welcomes a new member, +we could have created an individual file for +each of the members of our team, defined a collection, and looped through +those members that way. +To use the collection of files like this, +we would keep the default value of `output`, `false`. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: ## Looping Over a Collection At the end of your `index.md`, add a new for loop to iterate over the titles and dates of the `blogposts` collection: -~~~ +```markdown ## Blog Posts {% raw %}{% for post in site.blogposts %} - {{ post.date | date_to_string }}: [{{ post.title }}]({{ post.url | relative_url }}) {% endfor %}{% endraw %} -~~~ -{: .language-markdown } +``` -![Rendered blog post list in the index page](../fig/blog_posts_list.png){: .image-with-shadow width="800px" } +![](fig/blog_posts_list.png){alt='Rendered blog post list in the index page' .image-with-shadow width="800px" } There is a lot happening in those few lines above! Let's break it down into smaller chunks and explore them one-by-one: 1. `{% raw %}{% for post in site.blogposts %}{% endraw %}` - initialises a loop through the collection. - The collection itself is made available to us as a `site` variable, - with the name we gave it in `_config.yml`. + initialises a loop through the collection. + The collection itself is made available to us as a `site` variable, + with the name we gave it in `_config.yml`. 2. `- ` will create a bullet point for each post. 3. `{% raw %}{{ post.date | date_to_string }}{% endraw %}` accesses the `date` - defined in the post's YAML header and displays it in the list as a string. + defined in the post's YAML header and displays it in the list as a string. 4. `{% raw %}[{{ post.title }}]({{ post.url | relative_url }}){% endraw %}` creates a link with the post's title - (again extracted from the YAML header of the post file) as the link text, - and the URL of the rendered post page as the link target. - Unlike the page title, - the URL is not defined in the page front matter but instead provided by Jekyll. - This page URL is passed to the `relative_url` filter, - which ensures the base URL of the GitHub Pages site is prepended and - the link resolves correctly. + (again extracted from the YAML header of the post file) as the link text, + and the URL of the rendered post page as the link target. + Unlike the page title, + the URL is not defined in the page front matter but instead provided by Jekyll. + This page URL is passed to the `relative_url` filter, + which ensures the base URL of the GitHub Pages site is prepended and + the link resolves correctly. 5. `{% raw %}{% endfor %}{% endraw %}` ends the for loop after every post in the - collection (i.e. every file in the `_blogposts` folder) has been iterated over. + collection (i.e. every file in the `_blogposts` folder) has been iterated over. Clicking on one of these links takes us to the rendered version of the blog post page. @@ -421,10 +434,10 @@ you can pass the collection through the [`sort`][liquid-sort] filter when initialising the for loop. You might be tempted to write: -~~~ + +```warning {% raw %}{% for post in site.blogposts | sort: "author" %}{% endraw %} -~~~ -{: .warning } +``` which seems to work but may not produce the result we expect. @@ -433,11 +446,11 @@ but can be seen if building the site locally. This a limitation of Liquid in that it doesn't allow combining `for` instructions directly with filters. Instead, we need to reuse the `assign` instruction we used above: -~~~ + +```source {% raw %}{% assign sorted_posts = site.blogposts | sort: "author" %} {% for post in sorted_posts %}{% endraw %} -~~~ -{: .source } +``` Other filters also exist for working with lists of values, such as [`group_by`][liquid-group-by], @@ -445,69 +458,83 @@ which can be used to group the values by a particular field, and [`sample`][liquid-sample], which returns a random sample of the values in the list. -> ## Exercise: Adding the Post Author -> -> Extend the example above to also state the name of the author -> next to each post in the list. -> -> > ## Solution -> > -> > ~~~ -> > {% raw %}{% for post in site.blogposts %} -> > - {{ post.date | date_to_string }}: [{{ post.title }}]({{ post.url }}) by {{ post.author }} -> > {% endfor %}{% endraw %} -> > ~~~ -> > {: .source } -> {: .solution } -{: .challenge } - -> ## Exercise: Reusable Post List -> -> A list of blog posts is exactly the kind of component we are likely to want to -> use in multiple places throughout the site. -> Move the code to create the listing to a new file in the `_includes` folder, -> modify it to work as an included block, -> and `include` it again the end of `index.md`. -> -> > ## Solution -> > -> > Create a new file, `_includes/post_list.html`, with the following content: -> > -> > ~~~ -> >

Blog Posts

-> >
    -> > {% raw %}{% for post in site.posts %} -> >
  • {{ post.date | date_to_string }}: {{ post.title }}
  • -> > {% endfor %}{% endraw %} -> >
-> > ~~~ -> > {: .language-html} -> > -> > and add an `include` statement at the end of `index.md`: -> > -> > ~~~ -> > {% raw %}{% include post_list.html %}{% endraw %} -> > ~~~ -> > {: .source } -> {: .solution } -{: .challenge } - -> ## Exercise: Extend the Collection -> -> Create another blog post and add it to the `blogposts` collection. -> Check that your new post appears in the list. -> -> > ## Solution -> > -> > Write another post Markdown file and save it into the `_blogposts` folder, -> > making sure you remember to add (at least) the `date` and -> > `title` fields in the YAML header. -> > -> > A link to the rendered version of that file should automatically appear -> > in the blog post list of your site's landing page (`index.html`). -> > -> {: .solution } -{: .challenge } +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Adding the Post Author + +Extend the example above to also state the name of the author +next to each post in the list. + +:::::::::::::: solution + +## Solution + +```source +{% raw %}{% for post in site.blogposts %} +- {{ post.date | date_to_string }}: [{{ post.title }}]({{ post.url }}) by {{ post.author }} +{% endfor %}{% endraw %} +``` + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Reusable Post List + +A list of blog posts is exactly the kind of component we are likely to want to +use in multiple places throughout the site. +Move the code to create the listing to a new file in the `_includes` folder, +modify it to work as an included block, +and `include` it again the end of `index.md`. + +:::::::::::::: solution + +## Solution + +Create a new file, `_includes/post_list.html`, with the following content: + +```html +

Blog Posts

+
    +{% raw %}{% for post in site.posts %} +
  • {{ post.date | date_to_string }}: {{ post.title }}
  • +{% endfor %}{% endraw %} +
+``` + +and add an `include` statement at the end of `index.md`: + +```source +{% raw %}{% include post_list.html %}{% endraw %} +``` + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Extend the Collection + +Create another blog post and add it to the `blogposts` collection. +Check that your new post appears in the list. + +:::::::::::::: solution + +## Solution + +Write another post Markdown file and save it into the `_blogposts` folder, +making sure you remember to add (at least) the `date` and +`title` fields in the YAML header. + +A link to the rendered version of that file should automatically appear +in the blog post list of your site's landing page (`index.html`). + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: ## Blogging in the Wild: the `_posts` Collection @@ -522,7 +549,7 @@ One of the key differences is the way that URLs are created for pages built from the `posts` collection: the `YYYY-MM-DD` date string defining the date of the post is used to create a nested URL structure of `/YYYY/MM/DD/`. -For this reason, _Jekyll requires that files in the `posts` collection +For this reason, \_Jekyll requires that files in the `posts` collection follow the naming structure `YYYY-MM-DD-post-slug.md` in order to be built for the site. For example, a file in `posts` called `2019-09-04-rise-and-shine.md` @@ -537,7 +564,7 @@ You can read more about the Finally, it is common to need to create a listing of posts (or some other collection) that is displayed in smaller chunks e.g. ten posts at a time. -This is called _pagination_, +This is called *pagination*, and is enabled in Jekyll via a plugin called `jekyll-paginate`. (This plugin is included by default in GitHub Pages.) The Jekyll documentation describes @@ -557,15 +584,13 @@ The path provided here should be relative to the root of your site - the directory where your `config.yml` is located. Taking the example from the `posts` collection above: -``` +```source {% raw %}{% link _posts/2019-09-04-rise-and-shine.md %}{% endraw %} ``` -{: .source } -``` +```output /2019/09/04/rise-and-shine.html ``` -{: .output } If you would like to [set up your computer to build your site locally][jekyll-install] @@ -573,40 +598,52 @@ e.g. to preview changes to your site before they "go live" on GitHub Pages, you should get into the habit of substituting in the `site.baseurl` variable at the start of these internal links: -``` +```source {% raw %}{{ site.baseurl }}{% link _posts/2019-09-04-rise-and-shine.md %}{% endraw %} ``` -{: .source} This will ensure that the links within your site work correctly in the local version of the site as well as on GitHub Pages. -> ## Comments on a Static Blog -> -> When setting up a blog on a website, it is common to want to include a comment feed -> as a way for readers to respond to the content of a post, direct questions to the author, etc. -> A comments section can be included in a static blog using one of the below approaches. -> 1. Disqus is the first approach. The Disqus website offers -> [instructions on how to enable comments for Jekyll platform (used for GitHub pages)](https://disqus.com/admin/install/platforms/jekyll/). -> [Here is a demo of Disqus with Jekyll](https://erresen.github.io/jekyll/disqus/2016/08/26/getting-comments-working-jekyll-disqus.html). -> Although if you are privacy inclined, browser extensions such as Privacy Badger block the Disqus widget so you might look for alternatives. -> 2. [Staticman](https://staticman.net/) is the second approach. -> The setup is more complex than some of the other options and, in our experience, it is easy to get the configuration wrong. -> [Here is a demo of comments with Staticman](https://travisdowns.github.io/blog/2020/02/05/now-with-comments.html). -> 3. [Just Comments](https://just-comments.com/) is the third approach. -> [Here is a demo of comments with Just Comments](https://60devs.com/adding-comments-to-your-jekyll-blog.html). -> 4. [fastpages](https://github.com/fastai/fastpages) is the most recent addition to -> enable comments via GitHub comments (uses [Utterances](https://utteranc.es/)). -> fastpages comes with lots of options and is used by several researchers. -> [Here is a demo of comments with fastpages](https://fastpages.fast.ai/fastpages/jupyter/2020/02/21/introducing-fastpages.html). -> 5. [Welcomments](https://welcomments.io/) (currently in beta testing) provides a webform for comments, -> and a bot that commits these to your website's source GitHub repository so that they are included -> and displayed when the page is rebuilt. -> From the comments section implementation standpoint, Disqus looks most simple followed by Just Comments and Staticman. -> Fastpages is much more than enabling a comments section. -> It is a blog template that uses Jekyll as a base, improves on Jekyll experience and offers additional features. -> For researchers this may be the option to go. -> -{: .callout} - -{% include links.md %} +::::::::::::::::::::::::::::::::::::::::: callout + +## Comments on a Static Blog + +When setting up a blog on a website, it is common to want to include a comment feed +as a way for readers to respond to the content of a post, direct questions to the author, etc. +A comments section can be included in a static blog using one of the below approaches. + +1. Disqus is the first approach. The Disqus website offers + [instructions on how to enable comments for Jekyll platform (used for GitHub pages)](https://disqus.com/admin/install/platforms/jekyll/). + [Here is a demo of Disqus with Jekyll](https://erresen.github.io/jekyll/disqus/2016/08/26/getting-comments-working-jekyll-disqus.html). + Although if you are privacy inclined, browser extensions such as Privacy Badger block the Disqus widget so you might look for alternatives. +2. [Staticman](https://staticman.net/) is the second approach. + The setup is more complex than some of the other options and, in our experience, it is easy to get the configuration wrong. + [Here is a demo of comments with Staticman](https://travisdowns.github.io/blog/2020/02/05/now-with-comments.html). +3. [Just Comments](https://just-comments.com/) is the third approach. + [Here is a demo of comments with Just Comments](https://60devs.com/adding-comments-to-your-jekyll-blog.html). +4. [fastpages](https://github.com/fastai/fastpages) is the most recent addition to + enable comments via GitHub comments (uses [Utterances](https://utteranc.es/)). + fastpages comes with lots of options and is used by several researchers. + [Here is a demo of comments with fastpages](https://fastpages.fast.ai/fastpages/jupyter/2020/02/21/introducing-fastpages.html). +5. [Welcomments](https://welcomments.io/) (currently in beta testing) provides a webform for comments, + and a bot that commits these to your website's source GitHub repository so that they are included + and displayed when the page is rebuilt. + From the comments section implementation standpoint, Disqus looks most simple followed by Just Comments and Staticman. + Fastpages is much more than enabling a comments section. + It is a blog template that uses Jekyll as a base, improves on Jekyll experience and offers additional features. + For researchers this may be the option to go. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + + +:::::::::::::::::::::::::::::::::::::::: keypoints + +- Iterate over multiple values in a list with a for loop. +- Collections are defined in a site's global configuration and populated in a corresponding folder. +- Collections are presented by Jekyll as a list of page objects. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + diff --git a/fig/about_page.png b/episodes/fig/about_page.png similarity index 100% rename from fig/about_page.png rename to episodes/fig/about_page.png diff --git a/fig/blank_new_repo.png b/episodes/fig/blank_new_repo.png similarity index 100% rename from fig/blank_new_repo.png rename to episodes/fig/blank_new_repo.png diff --git a/fig/blog_posts_list.png b/episodes/fig/blog_posts_list.png similarity index 100% rename from fig/blog_posts_list.png rename to episodes/fig/blog_posts_list.png diff --git a/fig/committing_formatting_addition_to_readme.png b/episodes/fig/committing_formatting_addition_to_readme.png similarity index 100% rename from fig/committing_formatting_addition_to_readme.png rename to episodes/fig/committing_formatting_addition_to_readme.png diff --git a/fig/create_repository.png b/episodes/fig/create_repository.png similarity index 100% rename from fig/create_repository.png rename to episodes/fig/create_repository.png diff --git a/fig/default_website.png b/episodes/fig/default_website.png similarity index 100% rename from fig/default_website.png rename to episodes/fig/default_website.png diff --git a/fig/directory-structure-rendered-website-with-annotations.png b/episodes/fig/directory-structure-rendered-website-with-annotations.png similarity index 100% rename from fig/directory-structure-rendered-website-with-annotations.png rename to episodes/fig/directory-structure-rendered-website-with-annotations.png diff --git a/fig/directory-structure-rendered-website.png b/episodes/fig/directory-structure-rendered-website.png similarity index 100% rename from fig/directory-structure-rendered-website.png rename to episodes/fig/directory-structure-rendered-website.png diff --git a/fig/directory-structure-rendered-website.xcf b/episodes/fig/directory-structure-rendered-website.xcf similarity index 100% rename from fig/directory-structure-rendered-website.xcf rename to episodes/fig/directory-structure-rendered-website.xcf diff --git a/fig/directory-structure.xcf b/episodes/fig/directory-structure.xcf similarity index 100% rename from fig/directory-structure.xcf rename to episodes/fig/directory-structure.xcf diff --git a/fig/exercise_add_code.png b/episodes/fig/exercise_add_code.png similarity index 100% rename from fig/exercise_add_code.png rename to episodes/fig/exercise_add_code.png diff --git a/fig/exercise_links.png b/episodes/fig/exercise_links.png similarity index 100% rename from fig/exercise_links.png rename to episodes/fig/exercise_links.png diff --git a/fig/exercise_nested_lists_enumerations.png b/episodes/fig/exercise_nested_lists_enumerations.png similarity index 100% rename from fig/exercise_nested_lists_enumerations.png rename to episodes/fig/exercise_nested_lists_enumerations.png diff --git a/fig/exercise_syntax_highlighting.png b/episodes/fig/exercise_syntax_highlighting.png similarity index 100% rename from fig/exercise_syntax_highlighting.png rename to episodes/fig/exercise_syntax_highlighting.png diff --git a/fig/filters-post-1851-05-06-DIG-ordinal.png b/episodes/fig/filters-post-1851-05-06-DIG-ordinal.png similarity index 100% rename from fig/filters-post-1851-05-06-DIG-ordinal.png rename to episodes/fig/filters-post-1851-05-06-DIG-ordinal.png diff --git a/fig/filters-post-1851-05-06-DIG-without-ordinal.png b/episodes/fig/filters-post-1851-05-06-DIG-without-ordinal.png similarity index 100% rename from fig/filters-post-1851-05-06-DIG-without-ordinal.png rename to episodes/fig/filters-post-1851-05-06-DIG-without-ordinal.png diff --git a/fig/filters_post_1827-11-22_surgeon.png b/episodes/fig/filters_post_1827-11-22_surgeon.png similarity index 100% rename from fig/filters_post_1827-11-22_surgeon.png rename to episodes/fig/filters_post_1827-11-22_surgeon.png diff --git a/fig/filters_post_1851-05-06_DIG.png b/episodes/fig/filters_post_1851-05-06_DIG.png similarity index 100% rename from fig/filters_post_1851-05-06_DIG.png rename to episodes/fig/filters_post_1851-05-06_DIG.png diff --git a/fig/filters_post_1851-05-06_DIG_ordinal.png b/episodes/fig/filters_post_1851-05-06_DIG_ordinal.png similarity index 100% rename from fig/filters_post_1851-05-06_DIG_ordinal.png rename to episodes/fig/filters_post_1851-05-06_DIG_ordinal.png diff --git a/fig/filters_post_1851-05-06_DIG_without_ordinal.png b/episodes/fig/filters_post_1851-05-06_DIG_without_ordinal.png similarity index 100% rename from fig/filters_post_1851-05-06_DIG_without_ordinal.png rename to episodes/fig/filters_post_1851-05-06_DIG_without_ordinal.png diff --git a/fig/first_index_page.png b/episodes/fig/first_index_page.png similarity index 100% rename from fig/first_index_page.png rename to episodes/fig/first_index_page.png diff --git a/fig/first_website.png b/episodes/fig/first_website.png similarity index 100% rename from fig/first_website.png rename to episodes/fig/first_website.png diff --git a/fig/gh-fork-button.png b/episodes/fig/gh-fork-button.png similarity index 100% rename from fig/gh-fork-button.png rename to episodes/fig/gh-fork-button.png diff --git a/fig/github-branch-ghpages.png b/episodes/fig/github-branch-ghpages.png similarity index 100% rename from fig/github-branch-ghpages.png rename to episodes/fig/github-branch-ghpages.png diff --git a/fig/github-forking-progress.png b/episodes/fig/github-forking-progress.png similarity index 100% rename from fig/github-forking-progress.png rename to episodes/fig/github-forking-progress.png diff --git a/fig/github_add_index.png b/episodes/fig/github_add_index.png similarity index 100% rename from fig/github_add_index.png rename to episodes/fig/github_add_index.png diff --git a/fig/github_create_another_file.png b/episodes/fig/github_create_another_file.png similarity index 100% rename from fig/github_create_another_file.png rename to episodes/fig/github_create_another_file.png diff --git a/fig/github_create_file.png b/episodes/fig/github_create_file.png similarity index 100% rename from fig/github_create_file.png rename to episodes/fig/github_create_file.png diff --git a/fig/group_website_exercise_add_a_sub_heading.png b/episodes/fig/group_website_exercise_add_a_sub_heading.png similarity index 100% rename from fig/group_website_exercise_add_a_sub_heading.png rename to episodes/fig/group_website_exercise_add_a_sub_heading.png diff --git a/fig/group_website_readme_commit.png b/episodes/fig/group_website_readme_commit.png similarity index 100% rename from fig/group_website_readme_commit.png rename to episodes/fig/group_website_readme_commit.png diff --git a/fig/group_website_readme_edit.png b/episodes/fig/group_website_readme_edit.png similarity index 100% rename from fig/group_website_readme_edit.png rename to episodes/fig/group_website_readme_edit.png diff --git a/fig/group_website_readme_render.png b/episodes/fig/group_website_readme_render.png similarity index 100% rename from fig/group_website_readme_render.png rename to episodes/fig/group_website_readme_render.png diff --git a/fig/group_website_repo.png b/episodes/fig/group_website_repo.png similarity index 100% rename from fig/group_website_repo.png rename to episodes/fig/group_website_repo.png diff --git a/fig/group_website_repo_edit.png b/episodes/fig/group_website_repo_edit.png similarity index 100% rename from fig/group_website_repo_edit.png rename to episodes/fig/group_website_repo_edit.png diff --git a/fig/html-list.png b/episodes/fig/html-list.png similarity index 100% rename from fig/html-list.png rename to episodes/fig/html-list.png diff --git a/fig/html-table.png b/episodes/fig/html-table.png similarity index 100% rename from fig/html-table.png rename to episodes/fig/html-table.png diff --git a/fig/includes_contact_links_footer.png b/episodes/fig/includes_contact_links_footer.png similarity index 100% rename from fig/includes_contact_links_footer.png rename to episodes/fig/includes_contact_links_footer.png diff --git a/fig/includes_navigation_links_header.png b/episodes/fig/includes_navigation_links_header.png similarity index 100% rename from fig/includes_navigation_links_header.png rename to episodes/fig/includes_navigation_links_header.png diff --git a/fig/initialize_readme_license.png b/episodes/fig/initialize_readme_license.png similarity index 100% rename from fig/initialize_readme_license.png rename to episodes/fig/initialize_readme_license.png diff --git a/fig/jekyll-gh-pages-website-overview.png b/episodes/fig/jekyll-gh-pages-website-overview.png similarity index 100% rename from fig/jekyll-gh-pages-website-overview.png rename to episodes/fig/jekyll-gh-pages-website-overview.png diff --git a/fig/jekyll-gh-pages-website-overview.svg b/episodes/fig/jekyll-gh-pages-website-overview.svg similarity index 100% rename from fig/jekyll-gh-pages-website-overview.svg rename to episodes/fig/jekyll-gh-pages-website-overview.svg diff --git a/fig/jekyll_build_error.png b/episodes/fig/jekyll_build_error.png similarity index 100% rename from fig/jekyll_build_error.png rename to episodes/fig/jekyll_build_error.png diff --git a/fig/jekyll_build_error_detail.png b/episodes/fig/jekyll_build_error_detail.png similarity index 100% rename from fig/jekyll_build_error_detail.png rename to episodes/fig/jekyll_build_error_detail.png diff --git a/fig/jekyll_fail_pending_successful.png b/episodes/fig/jekyll_fail_pending_successful.png similarity index 100% rename from fig/jekyll_fail_pending_successful.png rename to episodes/fig/jekyll_fail_pending_successful.png diff --git a/fig/layouts_banner_only.png b/episodes/fig/layouts_banner_only.png similarity index 100% rename from fig/layouts_banner_only.png rename to episodes/fig/layouts_banner_only.png diff --git a/fig/layouts_double_banner.png b/episodes/fig/layouts_double_banner.png similarity index 100% rename from fig/layouts_double_banner.png rename to episodes/fig/layouts_double_banner.png diff --git a/fig/layouts_double_navigation.png b/episodes/fig/layouts_double_navigation.png similarity index 100% rename from fig/layouts_double_navigation.png rename to episodes/fig/layouts_double_navigation.png diff --git a/fig/layouts_homepage_layout.png b/episodes/fig/layouts_homepage_layout.png similarity index 100% rename from fig/layouts_homepage_layout.png rename to episodes/fig/layouts_homepage_layout.png diff --git a/fig/lesson-home-page.png b/episodes/fig/lesson-home-page.png similarity index 100% rename from fig/lesson-home-page.png rename to episodes/fig/lesson-home-page.png diff --git a/fig/markdown_exercise.png b/episodes/fig/markdown_exercise.png similarity index 100% rename from fig/markdown_exercise.png rename to episodes/fig/markdown_exercise.png diff --git a/fig/markdown_preview_formatting.png b/episodes/fig/markdown_preview_formatting.png similarity index 100% rename from fig/markdown_preview_formatting.png rename to episodes/fig/markdown_preview_formatting.png diff --git a/fig/new_repo_button.png b/episodes/fig/new_repo_button.png similarity index 100% rename from fig/new_repo_button.png rename to episodes/fig/new_repo_button.png diff --git a/fig/page-generation-js4ds.svg b/episodes/fig/page-generation-js4ds.svg similarity index 100% rename from fig/page-generation-js4ds.svg rename to episodes/fig/page-generation-js4ds.svg diff --git a/fig/pages_check_main.png b/episodes/fig/pages_check_main.png similarity index 100% rename from fig/pages_check_main.png rename to episodes/fig/pages_check_main.png diff --git a/fig/plus_new_repo.png b/episodes/fig/plus_new_repo.png similarity index 100% rename from fig/plus_new_repo.png rename to episodes/fig/plus_new_repo.png diff --git a/fig/rendered-website.xcf b/episodes/fig/rendered-website.xcf similarity index 100% rename from fig/rendered-website.xcf rename to episodes/fig/rendered-website.xcf diff --git a/fig/repo_settings.png b/episodes/fig/repo_settings.png similarity index 100% rename from fig/repo_settings.png rename to episodes/fig/repo_settings.png diff --git a/fig/repository_contents.png b/episodes/fig/repository_contents.png similarity index 100% rename from fig/repository_contents.png rename to episodes/fig/repository_contents.png diff --git a/fig/repository_details.png b/episodes/fig/repository_details.png similarity index 100% rename from fig/repository_details.png rename to episodes/fig/repository_details.png diff --git a/fig/set_CC0_license.png b/episodes/fig/set_CC0_license.png similarity index 100% rename from fig/set_CC0_license.png rename to episodes/fig/set_CC0_license.png diff --git a/fig/set_repo_description.png b/episodes/fig/set_repo_description.png similarity index 100% rename from fig/set_repo_description.png rename to episodes/fig/set_repo_description.png diff --git a/fig/set_repo_name.png b/episodes/fig/set_repo_name.png similarity index 100% rename from fig/set_repo_name.png rename to episodes/fig/set_repo_name.png diff --git a/fig/settings_pages_tab.png b/episodes/fig/settings_pages_tab.png similarity index 100% rename from fig/settings_pages_tab.png rename to episodes/fig/settings_pages_tab.png diff --git a/fig/soft_hard_markdown_line_break.png b/episodes/fig/soft_hard_markdown_line_break.png similarity index 100% rename from fig/soft_hard_markdown_line_break.png rename to episodes/fig/soft_hard_markdown_line_break.png diff --git a/fig/team_members_list.png b/episodes/fig/team_members_list.png similarity index 100% rename from fig/team_members_list.png rename to episodes/fig/team_members_list.png diff --git a/fig/website_url.png b/episodes/fig/website_url.png similarity index 100% rename from fig/website_url.png rename to episodes/fig/website_url.png diff --git a/fig/website_url_green_tick.png b/episodes/fig/website_url_green_tick.png similarity index 100% rename from fig/website_url_green_tick.png rename to episodes/fig/website_url_green_tick.png diff --git a/files/site_banner.png b/episodes/files/site_banner.png similarity index 100% rename from files/site_banner.png rename to episodes/files/site_banner.png diff --git a/episodes/filters.md b/episodes/filters.md index 37eb1772..048196fd 100644 --- a/episodes/filters.md +++ b/episodes/filters.md @@ -1,19 +1,23 @@ --- -title: "Working With Filters" +title: Working With Filters teaching: 20 exercises: 5 -questions: -- "How can I control the format of variable values such as dates when I insert them into a page?" -objectives: -- "Use filters to control the format and content of substituted values." -keypoints: -- "Liquid filters can be used to adapt the values of variables when adding them into your pages." -- "Datetime filters such as `date_to_string` can provide more readable timestamps on your pages and posts." -- "GitHub Pages doesn't use the most recent version of Jekyll, so you should avoid the features added most recently." --- ## Writing Blog Posts +::::::::::::::::::::::::::::::::::::::: objectives + +- Use filters to control the format and content of substituted values. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: questions + +- How can I control the format of variable values such as dates when I insert them into a page? + +:::::::::::::::::::::::::::::::::::::::::::::::::: + So far we have been building our site one page at a time, but these individual pages are quite self-contained and their content is likely to be fairly constant: @@ -39,7 +43,7 @@ To start adding blog posts to our site the first thing we need to do is create a new layout for these posts, inheriting from the default layout we created earlier. -~~~ +```html {% raw %}--- layout: default --- @@ -48,15 +52,14 @@ layout: default Published on {{ page.date }} {{ content }}{% endraw %} -~~~ -{: .language-html } +``` Save this layout to `_layouts/post.html`. Now we can create our first blog post (**in the root of our website repository for now**), `1827-11-22-surgeon.md`, remembering to add the `author` and `date` fields to the YAML front matter: -~~~ +```markdown {% raw %}--- layout: post title: I am a Surgeon! @@ -65,41 +68,49 @@ date: 1827-11-22 --- Today was a good day. I was promoted to Surgeon to the Forces!{% endraw %} -~~~ -{: .language-markdown } +``` You can view the post at `https://GITHUB_USERNAME.github.io/REPOSITORY_NAME/1827-11-22-surgeon.html`. -![Blog post '1827-11-22'](../fig/filters_post_1827-11-22_surgeon.png){: .image-with-shadow width="700px" } +![](fig/filters_post_1827-11-22_surgeon.png){alt="Blog post '1827-11-22'" .image-with-shadow width="700px" } This is a good start! Let's make a second post before we try to further improve our post layout. -> ## Exercise: Creating Another Post -> -> Write another blog post, in a file called `1851-05-06-DIG.md` in the root of our website repository, -> so that the rendered page looks like this: -> -> ![Blog post '1851-05-06'](../fig/filters_post_1851-05-06_DIG.png){: .image-with-shadow width="700px" } -> -> > ## Solution -> > Create the file `1851-05-06-DIG.md` in the root of the repository with the following content: -> > ~~~ -> > --- -> > layout: post -> > title: Promoted Again -> > author: Dr James Barry -> > date: 1851-05-06 -> > --- -> > -> > Good news: I have been promoted to Deputy Inspector-General of Hospitals. -> > ~~~ -> > {: .language-markdown } -> > You can view the post at https://GITHUB_USERNAME.github.io/REPOSITORY_NAME/1851-05-06-DIG.html. -> {: .solution } -{: .challenge } +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Creating Another Post + +Write another blog post, in a file called `1851-05-06-DIG.md` in the root of our website repository, +so that the rendered page looks like this: + +![](fig/filters_post_1851-05-06_DIG.png){alt="Blog post '1851-05-06'" .image-with-shadow width="700px" } + +:::::::::::::: solution + +## Solution + +Create the file `1851-05-06-DIG.md` in the root of the repository with the following content: + +```markdown +--- +layout: post +title: Promoted Again +author: Dr James Barry +date: 1851-05-06 +--- + +Good news: I have been promoted to Deputy Inspector-General of Hospitals. +``` + +You can view the post at [https://GITHUB\_USERNAME.github.io/REPOSITORY\_NAME/1851-05-06-DIG.html](https://GITHUB_USERNAME.github.io/REPOSITORY_NAME/1851-05-06-DIG.html). + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + ## Introducing Filters The YYYY-MM-DD format for dates is easy to remember and @@ -111,14 +122,13 @@ we can define the format in which the date should be displayed in the `post.html layout file. The YYYY-MM-DD date in the post front matter will be converted to a more human format (e.g. "6th May 1851" instead of "1851-05-06" in the second post `1851-05-06-DIG.md` we added) at the top of each post, -using a _Filter_: +using a *Filter*: -~~~ +```markdown {% raw %}Published on {{ page.date | date_to_long_string: "ordinal" }}{% endraw %} -~~~ -{: .language-markdown } +``` -![Blog post '1851-05-06' with human readable date using ordinal parameter](../fig/filters_post_1851-05-06_DIG_ordinal.png){: .image-with-shadow width="700px" } +![](fig/filters_post_1851-05-06_DIG_ordinal.png){alt="Blog post '1851-05-06' with human readable date using ordinal parameter" .image-with-shadow width="700px" } Filters like `date_to_long_string` can be used when working with variable values on a page. @@ -126,44 +136,63 @@ When a filter is applied to a variable, it processes that value in some way: in the example above, it converts the format of the date string. We will explore the `"ordinal"` part in the exercise below. +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Date Formats + +`"ordinal"` is being passed as an argument to the `date_to_long_string` filter. +To see how this argument is changing the behaviour of the filter, +try removing it in the second post (`1851-05-06-DIG.md`), i.e. +`{% raw %}{{ page.date | date_to_long_string }}{% endraw %}`. +What happens? +Which output do you prefer? + +:::::::::::::: solution -> ## Exercise: Date Formats -> -> `"ordinal"` is being passed as an argument to the `date_to_long_string` filter. -> To see how this argument is changing the behaviour of the filter, -> try removing it in the second post (`1851-05-06-DIG.md`), i.e. -> `{% raw %}{{ page.date | date_to_long_string }}{% endraw %}`. -> What happens? -> Which output do you prefer? -> -> > ## Solution -> > -> > Without the `ordinal` argument, `date_to_long_string` produces the output -> > `06 May 1851` (i.e. using the two digits to represent day). -> > Whether you prefer this format is entirely subjective, -> > and we encourage you to use which ever you prefer in your post layout. -> > ![Blog post '1851-05-06' with human readable date without ordinal parameter](../fig/filters_post_1851-05-06_DIG_without_ordinal.png){: .image-with-shadow width="700px" } -> > -> {: .solution } -{: .challenge } +## Solution + +Without the `ordinal` argument, `date_to_long_string` produces the output +`06 May 1851` (i.e. using the two digits to represent day). +Whether you prefer this format is entirely subjective, +and we encourage you to use which ever you prefer in your post layout. +![](fig/filters_post_1851-05-06_DIG_without_ordinal.png){alt="Blog post '1851-05-06' with human readable date without ordinal parameter" .image-with-shadow width="700px" } + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: These filters are based on Liquid, the scripting language underlying Jekyll. We will see another example of a filter in use in the next, final section, after learning a bit about arrays and collections in Jekyll. -> ## Documentation and a Word of Warning -> [A complete list of available filters][filters] -> is provided in the [official Jekyll documentation][jekyll] -> and you might also find it helpful to refer to -> [the official Liquid documentation][liquid] -> while you continue to explore. -> -> Beware however, that -> **GitHub Pages does not use the most up-to-date version of Jekyll!** -> This means that some features you will read about in the Jekyll documentation -> will not be available for you to use on your site. -> [Use this page to check the versions of Jekyll and other dependencies used by GitHub Pages][ghp-dependencies]. -{: .callout } - -{% include links.md %} +:::::::::::::::::::::::::::::::::::::::: callout + +## Documentation and a Word of Warning + +[A complete list of available filters][filters] +is provided in the [official Jekyll documentation][jekyll] +and you might also find it helpful to refer to +[the official Liquid documentation][liquid] +while you continue to explore. + +Beware however, that +**GitHub Pages does not use the most up-to-date version of Jekyll!** +This means that some features you will read about in the Jekyll documentation +will not be available for you to use on your site. +[Use this page to check the versions of Jekyll and other dependencies used by GitHub Pages][ghp-dependencies]. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + + +:::::::::::::::::::::::::::::::::::::::: keypoints + +- Liquid filters can be used to adapt the values of variables when adding them into your pages. +- Datetime filters such as `date_to_string` can provide more readable timestamps on your pages and posts. +- GitHub Pages doesn't use the most recent version of Jekyll, so you should avoid the features added most recently. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + diff --git a/episodes/github-pages.md b/episodes/github-pages.md index c86cc3ca..472ab7b4 100644 --- a/episodes/github-pages.md +++ b/episodes/github-pages.md @@ -1,26 +1,26 @@ --- -title: "Hosting Websites on GitHub" +title: Hosting Websites on GitHub teaching: 20 exercises: 20 -questions: -- "How do I publish my page or a website on the Web via GitHub?" -objectives: -- "Publish Markdown files as HTML on the Web with GitHub Pages" -keypoints: -- "GitHub Pages is a static site hosting service that takes files in various formats - (Markdown, HTML, CSS, JavaScript, etc.) - straight from a repository on GitHub, runs them through its website engine Jekyll, builds them into a website, - and publishes them on the Web" -- "By convention, if you create a branch called `gh-pages` in your repository, it will automatically be published as a website by GitHub" -- "You can configure any branch of a repository to be used for website (it does not have to be `gh-pages`)" -- "GitHub publishes websites on special URLs formatted as 'https://GITHUB_USERNAME.github.io/REPOSITORY_NAME'" - --- Now that you know how to create Markdown files, let's see how to turn them into Web pages. GitHub has a service just for that called GitHub Pages. +::::::::::::::::::::::::::::::::::::::: objectives + +- Publish Markdown files as HTML on the Web with GitHub Pages + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: questions + +- How do I publish my page or a website on the Web via GitHub? + +:::::::::::::::::::::::::::::::::::::::::::::::::: + ## Publishing a Website With GitHub Pages + [GitHub Pages](https://docs.github.com/en/github/working-with-github-pages/about-github-pages) is a free website hosting service by GitHub that takes files (Markdown, HTML, CSS, JavaScript, etc.) from your GitHub repository which is configured as a website, @@ -33,45 +33,55 @@ There are other services available to create and publish websites but one of the Let's continue from the GitHub repository we have created in the previous episode. One important file you should already have is `README.md`, which will become the homepage of your project website (until we add the index file later on). ## Enabling GitHub Pages -In order to tell GitHub that your repository contains a website that needs rendering you need to configure GitHub Pages settings. You can do so from your repository's _Settings_ page, as explained below. + +In order to tell GitHub that your repository contains a website that needs rendering you need to configure GitHub Pages settings. You can do so from your repository's *Settings* page, as explained below. You may have noticed that when we created our repository in previous episode, by default GitHub created a branch called `main` and stored our files there. We now need to tell GitHub Pages that this branch contains our website files. -> ## What Is a Branch? -> You may have never heard about Git branches and wonder what they are. A branch is one version of your project (the files in your repository) that can contain its own set of commits - you can have many branches (versions) of your repository. The default branch automatically created with a new github repository is called `main`. -> -{: .callout} -1. Click on the repository's `Settings` tab (the one with the little cog/gear icon) as shown on the figure below: +::::::::::::::::::::::::::::::::::::::::: callout - ![Repository 'Settings' button in GitHub interface](../fig/repo_settings.png){: .image-with-shadow width="900px" } +## What Is a Branch? -2. On the menu on the left hand side, click on `Pages` +You may have never heard about Git branches and wonder what they are. A branch is one version of your project (the files in your repository) that can contain its own set of commits - you can have many branches (versions) of your repository. The default branch automatically created with a new github repository is called `main`. - ![Select 'Pages' tab in repository settings](../fig/settings_pages_tab.png){: .image-with-shadow width="900px" } +:::::::::::::::::::::::::::::::::::::::::::::::::: -3. You will see that the GitHub Pages settings are currently disabled. Select branch `main` to -tell GitHub which branch to use as a source and -click `Save` to enable GitHub Pages for this repository. +1. Click on the repository's `Settings` tab (the one with the little cog/gear icon) as shown on the figure below: + + ![](fig/repo_settings.png){alt="Repository 'Settings' button in GitHub interface" .image-with-shadow width="900px" } - ![Set default branch for the website in repository settings](../fig/pages_check_main.png){: .image-with-shadow width="900px" } +2. On the menu on the left hand side, click on `Pages` + + ![](fig/settings_pages_tab.png){alt="Select 'Pages' tab in repository settings" .image-with-shadow width="900px" } -4. The link to your repository's website will appear in the highlighted box above. If you click the link - your default browser will open and show your project website. If this does not happen, you should manually open your favourite web browser and paste the URL. +3. You will see that the GitHub Pages settings are currently disabled. Select branch `main` to + tell GitHub which branch to use as a source and + click `Save` to enable GitHub Pages for this repository. + + ![](fig/pages_check_main.png){alt='Set default branch for the website in repository settings' .image-with-shadow width="900px" } - ![URL where the project website will be published by GitHub Pages](../fig/website_url.png){: .image-with-shadow width="900px" } +4. The link to your repository's website will appear in the highlighted box above. If you click the link - your default browser will open and show your project website. If this does not happen, you should manually open your favourite web browser and paste the URL. + + ![](fig/website_url.png){alt='URL where the project website will be published by GitHub Pages' .image-with-shadow width="900px" } 5. It may take a while (from a few seconds to a few minutes) for GitHub to compile your website (depending on GitHub's availability and the complexity of -your website) and it may not become visible immediately. You will know it is ready when the link appears in green box with a "tick" in front of the web address (as shown in the figure below). - - ![Project website URL - indication of a successful build](../fig/website_url_green_tick.png){: .image-with-shadow width="900px" } + your website) and it may not become visible immediately. You will know it is ready when the link appears in green box with a "tick" in front of the web address (as shown in the figure below). + + ![](fig/website_url_green_tick.png){alt='Project website URL - indication of a successful build' .image-with-shadow width="900px" } 6. Once ready, you should see the contents of the `README.md` file that we created earlier, rendered as a website. + + ![](fig/first_website.png){alt='Our first website rendered by GitHub and showing the contents of README' .image-with-shadow width="900px" } - ![Our first website rendered by GitHub and showing the contents of README](../fig/first_website.png){: .image-with-shadow width="900px" } +::::::::::::::::::::::::::::::::::::::::: callout -> ## Using Branch `gh-pages` for Websites -> By convention, GitHub Pages uses branch called `gh-pages` to look for the website content. By creating a branch with that name, you implicitly tell GitHub that you want your content published and you do not need to configure -> GitHub Pages in `Settings`. Once you create `gh-pages` from your current branch (typically `main`, created by default when you created the repository), you can then choose to delete the other branch to avoid any confusion about where your content is stored. -{: .callout} +## Using Branch `gh-pages` for Websites + +By convention, GitHub Pages uses branch called `gh-pages` to look for the website content. By creating a branch with that name, you implicitly tell GitHub that you want your content published and you do not need to configure +GitHub Pages in `Settings`. Once you create `gh-pages` from your current branch (typically `main`, created by default when you created the repository), you can then choose to delete the other branch to avoid any confusion about where your content is stored. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: Either of the above two approaches to turning a repository to a website will give you the same result - the `gh-pages` approach is perhaps more common as it favours convention over configuration. @@ -79,21 +89,26 @@ Either of the above two approaches to turning a repository to a website will giv You may have noticed a slightly strange URL for your website appearing in that green box with a "tick" in front of it. This URL was generated by GitHub Pages and is not random. It is formatted as -'https://GITHUB_USERNAME.github.io/REPOSITORY_NAME' and is formed by appending: +'[https://GITHUB\_USERNAME.github.io/REPOSITORY\_NAME](https://GITHUB_USERNAME.github.io/REPOSITORY_NAME)' and is formed by appending: -- your GitHub username or organisation name under which the repository is created (GITHUB_USERNAME) +- your GitHub username or organisation name under which the repository is created (GITHUB\_USERNAME) - '.github.io/' (GitHub's web hosting domain) -- the repository name (REPOSITORY_NAME) +- the repository name (REPOSITORY\_NAME) Because the repository name is unique within one's personal or organisational GitHub account - this naming convention gives us a way of neatly creating Web addresses for any GitHub repository without any conflicts. -> ## Customising Domain -> GitHub Pages supports using custom domains, or changing your site's URL from the default ->'https://GITHUB_USERNAME.github.io/REPOSITORY_NAME' to any domain you own. -> [Check out the documentation on configuring a custom domain for your GitHub Pages site](https://docs.github.com/en/free-pro-team@latest/github/working-with-github-pages/configuring-a-custom-domain-for-your-github-pages-site). -{: .callout} +::::::::::::::::::::::::::::::::::::::::: callout + +## Customising Domain + +GitHub Pages supports using custom domains, or changing your site's URL from the default +'[https://GITHUB\_USERNAME.github.io/REPOSITORY\_NAME](https://GITHUB_USERNAME.github.io/REPOSITORY_NAME)' to any domain you own. +[Check out the documentation on configuring a custom domain for your GitHub Pages site](https://docs.github.com/en/free-pro-team@latest/github/working-with-github-pages/configuring-a-custom-domain-for-your-github-pages-site). + + +:::::::::::::::::::::::::::::::::::::::::::::::::: ## Making Your Pages More Findable @@ -104,7 +119,7 @@ and add descriptive topics or tags about the content or technologies used in you You can edit the details of your repository by clicking on the little cog/gear button as shown on the figure below. -![About section of a repository - edit repository details](../fig/repository_details.png){: .image-with-shadow width="900px" } +![](fig/repository_details.png){alt='About section of a repository - edit repository details' .image-with-shadow width="900px" } By doing this, you add a link to the repository's website on your repository's landing page and anyone (including yourself) can access it quickly when visiting your GitHub repository. @@ -118,35 +133,45 @@ To separate the contents of the repository's README from the website's homepage, To create a new file from GitHub interface, click the `Add file` button and select `Create new file` from the dropdown. -![Create a new file button in the GitHub interface](../fig/github_create_file.png){: .image-with-shadow width="900px" } +![](fig/github_create_file.png){alt='Create a new file button in the GitHub interface' .image-with-shadow width="900px" } Next, type some text into `index.md`. As shown below add a first level header that says `Building Websites in GitHub`. -![Create index.md file](../fig/github_add_index.png){: .image-with-shadow width="900px" } +![](fig/github_add_index.png){alt='Create index.md file' .image-with-shadow width="900px" } We are now ready to start adding more content to our website. Let's do some exercises. -> ## Exercise: Add New Content to the Website -> Add a new section 'Description' to file `index.md` and add some description. -> 1. From the GitHub interface, edit file `index.md` and add a new section called `Description` to it, with some text about the project. -> 2. View the changes on the website. -> -> > ## Solution -> > 1. Edit `index.md` file to look something like: -> > -> > ~~~ -> > # Building Websites in GitHub -> > -> > ## Description -> > This is an example website built while learning how to use Jekyll and GitHub Pages. -> > ~~~ -> > {: .language-markdown } -> > -> > 2. Go to your website. It should now look like: - ![Add 'About' section to index.md file](../fig/first_index_page.png){: .image-with-shadow width="900px" } -> {: .solution } -{: .challenge } +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Add New Content to the Website + +Add a new section 'Description' to file `index.md` and add some description. + +1. From the GitHub interface, edit file `index.md` and add a new section called `Description` to it, with some text about the project. +2. View the changes on the website. + +:::::::::::::: solution + +## Solution + +1. Edit `index.md` file to look something like: + + ```markdown + # Building Websites in GitHub + + ## Description + This is an example website built while learning how to use Jekyll and GitHub Pages. + ``` + +2. Go to your website. It should now look like: + ![](fig/first_index_page.png){alt="Add 'About' section to index.md file" .image-with-shadow width="900px" } + + + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: Both the pages built from `README.md` and `index.md` have been served to us at the "root" of our site: @@ -155,7 +180,7 @@ the page we see when we point our browser to The actual name of this page is `index.html` (navigate to `https://YOURUSERNAME.github.io/REPONAME/index.html` to see this for yourself), -i.e. _the file `index.md` is converted by Jekyll to a page called `index.html`_. +i.e. *the file `index.md` is converted by Jekyll to a page called `index.html`*. As more Markdown files are added to your repository, the same process will automatically occur for those files too. @@ -172,7 +197,7 @@ we would need to point our browser at and `https://YOURUSERNAME.github.io/REPONAME/contact.html` for the page built from `contact.md`. -However, when linking **between pages of the same site** (_relative linking_), +However, when linking **between pages of the same site** (*relative linking*), GitHub Pages allows us to refer to the name of the original Markdown file, and handles the URL conversion for us. This means that, to link to `cake-recipes.html` from `index.html`, @@ -184,60 +209,78 @@ Relative links can point to files in other directories too: are both valid link targets (assuming the relevant files exist in your repository). -> ## Exercise: Create Links Between Pages -> -> Create a new file `about.md` and link to it from `index.md`. -> 1. From the GitHub interface, create a new Markdown file called `about.md` and add some content to it. -> 2. Add a link to `about.md` from `index.md`. -> 3. View the changes on the website. -> -> > ## Solution -> > -> > 1. Create a new file called `about.md` from the GitHub interface: -> > ![Create another page in GitHub called 'about.md'](../fig/github_create_another_file.png){: .image-with-shadow width="900px" } -> > Edit `about.md` file to look something like: -> > -> > ~~~ -> > # About -> > -> > ## Project -> > This research project is all about teaching you how to create websites with GitHub pages. -> > -> > ## Funders -> > We gratefully acknowledge funding from the XYZ Founding Council, under grant number 'abc'. -> > -> > ## Cite us -> > You can cite the project as: -> > -> > > *The Carpentries 2019 Annual Report. Zenodo. https://doi.org/10.5281/zenodo.3840372* -> > -> > ## Contact us -> > -> > - Email: [team@carpentries.org](mailto:team@carpentries.org) -> > - Twitter: [@thecarpentries](https://twitter.com/thecarpentries) -> > ~~~ -> > {: .language-markdown } -> > -> > Note how we used various Markdown syntax: quoted text (`>`), italic font (`*`) and external links -> > (a combination of square `[]` and round brackets `()` containing the link text and mailto or regular Web URLs respectively). -> > -> > 2. Edit `index.md` to add a link to `about.md`. -> > -> > ~~~ -> > # Building Websites in GitHub -> > -> > ## Description -> > This is an example website built while learning how to use Jekyll and GitHub Pages. -> > -> > More details about the project are available from the [About page](about). -> > ~~~ -> > {: .language-markdown } -> > -> > 3. Go to your website and click the link to 'About' page. It should look like: -> > ![Rendered contents of the 'about.md' page](../fig/about_page.png){: .image-with-shadow width="900px" } -> > -> > Note that the URL has '/about' appended to it - you can use this URL to access the 'About' page directly. -> {: .solution } -{: .challenge } - -{% include links.md %} +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Create Links Between Pages + +Create a new file `about.md` and link to it from `index.md`. + +1. From the GitHub interface, create a new Markdown file called `about.md` and add some content to it. +2. Add a link to `about.md` from `index.md`. +3. View the changes on the website. + +:::::::::::::: solution + +## Solution + +1. Create a new file called `about.md` from the GitHub interface: + ![](fig/github_create_another_file.png){alt="Create another page in GitHub called 'about.md'" .image-with-shadow width="900px" } + Edit `about.md` file to look something like: + + ```markdown + # About + + ## Project + This research project is all about teaching you how to create websites with GitHub pages. + + ## Funders + We gratefully acknowledge funding from the XYZ Founding Council, under grant number 'abc'. + + ## Cite us + You can cite the project as: + + > *The Carpentries 2019 Annual Report. Zenodo. https://doi.org/10.5281/zenodo.3840372* + + ## Contact us + + - Email: [team@carpentries.org](mailto:team@carpentries.org) + - Twitter: [@thecarpentries](https://twitter.com/thecarpentries) + ``` + + Note how we used various Markdown syntax: quoted text (`>`), italic font (`*`) and external links + (a combination of square `[]` and round brackets `()` containing the link text and mailto or regular Web URLs respectively). + +2. Edit `index.md` to add a link to `about.md`. + + ```markdown + # Building Websites in GitHub + + ## Description + This is an example website built while learning how to use Jekyll and GitHub Pages. + + More details about the project are available from the [About page](about). + ``` + +3. Go to your website and click the link to 'About' page. It should look like: + ![](fig/about_page.png){alt="Rendered contents of the 'about.md' page" .image-with-shadow width="900px" } + + Note that the URL has '/about' appended to it - you can use this URL to access the 'About' page directly. + + + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + + +:::::::::::::::::::::::::::::::::::::::: keypoints + +- GitHub Pages is a static site hosting service that takes files in various formats (Markdown, HTML, CSS, JavaScript, etc.) straight from a repository on GitHub, runs them through its website engine Jekyll, builds them into a website, and publishes them on the Web +- By convention, if you create a branch called `gh-pages` in your repository, it will automatically be published as a website by GitHub +- You can configure any branch of a repository to be used for website (it does not have to be `gh-pages`) +- GitHub publishes websites on special URLs formatted as 'https://GITHUB\_USERNAME.github.io/REPOSITORY\_NAME' + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + diff --git a/episodes/includes.md b/episodes/includes.md index 2e34d53d..f2facdd9 100644 --- a/episodes/includes.md +++ b/episodes/includes.md @@ -1,16 +1,22 @@ --- -title: "Reusing Blocks of Content" +title: Reusing Blocks of Content teaching: 35 exercises: 40 -questions: -- "How can I reuse the same chunks of material in multiple pages?" -objectives: -- "Create reusable blocks of content and insert them into pages" -keypoints: -- "The content of files in the `_includes/` directory can be inserted into a page with `{ % include file_name % }`" --- -{% include base_path.html %} + + +::::::::::::::::::::::::::::::::::::::: objectives + +- Create reusable blocks of content and insert them into pages + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: questions + +- How can I reuse the same chunks of material in multiple pages? + +:::::::::::::::::::::::::::::::::::::::::::::::::: In the previous episode, we discussed the benefits of using global and local variables @@ -19,43 +25,51 @@ However, repeated use of content in and across websites is usually not limited to individual values such as email addresses and social media handles. -> ## Exercise: What Gets Reused? -> -> Look at the two pages linked below, -> and browse some other pages on the same site. -> -> * [The Software Sustainability Institute][ssi-homepage] -> * [DiverseKids Book Store][diversekids] -> -> What content is being reused between pages on these sites? -> Pair up and compare your partner's notes with your own. -> Can you identify any common type(s) of content that is being reused in these sites? -> -> > ## Solution -> > -> > The Software Sustainability Institute website reuses many structural -> > elements, such as the **page header** -> > (containing the "top menu," the institute's logo, links to social media, etc) -> > and **footer** -> > (containing copyright and licensing information, -> > links to the privacy policy and accessibility statement, -> > a form to subscribe to the institute's newsletter, etc). -> > Elsewhere, blocks of text and images are reused in the main body -> > of multiple pages, e.g. -> > blog and news posts all end with a description of -> > how the reader can contact the SSI to discuss the content. -> > -> > The DiverseKids site has the same kind of shared header and footer -> > on each page: this is a common theme across most websites, -> > helping to improve navigation and other aspects of the user experience -> > and achieve consistent "branding" across the whole site. -> > The books listed under each category include a title, a price, -> > and cover image. -> > The category links themselves are also shared across each page, -> > probably generated from the existing categories of books in the collection, -> > and updated automatically when a category is added or removed. -> {: .solution } -{: .challenge } +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: What Gets Reused? + +Look at the two pages linked below, +and browse some other pages on the same site. + +- [The Software Sustainability Institute][ssi-homepage] +- [DiverseKids Book Store][diversekids] + +What content is being reused between pages on these sites? +Pair up and compare your partner's notes with your own. +Can you identify any common type(s) of content that is being reused in these sites? + +:::::::::::::: solution + +## Solution + +The Software Sustainability Institute website reuses many structural +elements, such as the **page header** +(containing the "top menu," the institute's logo, links to social media, etc) +and **footer** +(containing copyright and licensing information, +links to the privacy policy and accessibility statement, +a form to subscribe to the institute's newsletter, etc). +Elsewhere, blocks of text and images are reused in the main body +of multiple pages, e.g. +blog and news posts all end with a description of +how the reader can contact the SSI to discuss the content. + +The DiverseKids site has the same kind of shared header and footer +on each page: this is a common theme across most websites, +helping to improve navigation and other aspects of the user experience +and achieve consistent "branding" across the whole site. +The books listed under each category include a title, a price, +and cover image. +The category links themselves are also shared across each page, +probably generated from the existing categories of books in the collection, +and updated automatically when a category is added or removed. + + + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: The most commonly reused content is structural: menus and branding information used to present a consistent and recognisable interface to the user regardless @@ -68,13 +82,18 @@ if you need to update that content - changing the contact address, updating a price or picture associated with a listing, and so on - you need only change this information in one place for the update to be propagated across the whole site. -This is related to the __DRY__ (Don't Repeat Yourself) principle of +This is related to the **DRY** (Don't Repeat Yourself) principle of good practice in programming. ->## __DRY__ (Don't Repeat Yourself) Principle ->[DRY principle](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) ->is one of the basic principles of software development aimed at reducing repetition of information. -{: .callout} +::::::::::::::::::::::::::::::::::::::::: callout + +## **DRY** (Don't Repeat Yourself) Principle + +[DRY principle](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) +is one of the basic principles of software development aimed at reducing repetition of information. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: As far as we know, the sites linked in the previous exercise aren't built with Jekyll. @@ -90,99 +109,108 @@ To make these links appear above every page on our site, we could add the same code immediately after the YAML header of each Markdown file in our repository. But if we wanted to adjust the menu - adjust the navigation link target, add a new navigation link, remove a link, etc. - we would need to make the same adjustment on every page. -This is both time-consuming and error-prone: +This is both time-consuming and error-prone: it would be easy to accidentally mistype a link or forget to update one of the files. Instead, we can go some way to avoid this hassle by using some magic that Jekyll provides: `include` tags. To demonstrate this, we will save an HTML snippet for creating navigation links into a new file called `navigation.html` in a new folder called `_includes` within our repository. The folder `_includes` has special -meaning to Jekyll - it tells Jekyll where to look for code snippets that can be reused (included) in other parts of the website. +meaning to Jekyll - it tells Jekyll where to look for code snippets that can be reused (included) in other parts of the website. 1. Click "Create new file" under the "Add file" -dropdown on your repository homepage -2. In the "Name your file..." box, type `_includes/`. As you enter the "/" after the folder name "_includes", -the folder is automatically inserted in the path displayed in front of the box for naming the file you are adding. + dropdown on your repository homepage + +2. In the "Name your file..." box, type `_includes/`. As you enter the "/" after the folder name "\_includes", + the folder is automatically inserted in the path displayed in front of the box for naming the file you are adding. + 3. You can then name the file `navigation.html` and, when you commit the changes, - the `_includes` folder will have been added to your repository too. + the `_includes` folder will have been added to your repository too. + 4. Insert the following HTML snippet into `navigation.html` and commit the changes: + + ```html + {% raw %} + + + + +
HomeAbout
+
{% endraw %} + ``` + + The snippet will create a table with a single row with two links followed by a horizontal line separator. - ~~~ - {% raw %} - - - - -
HomeAbout
-
{% endraw %} - ~~~ - {: .language-html } -The snippet will create a table with a single row with two links followed by a horizontal line separator. 5. Now insert the following `include` directive at the beginning of `index.md`: - - ~~~ - {% raw %}--- - lesson-example: "https://carpentries.github.io/lesson-example/" - --- - - {% include navigation.html %} - - # Building Websites in GitHub - - ## Description - {{ site.description }} - - More details about the project are available from the [About page](about). - - See some [examples of our work]({{ page.lesson-example }}). - - Have any questions about what we do? [We'd love to hear from you!](mailto:{{ site.email }}){% endraw %} - ~~~ - {: .language-markdown } + + ```markdown + {% raw %}--- + lesson-example: "https://carpentries.github.io/lesson-example/" + --- + + {% include navigation.html %} + + # Building Websites in GitHub + + ## Description + {{ site.description }} + + More details about the project are available from the [About page](about). + + See some [examples of our work]({{ page.lesson-example }}). + + Have any questions about what we do? [We'd love to hear from you!](mailto:{{ site.email }}){% endraw %} + ``` Refresh the `index.html` page and, barring any typos, e.g. in the name of the file, you should see the navigation links on the top of the page. -![A page displaying the navigation links header](../fig/includes_navigation_links_header.png){: .image-with-shadow width="800px" } +![](fig/includes_navigation_links_header.png){alt='A page displaying the navigation links header' .image-with-shadow width="800px" } You can add the same `include` tag at the top of all the other Markdown files for your site to get the same navigation section displayed on every page. -> ## Exercise: Reuse Site Navigation -> -> Reuse the navigation snippet to add navigation links to the About page. -> -> > ## Solution -> > Insert the `include` directive at the top of `about.md` so that it now looks as follows: -> > -> >~~~ -> >{% raw %}{% include navigation.html %}{% endraw %} -> > -> ># About -> > -> >## Project -> > -> >{% raw %}{{ site.description }}{% endraw %} -> > -> >## Funders -> > -> >We gratefully acknowledge funding from the XYZ Founding Council, under grant number 'abc'. -> > -> >## Cite us -> > -> >You can cite the project as: -> > -> > > *The Carpentries 2019 Annual Report. Zenodo. https://doi.org/10.5281/zenodo.3840372* -> > -> >## Contact us -> > -> > - Email: [{% raw %}{{ site.email }}{% endraw %}](mailto:{% raw %}{{ site.email }}{% endraw %}) -> > - Twitter: [{% raw %}{{ site.twitter }}]({{ site.twitter }}{% endraw %}) -> > ~~~ -> > {: .language-markdown } -> {: .solution } -{: .challenge } +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Reuse Site Navigation + +Reuse the navigation snippet to add navigation links to the About page. + +:::::::::::::: solution + +## Solution + +Insert the `include` directive at the top of `about.md` so that it now looks as follows: + +```markdown +{% raw %}{% include navigation.html %}{% endraw %} + +# About + +## Project + +{% raw %}{{ site.description }}{% endraw %} + +## Funders + +We gratefully acknowledge funding from the XYZ Founding Council, under grant number 'abc'. + +## Cite us + +You can cite the project as: + + > *The Carpentries 2019 Annual Report. Zenodo. https://doi.org/10.5281/zenodo.3840372* + +## Contact us + + - Email: [{% raw %}{{ site.email }}{% endraw %}](mailto:{% raw %}{{ site.email }}{% endraw %}) + - Twitter: [{% raw %}{{ site.twitter }}]({{ site.twitter }}{% endraw %}) +``` + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: The `include` tag can be used to insert the Markdown or HTML contained in any file saved within `_includes` directory: provide the path to that file @@ -193,90 +221,109 @@ the `_includes` folder has a name beginning with an underscore to show that it has a special meaning to Jekyll. We will see another example of this shortly. -> ## Why Not Use Variables? -> -> We must place our blocks of content for inclusion in separate files because -> **Jekyll does not support substitution of variables within variables**. -> If you'd like to investigate further, -> you might try creating a global variable in your site's `_config.yml` -> which includes a call to another variable in its value, e.g. -> `social: "{% raw %}Follow us on [Twitter]({{site.twitter}}){% endraw %}"`, -> and using it in a page (`{% raw %}{{site.social}}{% endraw %}` for the example above). -{: .callout } +:::::::::::::::::::::::::::::::::::::::: callout + +## Why Not Use Variables? + +We must place our blocks of content for inclusion in separate files because +**Jekyll does not support substitution of variables within variables**. +If you'd like to investigate further, +you might try creating a global variable in your site's `_config.yml` +which includes a call to another variable in its value, e.g. +`social: "{% raw %}Follow us on [Twitter]({{site.twitter}}){% endraw %}"`, +and using it in a page (`{% raw %}{{site.social}}{% endraw %}` for the example above). + + +:::::::::::::::::::::::::::::::::::::::::::::::::: -## Reusing Footer +## Reusing Footer -The last line of `about.md` includes contact details - this is the kind of information you might want to reuse +The last line of `about.md` includes contact details - this is the kind of information you might want to reuse in multiple places throughout your site as a footer. -~~~ +```markdown ## Contact us - Email: [{% raw %}{{ site.email }}{% endraw %}](mailto:{% raw %}{{ site.email }}{% endraw %}) - Twitter: [{% raw %}{{ site.twitter }}{% endraw %}]({% raw %}{{ site.twitter }}{% endraw %}) -~~~ -{: .language-markdown } +``` -Let's convert the above Markdown snippet into HTML as shown below and reuse it in +Let's convert the above Markdown snippet into HTML as shown below and reuse it in `index.md` and `about.md` files. We will explain why we need the file to be in HTML rather than Markdown shortly. -~~~ +```html

Contact us

-~~~ -{: .language-html } -This HTML snippet will create a horizontal line separator followed by an unordered list with two elements: +``` + +This HTML snippet will create a horizontal line separator followed by an unordered list with two elements: a contact email address and the Twitter URL wrapped as links using the anchor tag. -> ## Exercise: Reuse Footer -> Create the footer inside the `_includes` folder containing the above HTML snippet and use -> the `include` directive to insert it at the bottom of `index.md` and ->`about.md` (making sure to remove the equivalent contact section from `about.md` to avoid repetition). -> -> > ## Solution -> > 1. Create a file called `footer.html` inside the `_includes` folder to contain the footer HTML snippet. -> > -> >2. Add the line: -> > -> > ~~~ -> > {% raw %}{% include footer.html %}{% endraw %} -> > ~~~ -> > {: .language-markdown } -> > -> > at the bottom of both `index.md` and `about.md` (replacing the equivalent contact section where present). -> > -> >After refreshing any of these two pages - you should see a horizontal +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Reuse Footer + +Create the footer inside the `_includes` folder containing the above HTML snippet and use +the `include` directive to insert it at the bottom of `index.md` and +`about.md` (making sure to remove the equivalent contact section from `about.md` to avoid repetition). + +:::::::::::::: solution + +## Solution + +1. Create a file called `footer.html` inside the `_includes` folder to contain the footer HTML snippet. + +2. Add the line: + + ```markdown + {% raw %}{% include footer.html %}{% endraw %} + ``` + +at the bottom of both `index.md` and `about.md` (replacing the equivalent contact section where present). + +After refreshing any of these two pages - you should see a horizontal line separating the main page content from the footer of the page which now contains contact information. -> > -> >![A page displaying contact links as footer](../fig/includes_contact_links_footer.png){: .image-with-shadow width="800px" } -> {: .solution } -{: .challenge } + +![](fig/includes_contact_links_footer.png){alt='A page displaying contact links as footer' .image-with-shadow width="800px" } + + + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: This is another example of how we can create a block of common content and reuse it in multiple pages on our site -by using Jekyll's `include` directive and placing code snippets in the `_includes` directory -(where Jekyll looks for them by name by convention). +by using Jekyll's `include` directive and placing code snippets in the `_includes` directory +(where Jekyll looks for them by name by convention). ## Reusing Link References - You can use `include` tags to help minimise the effort required to - keep links up-to-date across your site. - In the [Authoring with Markdown]({{relative_root_path}}/markdown#reference-style-links) section, - we learned about writing reference-style links in Markdown, - e.g. `[link text][link-target]` in the body of the file with a corresponding - `[link-target]: https://carpentries.org` link reference - (usually all such references are kept at the bottom of the file). - Using `include` tags, - the link references for every page on your site can be stored in a file in the - `_includes` folder (we recommend the name `_includes/links.md`) - and inserted into the end of each page. - With this approach, any time you need to update one of these link references, - e.g. if the URL changes to your host institute website, - you only need to change the URL in `_includes/links.md` to update the target - of all the relevant links across your site. - - -{% include links.md %} +You can use `include` tags to help minimise the effort required to +keep links up-to-date across your site. +In the [Authoring with Markdown](markdown#reference-style-links) section, +we learned about writing reference-style links in Markdown, +e.g. `[link text][link-target]` in the body of the file with a corresponding +`[link-target]: https://carpentries.org` link reference +(usually all such references are kept at the bottom of the file). +Using `include` tags, +the link references for every page on your site can be stored in a file in the +`_includes` folder (we recommend the name `_includes/links.md`) +and inserted into the end of each page. +With this approach, any time you need to update one of these link references, +e.g. if the URL changes to your host institute website, +you only need to change the URL in `_includes/links.md` to update the target +of all the relevant links across your site. + + + +:::::::::::::::::::::::::::::::::::::::: keypoints + +- The content of files in the `_includes/` directory can be inserted into a page with `{ % include file_name % }` + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + diff --git a/episodes/introduction.md b/episodes/introduction.md index f7ccc590..70af98d9 100644 --- a/episodes/introduction.md +++ b/episodes/introduction.md @@ -1,21 +1,25 @@ --- -title: "Introduction" +title: Introduction teaching: 30 exercises: 10 -questions: -- "What is static web content?" -- "Why should I use GitHub or GitLab Pages to create my website?" -objectives: -- "Explain what a static site generator does." -- "Choose the appropriate tool for a website/project." -keypoints: -- "A static site generator combines page-specific content with layout elements and styling information to construct individual static webpages." -- "GitHub Pages/GitLab Pages is a good choice for people who are already familiar with Git and GitHub/GitLab." -- "This approach can be used to create a relatively small website/blog on a limited budget." --- ## How Websites Work +::::::::::::::::::::::::::::::::::::::: objectives + +- Explain what a static site generator does. +- Choose the appropriate tool for a website/project. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: questions + +- What is static web content? +- Why should I use GitHub or GitLab Pages to create my website? + +:::::::::::::::::::::::::::::::::::::::::::::::::: + When we use a web browser to visit a page on the World-Wide Web, the browser asks for information from a server - a computer storing the data relevant to the site and configured to receive and respond to requests for that data. @@ -52,7 +56,7 @@ HTML documents tend to get verbose rather quickly. The simplest, valid HTML `Hello world` is: -~~~ +```html @@ -62,8 +66,7 @@ The simplest, valid HTML `Hello world` is:

Hello, World!

-~~~ -{: .language-html } +``` So as you can imagine, writing long HTML documents by hand is rather painful. Notice that we didn't specify anything about how and where the text should be displayed. @@ -72,46 +75,57 @@ To achieve this we would additionally need to include stylized tags or Cascading If you do not provide CSS instructions (either inside your HTML document or as a separate file), a web browser will make a best guess regarding the layout of HTML elements on the page based on its defaults. -> ## The Many Tags in HTML -> -> In the `Hello world` example above 5 different tags are used (`html`, `head`, `title`, `body` and `p`) in their open `<>` and closed `` form. -> We see also the special `doctype` tag that indicates the format and version of the document, in this case, [HTML(5)][html5-wikipedia]. -> -> Many other tags exist to define: -> - *structural elements*, such as `table`, `div`, `span`, `nav`, `section`; -> - *lists*, such as `ul` (for unordered lists) and `or` (for ordered lists); -> - *stylized elements*, such as `i`/`em` (for *italics/emphasis*), `b`/`strong` (for **bold**) and `u` (for underlined text); -> - *headings*, numbered from `h1` to `h6` for titles and progressively smaller sub-titles; -> - *media elements*, such as `img`, `video`, `audio` to embed rich media content; and -> - *links*, using the important `a` (anchor) tag to [link](#) to sections in the same page or other pages within the same or external websites. -> -> The [list of valid HTML tags][html5-tags] is rather extensive, -> covering a rich range of features powering today's [world wide web][www-wikipedia]. -{: .callout } - -> ## Exercise: Writing Basic HTML -> -> Given the stylized text: -> ->

Hello, World!

-> -> write the HTML that will produce the same result. -> **Hint** the big font is achieved by use of a heading. -> -> > ## Solution -> > -> > ~~~ -> >

Hello, World!

-> > ~~~ -> > {: .language-html } -> {: .solution } -{: .challenge } - -Let's write a more complex HTML example using a table showing the "Hello, World!" text in different languages that renders like: -![HTML table example](../fig/html-table.png){: .image-with-shadow width="600px" } +:::::::::::::::::::::::::::::::::::::::: callout + +## The Many Tags in HTML + +In the `Hello world` example above 5 different tags are used (`html`, `head`, `title`, `body` and `p`) in their open `<>` and closed `` form. +We see also the special `doctype` tag that indicates the format and version of the document, in this case, [HTML(5)][html5-wikipedia]. + +Many other tags exist to define: + +- *structural elements*, such as `table`, `div`, `span`, `nav`, `section`; +- *lists*, such as `ul` (for unordered lists) and `or` (for ordered lists); +- *stylized elements*, such as `i`/`em` (for *italics/emphasis*), `b`/`strong` (for **bold**) and `u` (for underlined text); +- *headings*, numbered from `h1` to `h6` for titles and progressively smaller sub-titles; +- *media elements*, such as `img`, `video`, `audio` to embed rich media content; and +- *links*, using the important `a` (anchor) tag to [link](#) to sections in the same page or other pages within the same or external websites. + +The [list of valid HTML tags][html5-tags] is rather extensive, +covering a rich range of features powering today's [world wide web][www-wikipedia]. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Writing Basic HTML + +Given the stylized text: + +

Hello, World!

+ +write the HTML that will produce the same result. +**Hint** the big font is achieved by use of a heading. + +:::::::::::::: solution + +## Solution + +```html +

Hello, World!

+``` + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +Let's write a more complex HTML example using a table showing the "Hello, World!" text in different languages that renders like: +![](fig/html-table.png){alt='HTML table example' .image-with-shadow width="600px" } The HTML to produce such a table looks like this (you can copy+paste the snippet into the HTML file you created in the previous example): -~~~ + +```html @@ -119,37 +133,35 @@ The HTML to produce such a table looks like this (you can copy+paste the snippet
LanguageText
EnglishHello, World!
PortugueseOlá, Mundo!
SerbianZdravo, svete!
-~~~ -{: .language-html } +``` -Each row is enclosed between **t**able **r**ow `` and `` tags. Within a row, `` and `` tags are used to contain **t**able **h**eadings +Each row is enclosed between **t**able **r**ow `` and `` tags. Within a row, `` and `` tags are used to contain **t**able **h**eadings (special table cells displayed in bold font), while regular **t**able **d**ata cells are contained within `` and `` tags. A similar example written using HTML lists would look as follows: -![HTML list example](../fig/html-list.png){: .image-with-shadow width="600px" } +![](fig/html-list.png){alt='HTML list example' .image-with-shadow width="600px" } -~~~ +```html
  • English: Hello, World!
  • French: Bonjour, le monde!
  • Portuguese: Olá, Mundo!
  • Serbian: Zdravo, svete!
-~~~ -{: .language-html } +``` -Here, we used **u**nordered **l**ist tags `
    ` and `
` to define a list with 4 items, each in turn wrapped in -individual **l**ist **i**tem (`
  • ` and `
  • `) tags. +Here, we used **u**nordered **l**ist tags `
      ` and `
    ` to define a list with 4 items, each in turn wrapped in +individual **l**ist **i**tem (`
  • ` and `
  • `) tags. ## Static vs Dynamic Sites -_Static_ pages are those whose contents are stored on a server in a state ready +*Static* pages are those whose contents are stored on a server in a state ready to be sent to any user who makes a request for that web page. When a request is made, the server only needs to send the information comprising that web page (such as HTML and CSS). Sites that do not change often, such as a website -containing one’s CV, are often stored as static sites. +containing one's CV, are often stored as static sites. -Conversely, _dynamic_ +Conversely, *dynamic* sites are those that have their pages generated when a user makes a request for a web page. Depending on when the request is made, the content might change; for example, clicking refresh when viewing a discussion in a web forum might result @@ -166,11 +178,9 @@ However, we still need a way to tell the generator how we want our content to look when it's displayed in the browser. For that, we will use a tool called Markdown, which we'll learn about in the next episode. -![Pages can be created in several ways: static server-side generation (where HTML is generated once on the server and doesn't -change thereafter), dynamic server-side generation (where the server can update and send new HTML based on requests from -the user's browser), and client-side generation (where parts of HTML pages are generated by the browser using Javascript code)](../fig/page-generation-js4ds.svg) +![](fig/page-generation-js4ds.svg){alt="Pages can be created in several ways: static server-side generation (where HTML is generated once on the server and doesn'tchange thereafter), dynamic server-side generation (where the server can update and send new HTML based on requests fromthe user's browser), and client-side generation (where parts of HTML pages are generated by the browser using Javascript code)"} -_Figure 1.1: Page Generation Alternatives. This figure is a modified version of the original published in [JavaScript for Data Science][js4ds], and is reproduced here with permission from the author._ +*Figure 1.1: Page Generation Alternatives. This figure is a modified version of the original published in [JavaScript for Data Science][js4ds], and is reproduced here with permission from the author.* Static-generated sites are a great choice when the information you want to display on a website is the same regardless of who visits your site @@ -192,31 +202,39 @@ Among other things this means that, unlike with static pages (see the rest of this lesson), you're unlikely to find cost-free platforms to help you deliver dynamic content. -> ## Exercise: The Perfect Tool for the Job -> -> Given the following types of websites, -> reason if a static site generator is an appropriate solution to implement them. -> -> - (1) A personal website with *About* and *Projects* sections -> - (2) A forum or discussion platform -> - (3) A community blog or news website -> - (4) A search engine (such as google.com) -> - (5) A wiki (such as wikipedia.com) -> - (6) An online book -> -> > ## Solution -> > -> > - (1) **personal website**: In most cases, **Yes**. This kind of content is typically written/edited by one person and meant to have a read-only access to visitors. -> > - (2) **forum or discussion**: Most likely **No**. Such website requires interactivity and ways to identify who wrote what content. -> > -> > For questions 3 and 5 the answer is both **Yes** and **No** depending on the requirements and necessary functionality. -> > -> > - (3) **blog/news**: A simple blog or news website, maintained by a small set of users, is perfectly achievable by using a static generator. For very large groups of content creators or if access to articles needs to be controlled individually, using a static generator will lead to difficult technical challenges. -> > - (4) **search engine**: Most often **No**. Implementing something as sophisticated as Google's search would be close to impossible with a static generator. There are ways to have a simple engine that searches across all pages produced by a static generator using indexing and making clever use of browser features but this approach has many limitations. -> > - (5) **wiki**: A simple wiki is perfectly doable with a static generator (e.g. [GitHub Wiki Pages](https://guides.github.com/features/wikis/)), however it becomes limiting as soon as its content needs to be edited or discussed by many users, as is the case of Wikipedia. -> > - (6) **online book**: Definitely **Yes**. Static generators are perfect for this type of website. They typically provide ways to avoid repeating content (variables and templates), automatic creation of a *Table Of Contents*, among other goodies. -> {: .solution } -{: .challenge } +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: The Perfect Tool for the Job + +Given the following types of websites, +reason if a static site generator is an appropriate solution to implement them. + +- (1) A personal website with *About* and *Projects* sections +- (2) A forum or discussion platform +- (3) A community blog or news website +- (4) A search engine (such as google.com) +- (5) A wiki (such as wikipedia.com) +- (6) An online book + +:::::::::::::: solution + +## Solution + +- (1) **personal website**: In most cases, **Yes**. This kind of content is typically written/edited by one person and meant to have a read-only access to visitors. +- (2) **forum or discussion**: Most likely **No**. Such website requires interactivity and ways to identify who wrote what content. + +For questions 3 and 5 the answer is both **Yes** and **No** depending on the requirements and necessary functionality. + +- (3) **blog/news**: A simple blog or news website, maintained by a small set of users, is perfectly achievable by using a static generator. For very large groups of content creators or if access to articles needs to be controlled individually, using a static generator will lead to difficult technical challenges. +- (4) **search engine**: Most often **No**. Implementing something as sophisticated as Google's search would be close to impossible with a static generator. There are ways to have a simple engine that searches across all pages produced by a static generator using indexing and making clever use of browser features but this approach has many limitations. +- (5) **wiki**: A simple wiki is perfectly doable with a static generator (e.g. [GitHub Wiki Pages](https://guides.github.com/features/wikis/)), however it becomes limiting as soon as its content needs to be edited or discussed by many users, as is the case of Wikipedia. +- (6) **online book**: Definitely **Yes**. Static generators are perfect for this type of website. They typically provide ways to avoid repeating content (variables and templates), automatic creation of a *Table Of Contents*, among other goodies. + + + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: ## GitHub Pages @@ -232,7 +250,7 @@ that you have to be familiar with (as shown in the diagram below). It may sound but we will explain most of these technologies in this lesson - we only don't cover CSS/Sass (styling language that gets compiled into CSS) and JavaScript/CoffeeScript (scripting language that gets compiled into JavaScript) in detail. -![Static websites in GitHub Pages technology overview diagram](../fig/jekyll-gh-pages-website-overview.svg){: width="700px" } +![](fig/jekyll-gh-pages-website-overview.svg){alt='Static websites in GitHub Pages technology overview diagram' width="700px" } First, we are going to set up a repository to store our files and learn more about how to author and format the content of our pages using HTML and Markdown, before configuring GitHub to display this content as a website using GitHub Pages. @@ -251,64 +269,85 @@ though it can be handy if you need to revert to old versions In this lesson we will be working with this folder on the web to control the website we will be creating. -> ## Setup a GitHub account -> Before you can create a repo, you will need to -> [create a GitHub account](https://github.com/join) -{: .callout} +::::::::::::::::::::::::::::::::::::::::: callout + +## Setup a GitHub account + +Before you can create a repo, you will need to +[create a GitHub account](https://github.com/join) + -Make sure to login with your GitHub account and visit https://github.com. +:::::::::::::::::::::::::::::::::::::::::::::::::: + +Make sure to login with your GitHub account and visit [https://github.com](https://github.com). Click the green "New" repo button on the left hand side of GitHub: -![New repository button](../fig/new_repo_button.png){: .image-with-shadow width="100px" } +![](fig/new_repo_button.png){alt='New repository button' .image-with-shadow width="100px" } **or** click the "+" menu in the upper righthand corner and choose "New Repository". -![Dropdown plus menu with new repository option highlighted](../fig/plus_new_repo.png){: .image-with-shadow width="200px" } +![](fig/plus_new_repo.png){alt='Dropdown plus menu with new repository option highlighted' .image-with-shadow width="200px" } Next you will need to fill in some info about your repository. -![Blank new repository page](../fig/blank_new_repo.png){: .image-with-shadow width="600px" } +![](fig/blank_new_repo.png){alt='Blank new repository page' .image-with-shadow width="600px" } In this lesson, we will be working on a general group website. You can imagine this website may be for your lab group, a specific project group, or another group you work with. Under the "Repository name" field type `group-website`. -![New repository - set name to group-website](../fig/set_repo_name.png){: .image-with-shadow width="600px" } +![](fig/set_repo_name.png){alt='New repository - set name to group-website' .image-with-shadow width="600px" } We can also add a description (for instance **Repo for learning how to make websites with Jekyll and GitHub pages**) so we know what this repo is when we find it again after the workshop. -![New repository - set description](../fig/set_repo_description.png){: .image-with-shadow width="600px" } +![](fig/set_repo_description.png){alt='New repository - set description' .image-with-shadow width="600px" } Under the "Initialize this repository with:" section we will check `Add a README file` and `Choose a license`. It is good practice to have a README file that gives more information about your repo and to set a license for your work. -![Initialise a new repository with a README and a licence file](../fig/initialize_readme_license.png){: .image-with-shadow width="600px" } +![](fig/initialize_readme_license.png){alt='Initialise a new repository with a README and a licence file' .image-with-shadow width="600px" } -for this example repository we’ll use the `Creative Commons Zero v1.0 Universal` (CC0) license, +for this example repository we'll use the `Creative Commons Zero v1.0 Universal` (CC0) license, which allows anyone to re-use and adapt the content of the repository without restriction, -but you may want to consider choosing something more restrictive when you’re building +but you may want to consider choosing something more restrictive when you're building your own website. -> ## Checkout Other Licences -> You may want to checkout [this lesson](https://swcarpentry.github.io/git-novice/11-licensing/index.html) or -> [GitHub's license documentation](https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository) -> for more information about possible licenses. -{: .callout} +::::::::::::::::::::::::::::::::::::::::: callout + +## Checkout Other Licences + +You may want to checkout [this lesson](https://swcarpentry.github.io/git-novice/11-licensing/index.html) or +[GitHub's license documentation](https://docs.github.com/en/free-pro-team@latest/github/creating-cloning-and-archiving-repositories/licensing-a-repository) +for more information about possible licenses. -![Set licence to CC0](../fig/set_CC0_license.png){: .image-with-shadow width="600px" } + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +![](fig/set_CC0_license.png){alt='Set licence to CC0' .image-with-shadow width="600px" } Once you've finished these steps you can click the "Create Repository" button to finish creating the repo. -![Filled in form with a create repository button](../fig/create_repository.png){: .image-with-shadow width="600px" } +![](fig/create_repository.png){alt='Filled in form with a create repository button' .image-with-shadow width="600px" } GitHub will then setup the repo and it should create the repo called `group-website` with a `README.md` file and a `LICENSE` file. -![Github repository for the group website](../fig/group_website_repo.png){: .image-with-shadow width="800px" } +![](fig/group_website_repo.png){alt='Github repository for the group website' .image-with-shadow width="800px" } + + [qwantz-easter-egg-ext]: https://chrome.google.com/webstore/detail/dinosaur-comics-easter-eg/bojkkeeefjmeogpgnlomodfkkfkfhabj -{% include links.md %} + +:::::::::::::::::::::::::::::::::::::::: keypoints + +- A static site generator combines page-specific content with layout elements and styling information to construct individual static webpages. +- GitHub Pages/GitLab Pages is a good choice for people who are already familiar with Git and GitHub/GitLab. +- This approach can be used to create a relatively small website/blog on a limited budget. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + diff --git a/episodes/layouts.md b/episodes/layouts.md index 51d65ab0..3e0f58ab 100644 --- a/episodes/layouts.md +++ b/episodes/layouts.md @@ -1,23 +1,26 @@ --- -title: "Page Layouts" +title: Page Layouts teaching: 30 exercises: 25 -questions: -- "How can I design the layout for all pages on my site?" -- "Where can I find pre-built themes for my site?" -- "How can I create new layouts based on those I already have?" -objectives: -- "Apply a template layout to a page" -- "Find and implement pre-existing themes to determine the style of a site" -- "Create new page templates that inherit from existing layouts" -keypoints: -- "Files in the `_layouts/` directory can be used as page templates" -- "The structure of a page is determined by the `layout` field in the page front matter" -- "You can find many pre-existing themes for sites on the Internet" -- "You can avoid duplicated effort by basing new layouts on previous ones" --- -{% include base_path.html %} + + +::::::::::::::::::::::::::::::::::::::: objectives + +- Apply a template layout to a page +- Find and implement pre-existing themes to determine the style of a site +- Create new page templates that inherit from existing layouts + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: questions + +- How can I design the layout for all pages on my site? +- Where can I find pre-built themes for my site? +- How can I create new layouts based on those I already have? + +:::::::::::::::::::::::::::::::::::::::::::::::::: Elements that will appear on every page across our website, like the banner image we included in our pages in the previous section, @@ -27,7 +30,7 @@ these structural elements do not change from page to page. As such, although the `include` tags reduce the pain endured when adjusting that repeated content, it is not good practice to `include` the same content over and over again. -This structure can instead be defined within the _layout_ of the pages of the site. +This structure can instead be defined within the *layout* of the pages of the site. Common elements found in a layout are logos, @@ -51,10 +54,9 @@ which we will save in a file `_layouts/default.html`. Having defined our navigational links in a separate file, we will start with a layout file that only includes these links: -~~~ +```markdown {% raw %}{% include navigation.html %}{% endraw %} -~~~ -{: .language-markdown } +``` You have just defined the first layout for pages on your site. Congratulations! @@ -70,12 +72,11 @@ the bad: all the other page content has disappeared! The page content is missing because we haven't yet told Jekyll where to put it. To do that we need to add the special `content` variable into the layout file: -~~~ +```markdown {% raw %}{% include navigation.html %}{% endraw %} {% raw %}{{ content }}{% endraw %} -~~~ -{: .language-markdown } +``` We can use the `content` variable to tell Jekyll where it should place **all the content defined in the Markdown of the page** within this layout. @@ -85,48 +86,59 @@ we now see the page content has returned but we have two more problems: the styling of our pages has changed (for the worse) and the navigational links appear twice! -![A page displaying the navigation section twice.](../fig/layouts_double_navigation.png){: .image-with-shadow width="800px" } +![](fig/layouts_double_navigation.png){alt='A page displaying the navigation section twice.' .image-with-shadow width="800px" } The duplication is happening because the `{% raw %}{% include navigation.html %}{% endraw %}` tag is still present in `index.md`. -> ## Exercise: Cleaning Up -> -> Remove the include tag for navigation links from all the pages of your site (e.g. `about.md`), -> and set every page to use the `default` layout. -> -{: .challenge } +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Cleaning Up + +Remove the include tag for navigation links from all the pages of your site (e.g. `about.md`), +and set every page to use the `default` layout. + +:::::::::::::::::::::::::::::::::::::::::::::::::: Now that we have cleaned the duplicated navigation links, we may want to add another element to our layout. In a similar manner to the navigation links appearing on every page, we may want a common footer to appear too. -> ## Exercise: Expanding the Layout -> -> Expand the layout we have just created to include a footer element at the bottom defined in `_includes/footer.html` ->so that it appears at the end of each page that uses this layout. -> -> > ## Solution -> > Include the footer file in the `_layouts/default.html` layout file as follows: -> > -> > ~~~ -> > {% raw %}{% include navigation.html %} -> > -> > {{ content }} -> > -> > {% include footer.html %}{% endraw %} -> > ~~~ -> > {: .language-html } -> > -> > Remove all references to `footer.html` from pages as they will now be included via the layout. -> > Check that this works by reloading any of the pages that use the `default` layout. You should see a footer at -> > the bottom of the page. -> {: .solution } -{: .challenge } +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Expanding the Layout + +Expand the layout we have just created to include a footer element at the bottom defined in `_includes/footer.html` +so that it appears at the end of each page that uses this layout. + +:::::::::::::: solution + +## Solution + +Include the footer file in the `_layouts/default.html` layout file as follows: + +```html +{% raw %}{% include navigation.html %} + +{{ content }} + +{% include footer.html %}{% endraw %} +``` + +Remove all references to `footer.html` from pages as they will now be included via the layout. +Check that this works by reloading any of the pages that use the `default` layout. You should see a footer at +the bottom of the page. + + + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: ## HTML Structure, Metadata and a Default Layout + Before we defined a layout for our pages, -Jekyll used a _default theme_ to style the site. +Jekyll used a *default theme* to style the site. That default has been overwritten now that we applied a layout file to our site and that means, if we want to use our own customised layouts, @@ -135,8 +147,8 @@ There is still more to learn about page layouts, so we will come back to this issue of styling at the end of the episode. You might recall from -[the introduction]({{ relative_root_path }}{% link _episodes/introduction.md %}#hello-world-in-html) -to this tutorial, that a _valid_ HTML page consists of more than +[the introduction]({{ relative\_root\_path }}{% link \_episodes/introduction.md %}#hello-world-in-html) +to this tutorial, that a *valid* HTML page consists of more than only the content we want to display. We haven't written these extra elements (``, ``, ``, etc) in our layout file: but there are some advantages to defining these yourself: @@ -159,38 +171,42 @@ It is common practice to define the structural HTML elements of your site's page inside a `_layouts/default.html` file. This file defines the bare minimum layout your pages should have. -> ## Exercise: Adding HTML Structural Elements to Default Layout -> -> Modify the default layout file `_layouts/default.html` with the following content: -> -> ~~~ -> {% raw %} -> -> -> -> {{ page.title }} -> -> -> {% include navigation.html %} ->

    {{ page.title }}

    ->
    -> {{ content }} ->
    -> {% include footer.html %} -> -> {% endraw %} -> ~~~ -> {: .language-html } -> -> What do you notice has changed about the pages that use this layout? -> -> > ## Solution -> > -> > After updating the layout, -> > each page includes the page title displayed twice. -> > -> {: .solution } -{: .challenge } +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Adding HTML Structural Elements to Default Layout + +Modify the default layout file `_layouts/default.html` with the following content: + +```html +{% raw %} + + + + {{ page.title }} + + + {% include navigation.html %} +

    {{ page.title }}

    +
    + {{ content }} +
    + {% include footer.html %} + +{% endraw %} +``` + +What do you notice has changed about the pages that use this layout? + +:::::::::::::: solution + +## Solution + +After updating the layout, +each page includes the page title displayed twice. + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: Note that we have also included some additional HTML elements in our default layout - the display of the page title as level-one heading and wrapping the main page content within `
    ` and `
    ` tags. @@ -207,7 +223,7 @@ the Markdown content of our pages and instead define the title in the page front matter. For example, `about.md` should look like this after the change: -~~~ +```markdown --- layout: default title: About @@ -226,8 +242,7 @@ We gratefully acknowledge funding from the XYZ Founding Council, under grant num You can cite the project as: > *The Carpentries 2019 Annual Report. Zenodo. https://doi.org/10.5281/zenodo.3840372* -~~~ -{: .language-markdown } +``` ## Layout Inheritance @@ -236,7 +251,7 @@ we define for a site, Jekyll allows for layouts to be based on other layouts, which can be based on other layouts, and so on. -This is referred to as _layout inheritance_, +This is referred to as *layout inheritance*, and is refreshingly easy to use. For example, let's say we want to create a slightly different @@ -245,48 +260,46 @@ To do so, we first need to upload a banner image to our repository and create a `_includes/banner.html` to include the banner image: 1. To add a pre-made banner image, click "Create new file" under the "Add file" -dropdown on your repository homepage, + dropdown on your repository homepage, 2. In the "Name your file..." box, type `images/`. - The folder name should be automatically inserted in the path displayed - next to this box for naming the file. It is good practice to store all image files in a common folder. + The folder name should be automatically inserted in the path displayed + next to this box for naming the file. It is good practice to store all image files in a common folder. 3. You can then leave the file blank and name it `.gitkeep`. - When you commit the changes, the `images` folder will have been - added to your repository. We will be uploading our banner image to this folder in a moment. - Unfortunately GitHub does not provide a way to create a new folder - while uploading existing files, only while creating new ones. - When making these blank files, - which exist only to allow the existence of their parent repository, - it is traditional to call them `.gitkeep`. + When you commit the changes, the `images` folder will have been + added to your repository. We will be uploading our banner image to this folder in a moment. + Unfortunately GitHub does not provide a way to create a new folder + while uploading existing files, only while creating new ones. + When making these blank files, + which exist only to allow the existence of their parent repository, + it is traditional to call them `.gitkeep`. 4. Now [download this banner image that we will add to our pages][banner-image] - save it with the name `site_banner.png` and - upload the file to your newly-created `images` folder on GitHub: - you can do this by navigating into the folder and choosing - "Upload files" from the "Add file" dropdown you used before. + save it with the name `site_banner.png` and + upload the file to your newly-created `images` folder on GitHub: + you can do this by navigating into the folder and choosing + "Upload files" from the "Add file" dropdown you used before. Now that the banner image is available in our site repository, add the HTML file `_includes/banner.html` with the following content: -~~~ +```html Group Website banner -~~~ -{: .language-html } +``` Next, we need to create a new layout file `_layouts/home.html` and then set it to inherit from the default layout by adding YAML front matter specifying the `layout` (of the layout file) to be `default`. -~~~ +```html {% raw %}--- layout: default ---{% endraw %} -~~~ -{: .language-html } +``` We can then add any extentions to the new layout `home.html` that will be applied on top of the default layout. This is what `_layouts/home.html` file should look like: -~~~ +```html {% raw %}--- layout: default --- @@ -294,21 +307,25 @@ layout: default {% include banner.html %} {{ content }}{% endraw %} -~~~ -{: .language-html } +``` -> ## Defining a Layout for a Layout -> Note how layouts can be applied not only to regular pages but -> also to other layouts, effectively making a layout -> inherit from another layout. -{: .callout } +:::::::::::::::::::::::::::::::::::::::: callout + +## Defining a Layout for a Layout + +Note how layouts can be applied not only to regular pages but +also to other layouts, effectively making a layout +inherit from another layout. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: Finally, we can now update the layout of the home page to be `home` instead of `default` by modifying the YAML front matter. If you reload the home page now, you should now see that it has all of the structure provided in `default` layout as well as the banner image included from the `home` layout. -![Home page with inherited layout](../fig/layouts_homepage_layout.png){: .image-with-shadow width="800px" } +![](fig/layouts_homepage_layout.png){alt='Home page with inherited layout' .image-with-shadow width="800px" } The purpose of this approach, defining the core structure that will be common to every page across the site in a default layout, @@ -318,27 +335,29 @@ Whenever we want to update something about the styling or structure of our site, we should only need to make that change in a single file and let it propagate to all the relevant pages. -> ## We Can't Include Link References in the Layout -> -> In the previous section, -> [we recommended that you `include` a file of references]({{ relative_root_path }}{% link _episodes/includes.md %}#reusing-link-references) -> for the links on your site. -> Unfortunately, you cannot add this `{% raw %}{% include links.md %}{% endraw %}` -> tag to the default layout of your site to prevent you from needing to -> add it at the bottom of every page. -> This is a result of [the order of Jekyll's rendering process][jekyll-rendering], -> which constructs the HTML of the page content in isolation -> _before_ constructing the HTML of the relevant layout(s) and nesting it inside. -> If the link references are included in the layout rather than the content, -> those references will not be available while the content is converted to HTML -> and the links will not render correctly. -> It is annoying to have to remember to add -> `{% raw %}{% include links.md %}{% endraw %}` -> to the end of every page's Markdown, -> but less annoying than having to manually edit the same link reference in -> multiple locations throughout the site. -> -{: .callout} +::::::::::::::::::::::::::::::::::::::::: callout + +## We Can't Include Link References in the Layout + +In the previous section, +[we recommended that you `include` a file of references]({{ relative\_root\_path }}{% link \_episodes/includes.md %}#reusing-link-references) +for the links on your site. +Unfortunately, you cannot add this `{% raw %}{% include links.md %}{% endraw %}` +tag to the default layout of your site to prevent you from needing to +add it at the bottom of every page. +This is a result of [the order of Jekyll's rendering process][jekyll-rendering], +which constructs the HTML of the page content in isolation +*before* constructing the HTML of the relevant layout(s) and nesting it inside. +If the link references are included in the layout rather than the content, +those references will not be available while the content is converted to HTML +and the links will not render correctly. +It is annoying to have to remember to add +`{% raw %}{% include links.md %}{% endraw %}` +to the end of every page's Markdown, +but less annoying than having to manually edit the same link reference in +multiple locations throughout the site. + +:::::::::::::::::::::::::::::::::::::::::::::::::: ## Using Pre-Existing Layouts From a Theme @@ -367,4 +386,15 @@ Reusing pre-existing themes designed by professional web designers helps you focus more on the **content** of your site, which you can write using more user-friendly and human-readable Markdown. -{% include links.md %} + + +:::::::::::::::::::::::::::::::::::::::: keypoints + +- Files in the `_layouts/` directory can be used as page templates +- The structure of a page is determined by the `layout` field in the page front matter +- You can find many pre-existing themes for sites on the Internet +- You can avoid duplicated effort by basing new layouts on previous ones + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + diff --git a/episodes/markdown.md b/episodes/markdown.md index fdc57704..26e3d0a6 100644 --- a/episodes/markdown.md +++ b/episodes/markdown.md @@ -1,29 +1,36 @@ --- -title: "Authoring With Markdown" +title: Authoring With Markdown teaching: 20 exercises: 15 -questions: -- "How can I write content for my webpages?" -- "How do I link to other pages?" -objectives: -- "Create simple pages with formatted text" -keypoints: -- "Markdown is an relatively easy way to write formatted text" --- -# Markdown -Markdown is a language used to simplify writing HTML. -Plain text characters like # and * are used in place of HTML tags. +## Markdown + +::::::::::::::::::::::::::::::::::::::: objectives + +- Create simple pages with formatted text + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: questions + +- How can I write content for my webpages? +- How do I link to other pages? + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +Markdown is a language used to simplify writing HTML. +Plain text characters like # and \* are used in place of HTML tags. These characters are then processed by Jekyll (or another script or application) and transformed into HTML tags. -As the name Markdown suggests, +As the name Markdown suggests, the language has been trimmed *down* to a minimum. -The most frequently used elements, like -headings, -paragraphs, -lists, -tables -and basic text formatting (i.e. bold, italic) +The most frequently used elements, like +headings, +paragraphs, +lists, +tables +and basic text formatting (i.e. bold, italic) are part of Markdown. Markdown's simplified syntax keeps content human-readable. This is one reason it is a preferred language for formatted user input on web sites like: @@ -32,8 +39,8 @@ This is one reason it is a preferred language for formatted user input on web si - [GitHub](https://github.com/) - [GitLab](https://about.gitlab.com/) +## Where to Start Writing Markdown? -# Where to Start Writing Markdown? A lot of tools for rendering Markdown source code exist. Rendering is the process of generating a nice view of the content using the style information included in the source text. @@ -46,54 +53,56 @@ The image below shows the projects default view. This view includes a rendered view of the content inside the file `README.md`. Your project should look quite similar except for the red circle around the pencil symbol. -![On the homepage of a GitHub repository, the edit button is positioned to the top right of the README preview](../fig/group_website_repo_edit.png){: .image-with-shadow width="900px" } - +![](fig/group_website_repo_edit.png){alt='On the homepage of a GitHub repository, the edit button is positioned to the top right of the README preview' .image-with-shadow width="900px" } Click on that pencil symbol to open an editing interface of your project's `README.md` file. Once we've clicked the pencil symbol, GitHub will open that file in the editing interface. -![Editing interface of the group websites README file](../fig/group_website_readme_edit.png){: .image-with-shadow width="900px" } +![](fig/group_website_readme_edit.png){alt='Editing interface of the group websites README file' .image-with-shadow width="900px" } -We can change the content and have a look at the rendered view by clicking the _Preview changes_ tab. +We can change the content and have a look at the rendered view by clicking the *Preview changes* tab. -![Preview of the rendered content of the group websites README file](../fig/group_website_readme_render.png){: .image-with-shadow width="900px" } +![](fig/group_website_readme_render.png){alt='Preview of the rendered content of the group websites README file' .image-with-shadow width="900px" } Let's add `Some **bold** font` and see what happens when we preview it using the preview tab. If you check the "Show diff" box on the upper-right hand side, GitHub will show green vertical bars visually highlighting the new content. -To save the content to the file `README.md`, scroll down a bit and search for a _Commit changes_ menu +To save the content to the file `README.md`, scroll down a bit and search for a *Commit changes* menu at the bottom of the page. After having changed something, the commit menu looks like this: -![Commit menu for changes done in the GitHub web interface is located at the bottom of the website](../fig/group_website_readme_commit.png){: .image-with-shadow width="900px" } +![](fig/group_website_readme_commit.png){alt='Commit menu for changes done in the GitHub web interface is located at the bottom of the website' .image-with-shadow width="900px" } + +::::::::::::::::::::::::::::::::::::::::: callout + +### Writing a Commit Message -> ## Writing a Commit Message -> -> A commit message is a short, descriptive, and specific comment that will help us remember later on what we did and why. -> When editing in the Github interface, it will suggest a vague message about which file you've updated or added. -> It is best practice to change this message to a short but more informative message about what in the file has changed. -> This more descriptive message will make it much easier if future you needs to go looking through the history -> for which commit made a specific change. -> You can find more about writing commit message in [the Software Carpentry _Version Control with Git_ lesson](https://swcarpentry.github.io/git-novice/04-changes/index.html). -> -{: .callout} +A commit message is a short, descriptive, and specific comment that will help us remember later on what we did and why. +When editing in the Github interface, it will suggest a vague message about which file you've updated or added. +It is best practice to change this message to a short but more informative message about what in the file has changed. +This more descriptive message will make it much easier if future you needs to go looking through the history +for which commit made a specific change. +You can find more about writing commit message in [the Software Carpentry *Version Control with Git* lesson](https://swcarpentry.github.io/git-novice/04-changes/index.html). + +:::::::::::::::::::::::::::::::::::::::::::::::::: Commit this change to the `main` branch. -# Writing Markdown +## Writing Markdown Now that we know about the editing interface and preview tab of our projects `README.md` we can use it as a text editor and investigate selected Markdown features. Our `README.md` already contains vanilla text and two formatting features: + - Heading `# group-website` - Emphasis using `**bold**`. -Let's learn some more Markdown by adding some formatting and +Let's learn some more Markdown by adding some formatting and see what happens when we preview it using the preview tab. Add the following to your `README.md` file. -~~~ +```markdown # group-website Repo for learning how to make websites with Jekyll and GitHub pages @@ -111,154 +120,192 @@ are caused by two trailing spaces at the end of a line. - Software Carpentry - Data Carpentry - Library Carpentry -~~~ -{: .language-markdown } +``` You can then click the preview tab again to see how the formatting renders. -![Preview of the formatting added to the README](../fig/markdown_preview_formatting.png){: .image-with-shadow width="900px" } +![](fig/markdown_preview_formatting.png){alt='Preview of the formatting added to the README' .image-with-shadow width="900px" } If you click the `Show diff` checkbox in the right corner, GitHub will include a preview of differences too - the green bar indicates added lines, the red bar indicates deleted lines, and yellow - lines that have been modified. -> ## Markdown Trailing Spaces Are Meaningful -> -> In the example above there are two spaces at the end of `Line breaks `. -> These introduce what is called a **hard line break**, causing that paragraph to -> continue in the next line by adding a `
    ` to the generated HTML. -> -> If you break the line in a markdown file but don't include the two trailing spaces -> the generated HTML will continue in the same line **without** introducing a `
    `. -> This is called a **soft line break**. -> -> In some cases you may find that **soft line breaks** do introduce a `
    `. -> This can happen when using different [markdown flavors](#markdown-flavours). -> -> See for instance: -> ~~~ -> Soft line -> break -> -> Hard line -> break -> ~~~ -> {: .language-markdown } -> -> That produces: -> -> ![Difference between soft and hard breaks](../fig/soft_hard_markdown_line_break.png){: .image-with-shadow width="200px" } -> -{: .callout} +::::::::::::::::::::::::::::::::::::::::: callout + +### Markdown Trailing Spaces Are Meaningful + +In the example above there are two spaces at the end of `Line breaks `. +These introduce what is called a **hard line break**, causing that paragraph to +continue in the next line by adding a `
    ` to the generated HTML. + +If you break the line in a markdown file but don't include the two trailing spaces +the generated HTML will continue in the same line **without** introducing a `
    `. +This is called a **soft line break**. + +In some cases you may find that **soft line breaks** do introduce a `
    `. +This can happen when using different [markdown flavors](#markdown-flavours). + +See for instance: + +```markdown +Soft line +break + +Hard line +break +``` + +That produces: + +![](fig/soft_hard_markdown_line_break.png){alt='Difference between soft and hard breaks' .image-with-shadow width="200px" } + +:::::::::::::::::::::::::::::::::::::::::::::::::: To keep this addition to our `README.md` we need to commit these changes to save them. Scroll down to the bottom of the page, add a commit message if you wish, and then commit to the `main` branch. -![Committing the formatting added to the README](../fig/committing_formatting_addition_to_readme.png){: .image-with-shadow width="800px" } +![](fig/committing_formatting_addition_to_readme.png){alt='Committing the formatting added to the README' .image-with-shadow width="800px" } Let's do an exercise to try out writing more markdown. -> ## Exercise: Try Out Markdown -> Use [this cheatsheet][github-flavored-markdown] to add the following to your `README.md`: -> -> - Another second level heading -> - Some text under that second level heading that includes an link and ~~strikethrough~~ text. -> - A third level heading -> - A numbered list -> - Bonus: Add this image -> -> > ## Example Solution -> > For example your markdown might look like the following: -> > ~~~ -> > ## More info on the lesson -> > You can find this lesson [here](https://carpentries-incubator.github.io/jekyll-pages-novice/). -> > -> > ### Four reasons you should learn Markdown: -> > -> > 1. Less formatting than HTML -> > 2. Easy to read even with formatting -> > 3. Commonly used for websites and software development -> > 4. We ~~don't~~ use it in The Carpentries -> > -> > ![Carpentries Logo](https://github.com/carpentries/carpentries.org/raw/main/images/TheCarpentries-opengraph.png) -> > ~~~ -> > {: .language-markdown } -> > ![Rendered solution to the Markdown exercise](../fig/markdown_exercise.png){: .image-with-shadow width="800px" } -> > -> {: .solution } -{: .challenge } - - -> ## Reference-Style Links -> -> Up to now, we have used _inline-style_ links which have the URL inline with the description text, for example: -> -> ~~~ -> [Carpentries Webpage](https://carpentries.org/) -> ~~~ -> {: .language-markdown } -> -> If you use a link more than once, consider using so called _reference-style_ links instead. -> Reference-style links reference the URL via a label. -> The label goes into square brackets `[ ]` right after the description text of the link and -> then later, usually at the bottom of the page, you can connect that label to the url it references to complete the link. -> This looks like: -> ~~~ -> [Carpentries Webpage][carpentries] -> -> [carpentries]: https://carpentries.org/ -> ~~~ -> {: .language-markdown } -> -> and helps to follow the [DRY principle][dry-principle], avoiding redundant specification of information. -> -{: .callout} - -> ## Note about image use and attribution -> When using images on your website that you don't own, it's important to reuse the -content responsibly. -> This means ensuring that the image owner has given permission for the image to be reused and that the image includes appropriate attribution to the owner. -> If you're unsure about the availability of an image you can always contact the owner or check if a license is provided alongside the image which may include conditions for reuse. -> Anyone can re-use and edit Public Domain images so searching for images in the public domain can be a good way to find images for your website. -> However, it is still good practice to give credit when possible, even for public domain images. -{: .callout } +:::::::::::::::::::::::::::::::::::::: challenge + +### Exercise: Try Out Markdown + +Use [this cheatsheet][github-flavored-markdown] to add the following to your `README.md`: + +- Another second level heading +- Some text under that second level heading that includes an link and ~~strikethrough~~ text. +- A third level heading +- A numbered list +- Bonus: Add this image [https://raw.githubusercontent.com/carpentries/carpentries.org/main/images/TheCarpentries-opengraph.png](https://raw.githubusercontent.com/carpentries/carpentries.org/main/images/TheCarpentries-opengraph.png) + +:::::::::::::: solution + +### Example Solution + +For example your markdown might look like the following: + +```markdown +## More info on the lesson +You can find this lesson [here](https://carpentries-incubator.github.io/jekyll-pages-novice/). + +### Four reasons you should learn Markdown: + +1. Less formatting than HTML +2. Easy to read even with formatting +3. Commonly used for websites and software development +4. We ~~don't~~ use it in The Carpentries + +![Carpentries Logo](https://github.com/carpentries/carpentries.org/raw/main/images/TheCarpentries-opengraph.png) +``` + +![](fig/markdown_exercise.png){alt='Rendered solution to the Markdown exercise' .image-with-shadow width="800px" } + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::::: callout + +### Reference-Style Links + +Up to now, we have used *inline-style* links which have the URL inline with the description text, for example: + +```markdown +[Carpentries Webpage](https://carpentries.org/) +``` + +If you use a link more than once, consider using so called *reference-style* links instead. +Reference-style links reference the URL via a label. +The label goes into square brackets `[ ]` right after the description text of the link and +then later, usually at the bottom of the page, you can connect that label to the url it references to complete the link. +This looks like: + +```markdown +[Carpentries Webpage][carpentries] + +[carpentries]: https://carpentries.org/ +``` + +and helps to follow the [DRY principle][dry-principle], avoiding redundant specification of information. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: callout + +### Note about image use and attribution + +When using images on your website that you don't own, it's important to reuse the +content responsibly. +This means ensuring that the image owner has given permission for the image to be reused and that the image includes appropriate attribution to the owner. +If you're unsure about the availability of an image you can always contact the owner or check if a license is provided alongside the image which may include conditions for reuse. +Anyone can re-use and edit Public Domain images so searching for images in the public domain can be a good way to find images for your website. +However, it is still good practice to give credit when possible, even for public domain images. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: We will continue to use Markdown and learn more throughout the rest of the lesson. Though later we will find we need HTML again for some features. -> ## Markdown Cheatsheet -> -> Markdown offers a variety of formatting features. -> Have a look at this [cheatsheet][github-flavored-markdown] to get an overview or look things up. -{: .callout} - -> ## Markdown Flavours ->The initial description of Markdown was informal and contained certain ambiguities so over the years [different Markdown ->implementations and syntax variations](https://github.com/commonmark/commonmark-spec/wiki/markdown-flavors) (often referred to as "flavours") ->appeared to support various syntax features and extensions. As a consequence, the syntax from one variant may not ->be interpreted as expected in another - you have to be aware which one is being used by a particular platform. Here are ->a few well-known variants: -> - [GitHub-flavored Markdown][github-flavored-markdown] (used on this lesson and by GitHub) -> - [GitLab-flavored Markdown][gitlab-flavored-markdown] (used by GitLab) -> - [Kramdown][kramdown] (a fast, Ruby, open source implementation released under the MIT licence) -{: .callout} - -> ## Optional Exercise: Add Your Repository Details to CodiMD -> -> If your instructors are using _CodiMD_ (or _HackMD_ or any other Markdown-based shared document platform) -> to take notes during this workshop, -> use Markdown syntax to add a link in that document to the repository you are using -> to follow along with this lesson. -> The link text should be your GitHub username, and the target your repository. -> Your instructors will direct you towards the appropriate location in the -> document to add your link. -> -{: .challenge } - ->## More Markdown Features -> Check out our [Extras page on Markdown](../more_markdown/index.html) for a more comprehensive overview of -> Markdown, including how to create fenced code blocks -> and do syntax highlighting for various languages. -{: .callout} - - -{% include links.md %} +::::::::::::::::::::::::::::::::::::::::: callout + +### Markdown Cheatsheet + +Markdown offers a variety of formatting features. +Have a look at this [cheatsheet][github-flavored-markdown] to get an overview or look things up. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::::: callout + +### Markdown Flavours + +The initial description of Markdown was informal and contained certain ambiguities so over the years [different Markdown +implementations and syntax variations](https://github.com/commonmark/commonmark-spec/wiki/markdown-flavors) (often referred to as "flavours") +appeared to support various syntax features and extensions. As a consequence, the syntax from one variant may not +be interpreted as expected in another - you have to be aware which one is being used by a particular platform. Here are +a few well-known variants: + +- [GitHub-flavored Markdown][github-flavored-markdown] (used on this lesson and by GitHub) +- [GitLab-flavored Markdown][gitlab-flavored-markdown] (used by GitLab) +- [Kramdown][kramdown] (a fast, Ruby, open source implementation released under the MIT licence) + + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::: challenge + +### Optional Exercise: Add Your Repository Details to CodiMD + +If your instructors are using *CodiMD* (or *HackMD* or any other Markdown-based shared document platform) +to take notes during this workshop, +use Markdown syntax to add a link in that document to the repository you are using +to follow along with this lesson. +The link text should be your GitHub username, and the target your repository. +Your instructors will direct you towards the appropriate location in the +document to add your link. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::::: callout + +### More Markdown Features + +Check out our [Extras page on Markdown](more_markdown/index.html) for a more comprehensive overview of +Markdown, including how to create fenced code blocks +and do syntax highlighting for various languages. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + + +:::::::::::::::::::::::::::::::::::::::: keypoints + +- Markdown is an relatively easy way to write formatted text + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + diff --git a/episodes/starting-jekyll.md b/episodes/starting-jekyll.md index bff3b1bc..843b79bb 100644 --- a/episodes/starting-jekyll.md +++ b/episodes/starting-jekyll.md @@ -1,20 +1,7 @@ --- -title: "Starting With Jekyll" +title: Starting With Jekyll teaching: 20 exercises: 10 -questions: -- "How can I use values stored in variables in my pages?" -- "How can I configure global values/settings for my site?" -objectives: -- "Substitute variable values into page content" -- "Adjust the configuration of the site and individual pages" -- "Learn how to identify and correct errors that lead to Jekyll build failures" -keypoints: -- "Variables can be defined globally in `_config.yml` or locally within YAML header (*front matter*) of a page" -- "Variable values can be substituted into page content with Liquid notation: `{{ variable }}`" -- "Global variables are accessible from any page of your website; local variables can only be accessed within -the page in which they were defined (and any pages that include this page)" -- "Errors can happen but Jekyll will often tell us what's wrong" --- [Jekyll](https://jekyllrb.com/) is a powerful static site generator behind GitHub Pages. It creates static HTML @@ -23,6 +10,21 @@ This 'compiled' content is then served as your website via the `github.io` Web d from the previous episode?). Jekyll automatically re-generates all the HTML pages for your website each time you make a change to your repository. +::::::::::::::::::::::::::::::::::::::: objectives + +- Substitute variable values into page content +- Adjust the configuration of the site and individual pages +- Learn how to identify and correct errors that lead to Jekyll build failures + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: questions + +- How can I use values stored in variables in my pages? +- How can I configure global values/settings for my site? + +:::::::::::::::::::::::::::::::::::::::::::::::::: + Jekyll makes managing your website easier because it depends on templates. Templates (or layouts in Jekyll notation) are blueprints that can be reused by multiple pages. For example, instead of repeating the same navigation markup on every page you create @@ -32,28 +34,31 @@ We will cover Jekyll layouts in a bit; for now let's start learning Jekyll and its scripting language called [Liquid](https://shopify.github.io/liquid/basics/introduction/). ## Global Parameters + Jekyll's main configuration options are specified in a `_config.yml` file, which is written in a language -called [YAML](https://yaml.org/) and placed in your site’s root directory. Parameters configured in `_config.yml` +called [YAML](https://yaml.org/) and placed in your site's root directory. Parameters configured in `_config.yml` are global or site-wide - that means they are accessible in every page of your website. -> ## YAML -> -> [YAML](https://yaml.org/) is a human-readable data-serialization language. It is commonly used for configuration files and in -> applications where text data is being stored or transmitted and it is programming language agnostic. -> -{: .callout} +::::::::::::::::::::::::::::::::::::::::: callout + +## YAML + +[YAML](https://yaml.org/) is a human-readable data-serialization language. It is commonly used for configuration files and in +applications where text data is being stored or transmitted and it is programming language agnostic. + +:::::::::::::::::::::::::::::::::::::::::::::::::: Let's create some configuration parameters for our website. -1. From the GitHub interface, create `_config.yml` file in your site’s root directory. -2. Add parameters `description` and `email` to it as: +1. From the GitHub interface, create `_config.yml` file in your site's root directory. - ~~~ - description: "This research project develops training materials for reseachers wanting to learn to build project - websites in GitHub with GitHub Pages." - email: "team@carpentries.org" - ~~~ - {: .language-yaml} +2. Add parameters `description` and `email` to it as: + + ```yaml + description: "This research project develops training materials for reseachers wanting to learn to build project + websites in GitHub with GitHub Pages." + email: "team@carpentries.org" + ``` 3. Commit your changes. @@ -62,108 +67,126 @@ Global configuration settings from In order to access the parameter's value within a page, you use Liquid's notation to output content by surrounding a variable in curly braces as `{% raw %}{{ variable }}{% endraw %}`. -> ## Predefined Global Parameters ->In addition to the global parameters you define, Jekyll also makes a number of +::::::::::::::::::::::::::::::::::::::::: callout + +## Predefined Global Parameters + +In addition to the global parameters you define, Jekyll also makes a number of [useful predefined site-wide variables](https://jekyllrb.com/docs/variables#site-variables) available to you within your website: e.g. `{% raw %}{{ site.time }}{% endraw %}` (the current time) or `{% raw %}{{ site.pages }}{% endraw %}` (a list of all pages). -{: .callout} + + +:::::::::::::::::::::::::::::::::::::::::::::::::: Let's make use of global parameters in our pages. 1. Modify `index.md` file to make use of our global parameters like this: + + ```markdown + # Building Websites in GitHub + + ## Description + {% raw %}{{ site.description }}{% endraw %} + + More details about the project are available from the [About page](about). + + Have any questions about what we do? [We'd love to hear from you!]({% raw %}mailto:{{ site.email }}{% endraw %}) + ``` + +2. We can use the same parameter in different pages. Let's reuse `{% raw %}{{ site.description }}{% endraw %}` and + `{% raw %}{{ site.email }}{% endraw %}` in `about.md` like this: + + ```markdown + # About + + ## Project + + {% raw %}{{ site.description }}{% endraw %} + + ## Funders + + We gratefully acknowledge funding from the XYZ Founding Council, under grant number 'abc'. + + ## Cite us + + You can cite the project as: + + > *The Carpentries 2019 Annual Report. Zenodo. https://doi.org/10.5281/zenodo.3840372* + + ## Contact us + + - Email: [{% raw %}{{ site.email }}{% endraw %}](mailto:{% raw %}{{ site.email }}{% endraw %}) + - Twitter: [@thecarpentries](https://twitter.com/thecarpentries) + ``` - ~~~ - # Building Websites in GitHub +3. Go to your website to see the changes. - ## Description - {% raw %}{{ site.description }}{% endraw %} +4. Note that site parameters will not render nicely when viewing files in GitHub (they will be displayed as text + `{% raw %}{{ site.PARAMETER_NAME }}{% endraw %}` rather than the parameter's rendered value) but will in the website. - More details about the project are available from the [About page](about). +::::::::::::::::::::::::::::::::::::::: challenge - Have any questions about what we do? [We'd love to hear from you!]({% raw %}mailto:{{ site.email }}{% endraw %}) - ~~~ - {: .language-markdown } +## Exercise: Create a Global Twitter Parameter -2. We can use the same parameter in different pages. Let's reuse `{% raw %}{{ site.description }}{% endraw %}` and -`{% raw %}{{ site.email }}{% endraw %}` in `about.md` like this: +In `about.md` we have a Twitter URL under the 'Contact us' section. That's one piece of information that could go into +global parameters in `_config.yml` as you may want to repeat it on a footer of every page. +Make changes to your website to extract Twitter URL as a global parameter. - ~~~ - # About +::::::::::::::: solution - ## Project +## Solution - {% raw %}{{ site.description }}{% endraw %} +1. Add parameter twitter to `_config.yml`: + + ```yaml + description: "This research project develops training materials for reseachers wanting to learn to build project + websites in GitHub with GitHub Pages." + email: "team@carpentries.org" + twitter: "https://twitter.com/thecarpentries" + ``` - ## Funders +2. Make use of the twitter parameter in `about.md`: + + ```markdown + # About + + ## Project + + {% raw %}{{ site.description }}{% endraw %} + + ## Funders + + We gratefully acknowledge funding from the XYZ Founding Council, under grant number 'abc'. + + ## Cite us + + You can cite the project as: + + > *The Carpentries 2019 Annual Report. Zenodo. https://doi.org/10.5281/zenodo.3840372* + + ## Contact us + + - Email: [{% raw %}{{ site.email }}{% endraw %}](mailto:{% raw %}{{ site.email }}{% endraw %}) + - Twitter: [{% raw %}{{ site.twitter }}{% endraw %}]({% raw %}{{ site.twitter }}{% endraw %}) + ``` - We gratefully acknowledge funding from the XYZ Founding Council, under grant number 'abc'. +3. Note that you should not see any changes to your website really. However, you can now access your Twitter URL from + any website page, should you need to. + + - ## Cite us +::::::::::::::::::::::::: - You can cite the project as: +:::::::::::::::::::::::::::::::::::::::::::::::::: - > *The Carpentries 2019 Annual Report. Zenodo. https://doi.org/10.5281/zenodo.3840372* +::::::::::::::::::::::::::::::::::::::::: callout - ## Contact us +## Reuse and Reduce - - Email: [{% raw %}{{ site.email }}{% endraw %}](mailto:{% raw %}{{ site.email }}{% endraw %}) - - Twitter: [@thecarpentries](https://twitter.com/thecarpentries) - ~~~ - {: .language-markdown } +Jekyll's global parameters are a useful way to keep all your site-wide configuration in +a single place (even if you only use them once). In combination with Jekyll layouts/templates (to be covered in the next episode) they are a great way of creating reusable markup snippets that can be repeated on multiple or even on every page of your website. Reuse helps you reduce the amount of code you have to write. -3. Go to your website to see the changes. -4. Note that site parameters will not render nicely when viewing files in GitHub (they will be displayed as text -`{% raw %}{{ site.PARAMETER_NAME }}{% endraw %}` rather than the parameter's rendered value) but will in the website. - -> ## Exercise: Create a Global Twitter Parameter -> In `about.md` we have a Twitter URL under the 'Contact us' section. That's one piece of information that could go into -> global parameters in `_config.yml` as you may want to repeat it on a footer of every page. -> Make changes to your website to extract Twitter URL as a global parameter. -> > ## Solution -> > 1. Add parameter twitter to `_config.yml`: -> > -> > ~~~ -> > description: "This research project develops training materials for reseachers wanting to learn to build project -> > websites in GitHub with GitHub Pages." -> > email: "team@carpentries.org" -> > twitter: "https://twitter.com/thecarpentries" -> > ~~~ -> > {: .language-yaml} -> > -> > 2. Make use of the twitter parameter in `about.md`: -> > -> > ~~~ -> > # About -> > -> > ## Project -> > -> > {% raw %}{{ site.description }}{% endraw %} -> > -> > ## Funders -> > -> > We gratefully acknowledge funding from the XYZ Founding Council, under grant number 'abc'. -> > -> > ## Cite us -> > -> > You can cite the project as: -> > -> > > *The Carpentries 2019 Annual Report. Zenodo. https://doi.org/10.5281/zenodo.3840372* -> > -> > ## Contact us -> > -> > - Email: [{% raw %}{{ site.email }}{% endraw %}](mailto:{% raw %}{{ site.email }}{% endraw %}) -> > - Twitter: [{% raw %}{{ site.twitter }}{% endraw %}]({% raw %}{{ site.twitter }}{% endraw %}) -> > ~~~ -> > {: .language-markdown } -> > -> > 3. Note that you should not see any changes to your website really. However, you can now access your Twitter URL from -> > any website page, should you need to. -> {: .solution} -{: .challenge} - -> ## Reuse and Reduce -> Jekyll's global parameters are a useful way to keep all your site-wide configuration in -> a single place (even if you only use them once). In combination with Jekyll layouts/templates (to be covered in the next episode) they are a great way of creating reusable markup snippets that can be repeated on multiple or even on every page of your website. Reuse helps you reduce the amount of code you have to write. -{: .callout} + +:::::::::::::::::::::::::::::::::::::::::::::::::: ## When Things Go Wrong @@ -171,202 +194,241 @@ So far we have seen how to successfully use Jekyll to produce a website. There are however some situations where Jekyll may fail to do so either due to a typo or missing information. -> ## Exercise: Troubleshooting Jekyll -> -> This exercise will help you recognise what common mistakes look like -> when working with these elements of a Jekyll website. -> -> Edit your `_config.yml` file and omit a closing quote `"` in one of the variables. -> -> > ## Solution -> > -> > For instance, a missing closing quote `"` in the `twitter` variable. -> > ~~~ -> > description: "This research project develops training materials for reseachers wanting to learn to build project -> > websites in GitHub with GitHub Pages." -> > email: "team@carpentries.org" -> > twitter: "https://twitter.com/thecarpentries -> > ~~~ -> > {: .language-yaml} -> > -> > If you navigate your GitHub repository you would be able to see something break in `about.md` where we use `{% raw %}{{ site.twitter }}{% endraw %}` however, -> > contrary to what we saw before with invalid Markdown, -> > Jekyll will refuse to build the website and produce an error message. -> > -> > We will see after this where to find the error message and identify what caused them. -> {: .solution } -{: .challenge } +:::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Troubleshooting Jekyll + +This exercise will help you recognise what common mistakes look like +when working with these elements of a Jekyll website. + +Edit your `_config.yml` file and omit a closing quote `"` in one of the variables. + +:::::::::::::: solution + +## Solution + +For instance, a missing closing quote `"` in the `twitter` variable. + +```yaml +description: "This research project develops training materials for reseachers wanting to learn to build project +websites in GitHub with GitHub Pages." +email: "team@carpentries.org" +twitter: "https://twitter.com/thecarpentries +``` + +If you navigate your GitHub repository you would be able to see something break in `about.md` where we use `{% raw %}{{ site.twitter }}{% endraw %}` however, +contrary to what we saw before with invalid Markdown, +Jekyll will refuse to build the website and produce an error message. + +We will see after this where to find the error message and identify what caused them. + + + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: If you were keeping an eye on the GitHub repository page until now, you may have noticed a yellow circle visible when the website is still being processed and a green check mark (✓) when successful. -You may have also noticed that in the same location there is now a red cross/X next to the commit message (❌). +You may have also noticed that in the same location there is now a red cross/X next to the commit message (❌). This indicates that something went wrong with the Jekyll build process after that commit. -![Jekyll pending/successful/failed builds after different commits](../fig/jekyll_fail_pending_successful.png){: .image-with-shadow width="800px" } +![](fig/jekyll_fail_pending_successful.png){alt='Jekyll pending/successful/failed builds after different commits' .image-with-shadow width="800px" } You may also find an email from GitHub in your inbox with details about the error. But let's look at our repository again. If we click the red cross/X next to the commit message (❌) a little pop-up will appear with additional information. -![Jekyll - a failed build](../fig/jekyll_build_error.png){: .image-with-shadow width="800px" } +![](fig/jekyll_build_error.png){alt='Jekyll - a failed build' .image-with-shadow width="800px" } Visiting the page behind the **Details** link will give us the information we were missing. -![Jekyll - error details of a failed build](../fig/jekyll_build_error_detail.png){: .image-with-shadow width="800px" } +![](fig/jekyll_build_error_detail.png){alt='Jekyll - error details of a failed build' .image-with-shadow width="800px" } From this page we can see that what caused the failure affected line 5 of the `_config.yml` file. This matches the line where we deleted the `"`. Since this typo prevents Jekyll from building the page, the process cannot continue. -> ## Failure Will Not Remove Your Website -> -> Given the failure you may be wondering what happened to the website? -> If you visit the address you will find that the website is still be available. -> -> GitHub will keep your previous version online until the error is fixed -> and a new build is completed successfully. -{: .callout } +:::::::::::::::::::::::::::::::::::::::: callout + +## Failure Will Not Remove Your Website + +Given the failure you may be wondering what happened to the website? +If you visit the address you will find that the website is still be available. + +GitHub will keep your previous version online until the error is fixed +and a new build is completed successfully. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: Lets go ahead and fix your intentional typo and re-add the missing `"`: -~~~ +```yaml description: "This research project develops training materials for reseachers wanting to learn to build project websites in GitHub with GitHub Pages." email: "team@carpentries.org" twitter: "https://twitter.com/thecarpentries" -~~~ -{: .language-yaml} +``` After a few seconds we should see a green checkmark again and our website will be updated. - ## Local Parameters -In addition to global (site-wide) parameters available via the `site` global variable, Jekyll makes _local_ (page-specific) information available to you via the `page` variable. +In addition to global (site-wide) parameters available via the `site` global variable, Jekyll makes *local* (page-specific) information available to you via the `page` variable. Some of these are pre-defined - like `page.title`, which gives you the title of the page that is currently active/being visited. Others you can define yourself. Check this [list of predefined page parameters](https://jekyllrb.com/docs/variables#page-variables). You can define local parameters using YAML notation within a Markdown page by including it in a page header and delimiting the header with triple-dashed lines `---`. These headers are called *front matter* and are used to set variables and metadata on individual pages in your Jekyll site. -> ## Front matter -> From [Jekyll's website](https://jekyllrb.com/docs/front-matter/): -> -> > Any file that contains a YAML front matter block will be processed by Jekyll as a special file. The front matter must be the first thing in the file and must take the form of valid YAML set between triple-dashed lines. -> -{: .callout} +::::::::::::::::::::::::::::::::::::::::: callout + +## Front matter + +From [Jekyll's website](https://jekyllrb.com/docs/front-matter/): -> ## Global and Local Parameters Are Case Sensitive -> It is important to note that the parameters used in the sites are case sensitive. -> By convention, usually they are all lowercase characters. -{: .callout} +> Any file that contains a YAML front matter block will be processed by Jekyll as a special file. The front matter must be the first thing in the file and must take the form of valid YAML set between triple-dashed lines. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::::: callout + +## Global and Local Parameters Are Case Sensitive + +It is important to note that the parameters used in the sites are case sensitive. +By convention, usually they are all lowercase characters. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: Here is an example: -~~~ +```yaml --- layout: post title: "My first blog post" author: "Danger Mouse" --- -~~~ -{: .language-yaml } +``` Between these triple-dashed lines, you can overwrite predefined variables (like `page.layout` or `page.title`) or create custom ones you need locally on the page (like `page.author`). These variables will then be available for you to access using Liquid's tags (e.g. `{% raw %}{{{% endraw %} page.title {% raw %}}}{% endraw %}` ) further down in the file and also in any files that include this one. Note that these variables are only accessible on that page. You will get an error if you try to reference a `page.variable` that was defined on a different page. -> ## Exercise: Practice With Local Variables -> -> Let's practice making and using local variables. Think of a local variable you may want to use only in your `about.md` or `index.md` page. -> If you cannot think of any, create a local variable called 'lesson-example' with the value -> of 'https://carpentries.github.io/lesson-example/' and reference it in your `index.md`. -> -> What did you add to your `index.md` to create this variable? -> Where did you add the front matter in your `index.md`? -> How did you reference that variable? -> -> > ## Solution -> > -> > Create a YAML header at the very top of `index.md` and add the `lesson-example` variable in between the -> > triple-dash delimiters. You can then reference the value within your `index.md` page as +::::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Practice With Local Variables + +Let's practice making and using local variables. Think of a local variable you may want to use only in your `about.md` or `index.md` page. +If you cannot think of any, create a local variable called 'lesson-example' with the value +of '[https://carpentries.github.io/lesson-example/](https://carpentries.github.io/lesson-example/)' and reference it in your `index.md`. + +What did you add to your `index.md` to create this variable? +Where did you add the front matter in your `index.md`? +How did you reference that variable? + +::::::::::::::: solution + +## Solution + +Create a YAML header at the very top of `index.md` and add the `lesson-example` variable in between the +triple-dash delimiters. You can then reference the value within your `index.md` page as `{% raw %}{{{% endraw %} page.lesson-example {% raw %}}}{% endraw %}`. Your file should now look like: -> > -> > ~~~ -> > --- -> > lesson-example: "https://carpentries.github.io/lesson-example/" -> > --- -> > -> > # Building Websites in GitHub -> > -> > ## Description -> > {% raw %}{{ site.description }}{% endraw %} -> > -> > More details about the project are available from the [About page](about). -> > -> > See some [examples of our work]({% raw %}{{{% endraw %} page.lesson-example {% raw %}}}{% endraw %}). -> > -> > Have any questions about what we do? [We'd love to hear from you!]({% raw %}mailto:{{ site.email }}{% endraw %}) -> > ~~~ -> > {: .language-markdown } -> > -> > Note that this variable is not accessible from `about.md` page and is local to `index.md`. -> {: .solution} -{: .challenge} - - -> ## Exercise: Practice With Troubleshooting -> -> Sometimes typos happen and can make your website change in surprising ways. -> Let's experiment with some possible issues that might come up and see what happens. -> -> Try the changes listed below on your `index.md` file and see what happens when the page renders. -> You will want to correct the previous mistake each time. -> 1. Use a global or local variable that you didn't define first. -> 2. Leave the dash off the end of the YAML header. -> 3. Don't put a space between the YAML header and the rest of the page -> 4. Put the YAML header in a different location in the page. -> -> > ## Solution -> > -> > 1. The place where you used the undefined variable is blank but otherwise no error. -> > Example: -> > -> > ~~~ -> > Hi! {% raw %}{{ site.greeting }}{% endraw %}. What have you been up to? -> > ~~~ -> > {: .language-markdown } -> > -> > 2. The header shows somewhat in the file and the variable that was defined goes to -> > the index page intead of the link we set. -> > -> > ~~~ -> > --- -> > lesson-example: "https://carpentries.github.io/lesson-example/" -> > -> > Examples of our work can be found at: {% raw %}{{ page.lesson-example }}{% endraw %} -> > ~~~ -> > {: .language-markdown } -> > -> > 3. This doesn't seem to affect our page but can often make more complex pages break. -> > -> > ~~~ -> > --- -> > lesson-example: "https://carpentries.github.io/lesson-example/" -> > --- -> > Examples of our work can be found at: {% raw %}{{ page.lesson-example }}{% endraw %} -> > ~~~ -> > {: .language-markdown } -> > -> > 4. This also makes the header somewhat show in the page and breaks the variable link we created. -> > -> > ~~~ -> > Examples of our work can be found at: {% raw %}{{ page.lesson-example }}{% endraw %} -> > --- -> > lesson-example: "https://carpentries.github.io/lesson-example/" -> > --- -> > ~~~ -> > {: .language-markdown } -> > -> {: .solution} -> Note: Be sure to fix any errors you intentionally introduced in your page before moving on. -{: .challenge} - -{% include links.md %} + +```markdown +--- +lesson-example: "https://carpentries.github.io/lesson-example/" +--- + +# Building Websites in GitHub + +## Description +{% raw %}{{ site.description }}{% endraw %} + +More details about the project are available from the [About page](about). + +See some [examples of our work]({% raw %}{{{% endraw %} page.lesson-example {% raw %}}}{% endraw %}). + +Have any questions about what we do? [We'd love to hear from you!]({% raw %}mailto:{{ site.email }}{% endraw %}) +``` + +Note that this variable is not accessible from `about.md` page and is local to `index.md`. + + + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::: challenge + +## Exercise: Practice With Troubleshooting + +Sometimes typos happen and can make your website change in surprising ways. +Let's experiment with some possible issues that might come up and see what happens. + +Try the changes listed below on your `index.md` file and see what happens when the page renders. +You will want to correct the previous mistake each time. + +1. Use a global or local variable that you didn't define first. +2. Leave the dash off the end of the YAML header. +3. Don't put a space between the YAML header and the rest of the page +4. Put the YAML header in a different location in the page. + +::::::::::::::: solution + +## Solution + +1. The place where you used the undefined variable is blank but otherwise no error. + Example: + + ```markdown + Hi! {% raw %}{{ site.greeting }}{% endraw %}. What have you been up to? + ``` + +2. The header shows somewhat in the file and the variable that was defined goes to + the index page intead of the link we set. + + ```markdown + --- + lesson-example: "https://carpentries.github.io/lesson-example/" + + Examples of our work can be found at: {% raw %}{{ page.lesson-example }}{% endraw %} + ``` + +3. This doesn't seem to affect our page but can often make more complex pages break. + + ```markdown + --- + lesson-example: "https://carpentries.github.io/lesson-example/" + --- + Examples of our work can be found at: {% raw %}{{ page.lesson-example }}{% endraw %} + ``` + +4. This also makes the header somewhat show in the page and breaks the variable link we created. + + ```markdown + Examples of our work can be found at: {% raw %}{{ page.lesson-example }}{% endraw %} + --- + lesson-example: "https://carpentries.github.io/lesson-example/" + --- + ``` + +::::::::::::::::::::::::: + + +Note: Be sure to fix any errors you intentionally introduced in your page before moving on. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + + +:::::::::::::::::::::::::::::::::::::::: keypoints + +- Variables can be defined globally in `_config.yml` or locally within YAML header (*front matter*) of a page +- Variable values can be substituted into page content with Liquid notation: `{{ variable }}` +- Global variables are accessible from any page of your website; local variables can only be accessed within the page in which they were defined (and any pages that include this page) +- Errors can happen but Jekyll will often tell us what's wrong + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + diff --git a/episodes/wrap-up.md b/episodes/wrap-up.md index 5f9b490b..325508e4 100644 --- a/episodes/wrap-up.md +++ b/episodes/wrap-up.md @@ -1,52 +1,60 @@ --- -title: "Wrap-up" +title: Wrap-up teaching: 0 exercises: 0 -questions: -- "How do all pieces of a Jekyll website fit into a directory structure?" -- "What other resources are available for learning more on Jekyll?" -objectives: -- "Summarise all the different technologies that are coming together to create GitHub Pages websites." -- "Look at the anatomy of a Jekyll website repository." -- "Identify other resources and further reading about Jekyll." -keypoints: -- "Jekyll is a powerful static site generator behind GitHub Pages that supports a high degree of reuse and separation of - content and presentation." -- "Learning more on Jekyll themes will enable you to create complex and professional-looking websites." --- -{% include base_path.html %} + + +::::::::::::::::::::::::::::::::::::::: objectives + +- Summarise all the different technologies that are coming together to create GitHub Pages websites. +- Look at the anatomy of a Jekyll website repository. +- Identify other resources and further reading about Jekyll. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::: questions + +- How do all pieces of a Jekyll website fit into a directory structure? +- What other resources are available for learning more on Jekyll? + +:::::::::::::::::::::::::::::::::::::::::::::::::: Thinking more about how you might use what you've learned in practice. You may want to make professional-looking websites by reusing existing website themes. Here, we are going to recap what we have learned so far and look at the anatomy of a GitHub Pages website and its common building blocks, and try using an existing theme template. -> ## Summary -> -> Throughout this lesson, we learned how to -> [create formatted webpage content with Markdown]({{ relative_root_path }}/markdown/), -> [configure a GitHub repository to use the Jekyll static site generator]({{ relative_root_path }}/github-pages/), -> and [how to use Jekyll to build our Markdown pages and various other files]({{ relative_root_path }}/starting-jekyll/) -> (HTML snippets, CSS, images, etc.) into a set of HTML documents that are then served via the GitHub Pages framework. -> ![Static websites in GitHub Pages technology overview diagram](../fig/jekyll-gh-pages-website-overview.svg){: width="700px" } -> **HTML** is the basic building block of webpages served on the Internet. It describes the structural elements of the -> page and their raw content and is often aided by **CSS** - an ordered set of styling instructions telling the browser -> how the content described in the HTML document should be organised and formatted. HTML is very verbose and difficult -> to write by hand - beyond their initial design HTML pages are meant to be processed by machines. -> For that reason, **Markdown** was introduced - a lightweight Markup language and a convention for -> adding style information to textual content while retaining the human-readable form. It is not as rich in syntax as HTML, -> but comparably more usable by a wider audience. -> -> **Jekyll** is a powerful static site generator behind **GitHub Pages** that supports a high degree of reuse and separation of -> content and presentation. It can be configured via the `_config.yml` **YAML** file -> that stores site-wide variables accessible from anywhere within our site. -> It also allows us to define and reuse page-wide variables, by defining them as the **front matter** at the beginning of -> our Markdown pages. Used in conjunction with **Liquid**, its scripting language, Jekyll allows us to include content from -> reusable markup snippets that can be repeated on multiple pages and to embed code snippets and filters into our pages to -> create some complex content assembly pipelines. That way, adding a new blog post to your website may only involve -> creating a file in the `_posts` folder of your website, setting it to use the 'post' template and focusing on its -> content - and it will magically appear at the top of your Blog timeline without any extra effort on your part. -{: .keypoints } +:::::::::::::::::::::::::::::::::::::: keypoints + +## Summary + +Throughout this lesson, we learned how to +[create formatted webpage content with Markdown]({{ relative\_root\_path }}/markdown/), +[configure a GitHub repository to use the Jekyll static site generator]({{ relative\_root\_path }}/github-pages/), +and [how to use Jekyll to build our Markdown pages and various other files]({{ relative\_root\_path }}/starting-jekyll/) +(HTML snippets, CSS, images, etc.) into a set of HTML documents that are then served via the GitHub Pages framework. +![](fig/jekyll-gh-pages-website-overview.svg){alt='Static websites in GitHub Pages technology overview diagram' width="700px" } +**HTML** is the basic building block of webpages served on the Internet. It describes the structural elements of the +page and their raw content and is often aided by **CSS** - an ordered set of styling instructions telling the browser +how the content described in the HTML document should be organised and formatted. HTML is very verbose and difficult +to write by hand - beyond their initial design HTML pages are meant to be processed by machines. +For that reason, **Markdown** was introduced - a lightweight Markup language and a convention for +adding style information to textual content while retaining the human-readable form. It is not as rich in syntax as HTML, +but comparably more usable by a wider audience. + +**Jekyll** is a powerful static site generator behind **GitHub Pages** that supports a high degree of reuse and separation of +content and presentation. It can be configured via the `_config.yml` **YAML** file +that stores site-wide variables accessible from anywhere within our site. +It also allows us to define and reuse page-wide variables, by defining them as the **front matter** at the beginning of +our Markdown pages. Used in conjunction with **Liquid**, its scripting language, Jekyll allows us to include content from +reusable markup snippets that can be repeated on multiple pages and to embed code snippets and filters into our pages to +create some complex content assembly pipelines. That way, adding a new blog post to your website may only involve +creating a file in the `_posts` folder of your website, setting it to use the 'post' template and focusing on its +content - and it will magically appear at the top of your Blog timeline without any extra effort on your part. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: As a last thing, let's put it all together by having a look at a directory structure of a real-life Jekyll website, where different pieces are located and see how they relate to visual components on the @@ -67,12 +75,13 @@ However, there are some common elements, such as `_config.yml` (website's global configuration), and folders starting with `_`, which have special meaning to Jekyll by convention, such as: + - `_includes` - containing reusable page snippets, - `_layouts` - for storing theme's page templates, - `_sass` or `assets` (without the leading `_`) where Jekyll looks for 'assets' such as CSS and -JavaScript files, + JavaScript files, - `_data` - for storing well-formatted site data (in either the .yml, .yaml, .json, .csv or .tsv formats) -that Jekyll autoloads and makes accessible accessible via the `site.data` global variable, + that Jekyll autoloads and makes accessible accessible via the `site.data` global variable, - `_site` - containing the static version of the website ready to be served to users once Jekyll compiles it. Other 'special' folders, particular to this example only, are `_episodes` and `_extras` - they are collections defined by the theme @@ -93,22 +102,26 @@ There is no firm naming convention in this case - Jekyll will not process these folders automatically and the website designer will have to make sure to access/link to the content of these folders appropriately. -![Directory structure of a jekyll website containing this lesson](../fig/directory-structure-rendered-website-with-annotations.png){: .image-with-shadow height="1200px" } +![](fig/directory-structure-rendered-website-with-annotations.png){alt='Directory structure of a jekyll website containing this lesson' .image-with-shadow height="1200px" } + +::::::::::::::::::::::::::::::::::::::::: callout + +## Reusing The Carpentries Jekyll Lesson Theme + +Reusing [the lesson template](https://github.com/carpentries/styles) to create a new lesson can be achieved by copying the theme repository and customising it by adding your episodes in the appropriate place. +The template is published under [the Creative Commons Attribution 4.0 license][cc-by-human], +which means you are free to re-use and modify it however you like as long as +you acknowledge the original source. +You will often find that other Jekyll themes are available with a similarly +permissive license, but you should always check the terms to make sure you +understand what you can and cannot do with your chosen theme. -> ## Reusing The Carpentries Jekyll Lesson Theme -> Reusing [the lesson template](https://github.com/carpentries/styles) to create a new lesson can be achieved by copying the theme repository and customising it by adding your episodes in the appropriate place. -> The template is published under [the Creative Commons Attribution 4.0 license][cc-by-human], -> which means you are free to re-use and modify it however you like as long as -> you acknowledge the original source. -> You will often find that other Jekyll themes are available with a similarly -> permissive license, but you should always check the terms to make sure you -> understand what you can and cannot do with your chosen theme. -> -{: .callout} +:::::::::::::::::::::::::::::::::::::::::::::::::: {% comment %} Have a look at another example - a simplified directory structure of a blog website ([reproduced from JekyllRb](https://jekyllrb.com/docs/structure/)). -~~~ + +```code . ├── _config.yml ├── _data @@ -131,8 +144,8 @@ Have a look at another example - a simplified directory structure of a blog webs ├── _site ├── .jekyll-metadata └── index.html # can also be an 'index.md' with valid front matter -~~~ -{: .code} +``` + {% endcomment %} ## Practice Customizing a Theme @@ -151,12 +164,12 @@ We will be using some and leaving others for you to explore later. To get your own copy of this repository, click the "Fork" button the upper right-hand side of the GitHub interface. -![the GitHub interface fork button](../fig/gh-fork-button.png){: height="50px"} +![](fig/gh-fork-button.png){alt='the GitHub interface fork button' height="50px"} -If you belong to many GitHub organizations, you might have to +If you belong to many GitHub organizations, you might have to choose which account to copy/fork the repo to. -![GitHub copying the fork](../fig/github-forking-progress.png){: height="200px"} +![](fig/github-forking-progress.png){alt='GitHub copying the fork' height="200px"} Now you will have your own copy of the template to modify. You can see the repo it was forked from in the upper left-hand side of the page. @@ -170,7 +183,7 @@ says `main`. Then in the box that reads "Find or create a branch" type `gh-pages`. Then click the "Create branch: gh-pages from 'main'" option that appears below. -![GitHub branching dropdown menu with gh-pages typed in box](../fig/github-branch-ghpages.png){: height="300px"} +![](fig/github-branch-ghpages.png){alt='GitHub branching dropdown menu with gh-pages typed in box' height="300px"} Once you've clicked that option you will see the box change to say `gh-pages` instead of `main` indicating you are working on the new branch you created. @@ -180,7 +193,7 @@ and check in "Settings" to see that it worked as expected. We will be making lots of edits to the new `gh-pages` branch in the challenges below. This will be easier to do if we make it the default branch. -To change the `gh-pages` branch to the default branch, first click +To change the `gh-pages` branch to the default branch, first click the branches button to the right of the drop-down menu we used to create the `gh-pages` branch. Then in the box that shows the `Default branch` click the two arrows button @@ -194,157 +207,193 @@ Now when you return to the `Code` tab or the main page of your repo, you will se **The following series of challenges will have you practice the skills you learned in this lesson to modify this template.** -> ## Update GitHub About Section Link to Site -> As we did before in the [Hosting Websites on GitHub episode](github-pages.md), update -> the repository details to link directly to the rendering website -> from your fork. -> -{: .challenge} +::::::::::::::::::::::::::::::::::::::: challenge -> ## Customize the Configuration -> -> Update the name and the description variables for the site. -> Reload the rendered page to see the changes to the actual site. -> -> Hint: See the [Starting with Jekyll episode](starting-jekyll.md) for review -> -> > ## Solution -> > -> > The description and name variables are site-wide variables so they are found in the `_config.yml` file -> > and can be updated there. Changes are then committed and the site can be reloaded after -> > Github re-renders the latest version of the site with Jekyll. -> > -> {: .solution} -{: .challenge} - -> ## Customize the Header Menu -> -> Find where the header menu is created and remove the "WP", "Ghost", and -> "Buy me a coffee" items. -> -> Hint: See the [Reusing Blocks of Content](includes.md) section for more information -> about where to find the header menu. -> -> > ## Solution -> > -> > Lines 12-20 need to be removed from the `_includes/menu-header.html` file. -> > -> {: .solution} -{: .challenge} - -> ## Update a Layout -> -> 1. Update the `post` layout to remove the newsletter. -> 1. Also remove the "Share this" block to the bottom of the post where the newsletter block used to be (above "Author Box"). -> -> Hint: Review the [Page Layouts](layouts.md) episode from this lesson for more information on layouts. -> -> > ## Solution -> > -> > 1. Lines 81-105 need to be removed to remove the newsletter. -> > 1. To move the "Share this" box, lines 45-65 should be cut (copied then deleted) and then pasted between the Article and the Author Box section. -> > -> {: .solution} -{: .challenge} - -> ## Customize the About Page -> -> Oftentimes you might want to edit some existing pages and layouts. In this exercise, we will make the -> `About` page for this site more useful by changing the layout, editing the text, and including -> it as a link in the header menu for this site. -> -> 1. Find the `About` page and update the layout to the `page` layout, -> turn off the comments option, remove the image and the "made with" text. -> 1. Make the `About` page content include the site description you updated -> and any other text you'd like to add. -> 1. Update the header menu to include a link for the `About` page. -> -> -> > ## Solution -> > -> > 1. The `About` page is called `about.md` and is in the `_pages` folder. Once found in the yaml header the variables can be changed to "page" for layout and "false" for comments. In the body of the page the line that starts with "Made with" is removed. -> > 1. In the body of the `_pages/about.md` description variable is added using liquid syntax, `{% raw %} {{ site.description }} {% endraw %}`, and add any other text that might be helpful for an about page. -> > 1. The header is updated in the `_includes/menu-header.html` (this may take some searching to track down). The same html from the other items in the header can be copied and modified. -> > -> {: .solution} -{: .challenge} - - -> ## Add Yourself as a Potential Author -> -> Find where the authors collection is defined and add yourself. -> -> Hint 1: the author for an individual post is defined in the frontmatter of the post but the -> collection of possible authors is defined in a location that allows use across the site. -> -> Hint 2: Review the [Loops and Collections](arrays.md) episode of this episode for a reminder -> on how collections work and reminder on where you might find the authors collection. -> -> > ## Solution -> > -> > The authors collection is found in the `_config.yml`. A new entry can be made by copying -> > lines 22-28, pasting them on line 38, and then customizing them. -> > -> {: .solution} -{: .challenge} - -> ## Add a New Blogpost -> Add a new blog post for today's date with the announcment of your new website. -> -> Hint: See the [Loops and Collections](arrays.md) for reminders and more information, -> Pay close attention to the Blogging in the Wild section as it tells you more about -> how to use the built-in `_posts` functionality. -> -> > ## Solution -> > -> > - Add a new file to the `_posts` folder with the filename `YYYY-MM-DD-some-key-info.md`. -> > - In another window, open another post in the `_posts` folder and copy the frontmatter (yaml header). -> > - Paste the front matter into your new file and change the author and title. -> > - Add some text, headers, images or other content if you wish. -> > -> {: .solution} -{: .challenge} - -> ## Use A Filter -> -> Currently the Authors page sorts based on the order of the collection but we would -> prefer it sort alphabetically. -> Use this [list of Jekyll filters](https://jekyllrb.com/docs/liquid/filters/) to -> find a filter and edit the `author-list.html` page to display the authors alphabetically. -> -> Hint: Refer to this section on [looping over a collection](https://carpentries-incubator.github.io/jekyll-pages-novice/arrays/index.html#looping-over-a-collection) -> if you get a (silent) build error with your first solution. -> -> -> > ## Solution -> > -> > For this change we need to first sort the collection and assign the sorted collection to a variable. -> > Then use that sorted collection variable in the for loop when we display the authors. -> > -> > In the `_pages/author-list.html` file add the line -> > `{% raw %}{% assign sorted_authors = site.authors | sort "name" %}{% endraw %}` -> > right before the `{% raw %}{% for author in site.authors %}{% endraw %}` line. -> > Then change that line to `{% raw %}{% for author in sorted_authors %}{% endraw %}`. -> > -> {: .solution} -{: .challenge} - -> ## Detective Work: Find Comments -> Look through the site and see if you can find how it allows for comments. -> -> > ## Solution -> > -> > This site uses [Disqus](https://disqus.com/) to manage comments. -> > If you'd like, you can create your own account and configure the site -> > to manage your comments. -> > -> {: .solution} -> -{: .challenge} +## Update GitHub About Section Link to Site + +As we did before in the [Hosting Websites on GitHub episode](github-pages.md), update +the repository details to link directly to the rendering website +from your fork. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::: challenge + +## Customize the Configuration + +Update the name and the description variables for the site. +Reload the rendered page to see the changes to the actual site. + +Hint: See the [Starting with Jekyll episode](starting-jekyll.md) for review + +::::::::::::::: solution + +## Solution + +The description and name variables are site-wide variables so they are found in the `_config.yml` file +and can be updated there. Changes are then committed and the site can be reloaded after +Github re-renders the latest version of the site with Jekyll. + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::: challenge + +## Customize the Header Menu + +Find where the header menu is created and remove the "WP", "Ghost", and +"Buy me a coffee" items. + +Hint: See the [Reusing Blocks of Content](includes.md) section for more information +about where to find the header menu. + +::::::::::::::: solution + +## Solution + +Lines 12-20 need to be removed from the `_includes/menu-header.html` file. + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::: challenge + +## Update a Layout + +1. Update the `post` layout to remove the newsletter. +2. Also remove the "Share this" block to the bottom of the post where the newsletter block used to be (above "Author Box"). + +Hint: Review the [Page Layouts](layouts.md) episode from this lesson for more information on layouts. +::::::::::::::: solution +## Solution + +1. Lines 81-105 need to be removed to remove the newsletter. +2. To move the "Share this" box, lines 45-65 should be cut (copied then deleted) and then pasted between the Article and the Author Box section. + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::: challenge + +## Customize the About Page + +Oftentimes you might want to edit some existing pages and layouts. In this exercise, we will make the +`About` page for this site more useful by changing the layout, editing the text, and including +it as a link in the header menu for this site. + +1. Find the `About` page and update the layout to the `page` layout, + turn off the comments option, remove the image and the "made with" text. +2. Make the `About` page content include the site description you updated + and any other text you'd like to add. +3. Update the header menu to include a link for the `About` page. + +::::::::::::::: solution + +## Solution + +1. The `About` page is called `about.md` and is in the `_pages` folder. Once found in the yaml header the variables can be changed to "page" for layout and "false" for comments. In the body of the page the line that starts with "Made with" is removed. +2. In the body of the `_pages/about.md` description variable is added using liquid syntax, `{% raw %} {{ site.description }} {% endraw %}`, and add any other text that might be helpful for an about page. +3. The header is updated in the `_includes/menu-header.html` (this may take some searching to track down). The same html from the other items in the header can be copied and modified. + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::: challenge + +## Add Yourself as a Potential Author + +Find where the authors collection is defined and add yourself. + +Hint 1: the author for an individual post is defined in the frontmatter of the post but the +collection of possible authors is defined in a location that allows use across the site. + +Hint 2: Review the [Loops and Collections](arrays.md) episode of this episode for a reminder +on how collections work and reminder on where you might find the authors collection. + +::::::::::::::: solution + +## Solution + +The authors collection is found in the `_config.yml`. A new entry can be made by copying +lines 22-28, pasting them on line 38, and then customizing them. + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::: challenge + +## Add a New Blogpost + +Add a new blog post for today's date with the announcment of your new website. + +Hint: See the [Loops and Collections](arrays.md) for reminders and more information, +Pay close attention to the Blogging in the Wild section as it tells you more about +how to use the built-in `_posts` functionality. + +::::::::::::::: solution + +## Solution + +- Add a new file to the `_posts` folder with the filename `YYYY-MM-DD-some-key-info.md`. +- In another window, open another post in the `_posts` folder and copy the frontmatter (yaml header). +- Paste the front matter into your new file and change the author and title. +- Add some text, headers, images or other content if you wish. + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::: challenge + +## Use A Filter + +Currently the Authors page sorts based on the order of the collection but we would +prefer it sort alphabetically. +Use this [list of Jekyll filters](https://jekyllrb.com/docs/liquid/filters/) to +find a filter and edit the `author-list.html` page to display the authors alphabetically. + +Hint: Refer to this section on [looping over a collection](https://carpentries-incubator.github.io/jekyll-pages-novice/arrays/index.html#looping-over-a-collection) +if you get a (silent) build error with your first solution. + +::::::::::::::: solution + +## Solution + +For this change we need to first sort the collection and assign the sorted collection to a variable. +Then use that sorted collection variable in the for loop when we display the authors. + +In the `_pages/author-list.html` file add the line +`{% raw %}{% assign sorted_authors = site.authors | sort "name" %}{% endraw %}` +right before the `{% raw %}{% for author in site.authors %}{% endraw %}` line. +Then change that line to `{% raw %}{% for author in sorted_authors %}{% endraw %}`. + +::::::::::::::::::::::::: + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::: challenge + +## Detective Work: Find Comments + +Look through the site and see if you can find how it allows for comments. + +> ## Solution +> +> This site uses [Disqus](https://disqus.com/) to manage comments. +> If you'd like, you can create your own account and configure the site +> to manage your comments. + +:::::::::::::::::::::::::::::::::::::::::::::::::: ## Further Resources + Below are some recommended resources to help you continue learning about Jekyll websites: - [W3C Schools HTML tutorial](https://www.w3schools.com/html/) @@ -356,4 +405,13 @@ Below are some recommended resources to help you continue learning about Jekyll - [Jekyll themes](https://jekyllrb.com/resources#themes) - [Jekyll liquid documentation](https://jekyllrb.com/docs/liquid/) -{% include links.md %} + + +:::::::::::::::::::::::::::::::::::::::: keypoints + +- Jekyll is a powerful static site generator behind GitHub Pages that supports a high degree of reuse and separation of content and presentation. +- Learning more on Jekyll themes will enable you to create complex and professional-looking websites. + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + diff --git a/gifnoc_.yml b/gifnoc_.yml new file mode 100644 index 00000000..4eca98d7 --- /dev/null +++ b/gifnoc_.yml @@ -0,0 +1,113 @@ +#------------------------------------------------------------ +# Values for this lesson. +#------------------------------------------------------------ + +# Which carpentry is this ("swc", "dc", "lc", or "cp")? +# swc: Software Carpentry +# dc: Data Carpentry +# lc: Library Carpentry +# cp: Carpentries (to use for instructor traning for instance) +carpentry: "incubator" + +# Overall title for pages. +title: "Building Websites With Jekyll and GitHub" + +# Life cycle stage of the lesson +# possible values: "pre-alpha", "alpha", "beta", "stable" +life_cycle: "beta" + +#------------------------------------------------------------ +# Generic settings (should not need to change). +#------------------------------------------------------------ + +# What kind of thing is this ("workshop" or "lesson")? +kind: "lesson" + + +repository: "carpentries-incubator/jekyll-pages-novice" + +# Email address, no mailto: +email: "tobyhodges@carpentries.org" + +# Sites. +amy_site: "https://amy.carpentries.org/workshops" +carpentries_github: "https://github.com/carpentries" +carpentries_pages: "https://carpentries.github.io" +carpentries_site: "https://carpentries.org/" +dc_site: "https://datacarpentry.org" +example_repo: "https://github.com/carpentries/lesson-example" +example_site: "https://carpentries.github.io/lesson-example" +lc_site: "https://librarycarpentry.org/" +swc_github: "https://github.com/swcarpentry" +swc_pages: "https://swcarpentry.github.io" +swc_site: "https://software-carpentry.org" +template_repo: "https://github.com/carpentries/styles" +training_site: "https://carpentries.github.io/instructor-training" +workshop_repo: "https://github.com/carpentries/workshop-template" +workshop_site: "https://carpentries.github.io/workshop-template" +cc_by_human: "https://creativecommons.org/licenses/by/4.0/" + +# Surveys. +pre_survey: "https://carpentries.typeform.com/to/wi32rS?slug=" +post_survey: "https://carpentries.typeform.com/to/UgVdRQ?slug=" +instructor_pre_survey: "https://www.surveymonkey.com/r/instructor_training_pre_survey?workshop_id=" +instructor_post_survey: "https://www.surveymonkey.com/r/instructor_training_post_survey?workshop_id=" + + +# Start time in minutes (0 to be clock-independent, 540 to show a start at 09:00 am). +start_time: 0 + +# Specify that things in the episodes collection should be output. +collections: + episodes: + output: true + permalink: /:path/index.html + extras: + output: true + permalink: /:path/index.html + +# manual episode order + +episode_order: + - introduction + - markdown + - github-pages + - starting-jekyll + - includes + - layouts + - filters + - arrays + - wrap-up + +# Set the default layout for things in the episodes collection. +defaults: + - values: + root: . + layout: page + - scope: + path: "" + type: episodes + values: + root: .. + layout: episode + - scope: + path: "" + type: extras + values: + root: .. + layout: page + +# Files and directories that are not to be copied. +exclude: + - Makefile + - bin/ + - .Rproj.user/ + - .vendor/ + - .docker-vendor/ + +# Turn on built-in syntax highlighting. +highlighter: rouge + +# variables used within the lesson + +exercise-repo: project-pages diff --git a/index.md b/index.md index 89d2398a..0194698a 100644 --- a/index.md +++ b/index.md @@ -1,30 +1,41 @@ --- -layout: lesson -root: . # Is the only page that doesn't follow the pattern /:path/index.html -permalink: index.html # Is the only page that doesn't follow the pattern /:path/index.html +permalink: index.html +site: sandpaper::sandpaper_site --- -> ## Looking for Beta Testers! -> **We are currently looking for volunteers to test this lesson!** -> If you would like to teach this lesson in a pilot workshop, -> please let the lesson developers know by -> [opening a new issue on the lesson repository](https://github.com/carpentries-incubator/jekyll-pages-novice/issues/new) -> or posting to the [`#jekyll-pages-lesson` Slack channel](https://swcarpentry.slack.com/archives/C0186GK56UC) -> on [The Carpentries Slack](https://swc-slack-invite.herokuapp.com/). -> We would love to help you prepare to teach the lesson and -> receive feedback on how it could be further improved, -> based on your experience in the workshop. -{: .testimonial } - -> ## Prerequisites -> -> This lesson guides you through making websites using Jekyll in a web hosting service GitHub Pages. -> If you are comfortable interacting with websites in a web browser, this lesson is for you. Basic understanding -> of HTML and/or Markdown as webpage authoring languages is welcome but not a must. -> -> There may be additional prerequisites for individual lessons in the extras section. -> -{: .prereq } +> **ATTENTION** This is an experimental test of [The Carpentries Workbench](https://carpentries.github.io/workbench) lesson infrastructure. +> It was automatically converted from the source lesson via [the lesson transition script](https://github.com/carpentries/lesson-transition/). +> +> If anything seems off, please contact Zhian Kamvar [zkamvar@carpentries.org](mailto:zkamvar@carpentries.org) + +:::::::::::::::::::::::::::::::::::: testimonial + +## Looking for Beta Testers! + +**We are currently looking for volunteers to test this lesson!** +If you would like to teach this lesson in a pilot workshop, +please let the lesson developers know by +[opening a new issue on the lesson repository](https://github.com/carpentries-incubator/jekyll-pages-novice/issues/new) +or posting to the [`#jekyll-pages-lesson` Slack channel](https://swcarpentry.slack.com/archives/C0186GK56UC) +on [The Carpentries Slack](https://swc-slack-invite.herokuapp.com/). +We would love to help you prepare to teach the lesson and +receive feedback on how it could be further improved, +based on your experience in the workshop. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: + +::::::::::::::::::::::::::::::::::::::::: prereq + +## Prerequisites + +This lesson guides you through making websites using Jekyll in a web hosting service GitHub Pages. +If you are comfortable interacting with websites in a web browser, this lesson is for you. Basic understanding +of HTML and/or Markdown as webpage authoring languages is welcome but not a must. + +There may be additional prerequisites for individual lessons in the extras section. + +:::::::::::::::::::::::::::::::::::::::::::::::::: For those already familiar with the ways that Git and an online platform like GitHub @@ -41,19 +52,23 @@ However, for those taking their first steps towards building sites like this, the process can be confusing and intimidating. This tutorial aims to address this, by providing a step-by-step guide to creating a collection of pages -and combining them into a coherent site using a framework called _Jekyll_. - -> ## Outdated Screenshots -> -> Throughout this lesson we will make use and show content and screenshots from GitHub.com. -> As an ever evolving platform, GitHub is always adding new features -> and new visual elements to its website. -> **Screenshots** in the lesson may then become out-of-sync, refer or show content that no longer exists. -> -> If during the lesson you find **screenshots** that no longer match what you see in your browser, -> please [open an issue][github-jekyll-issues] describing what you see and how it differs from the lesson content. -> Feel free to add as many screenshots as necessary to clarify the discrepancy. -{: .callout } +and combining them into a coherent site using a framework called *Jekyll*. + +:::::::::::::::::::::::::::::::::::::::: callout + +## Outdated Screenshots + +Throughout this lesson we will make use and show content and screenshots from GitHub.com. +As an ever evolving platform, GitHub is always adding new features +and new visual elements to its website. +**Screenshots** in the lesson may then become out-of-sync, refer or show content that no longer exists. + +If during the lesson you find **screenshots** that no longer match what you see in your browser, +please [open an issue][github-jekyll-issues] describing what you see and how it differs from the lesson content. +Feel free to add as many screenshots as necessary to clarify the discrepancy. + + +:::::::::::::::::::::::::::::::::::::::::::::::::: ## Target Audience @@ -87,16 +102,20 @@ An still needs to finish writing her thesis and doesn't have a lot of time to sp This lesson will teach An how to find and use an existing template to create her personal webpage and online CV, how to write formatted text and insert images to highlight the skills she has picked up, and how to host those pages online for free. -> ## Learning Objectives -> -> After following this lesson, -> learners will be able to: -> -> - **create** formatted page content with Markdown -> - **configure** their project to build and serve pages on GitHub -> - **build** a coherent site with multiple pages using the Jekyll framework -> - **customise** the layout and style of the pages on their site -> -{: .objectives } - -{% include links.md %} +::::::::::::::::::::::::::::::::::::: objectives + +## Learning Objectives + +After following this lesson, +learners will be able to: + +- **create** formatted page content with Markdown +- **configure** their project to build and serve pages on GitHub +- **build** a coherent site with multiple pages using the Jekyll framework +- **customise** the layout and style of the pages on their site + +:::::::::::::::::::::::::::::::::::::::::::::::::: + + + + diff --git a/instructors/instructor-notes.md b/instructors/instructor-notes.md new file mode 100644 index 00000000..dec9c333 --- /dev/null +++ b/instructors/instructor-notes.md @@ -0,0 +1,78 @@ +--- +title: Instructor Notes +--- + +## Episode: [Introduction](introduction/index.html) + +### HedgeDoc/CodiMD Collaborative Notes Document + +We recommend the usage of [HedgeDoc](https://hedgedoc.org) (formerly called CodiMD) and for instance +[The Carpentries CodiMD instance](https://codimd.carpentries.org) for creating your new documents. +All instructors can use it for note-taking when preparing or teaching this lesson and we also encourage +its usage during the workshop for asking questions and collaborating during exercises, especially when using breakout rooms. +The main advantage is that it uses Markdown so it can easily convince learners on the importance of learning Markdown. +Make use of [HackMD Mechanics](https://coderefinery.github.io/manuals/hackmd-mechanics/#basic-controls) +from [CodeRefinery](https://coderefinery.org/). Take time to orient your learners to using the document early on +to be ensure everyone understands how to use HedgeDoc. + +### Hello World in HTML + +When demonstrating "Hello World in HTML" you may choose to write the example HTML in a text editor +before viewing the saved file in a browser. Or you may prefer to write the HTML directly into the workshop +HedgeDoc/CodiMD shared notes document, which will provide immediate visual feedback on the rendered equivalent. +The advantage to using the workshop CodiMD is that it reduces the need to switch between so many windows and introduce +the text editor. The advantage of opening a plain `.html` file in the browser is that it +clearly demonstrates the utility of the `title` element. + +### Shared Website Example Repository + +When multiple instructors are teaching this lesson, the person who demonstrates creating the website repository +(at the end of the [Introduction](introduction/index.html) episode) should remember to add the +other instructors as collaborators on that repository. +This will save you trying to maintain consistency between multiple demo repositories while also handling questions, +helping people who are stuck, etc. + +## Episode: [Authoring With Markdown](markdown/index.html) + +### 'Add Your Repository Details to HedgeDoc' Exercise + +We recommend doing the ["Optional Exercise: Add Your Repository Details to CodiMD" exercise](markdown/index.html#optional-exercise-add-your-repository-details-to-codimd) when teaching online, as it is +very useful for helpers to have links to all the learner repos **and** rendered websites for troubleshooting. +Then when a learner messages in chat, the helper can find their repo and look at the commit history to find the error. + +## Episode: [Hosting Websites on GitHub](github-pages/index.html) + +### Adding a theme through the GitHub Pages Settings tab + +If you're pushed for time and want to quickly introduce adding themes to your website without lots of additional context around Jekyll there is now a `Theme Chooser` section in the GitHub Pages Settings tab. This allows users to briefly browse supported Jekyll themes for GitHub Pages and select one for their site. +It will add a `_config.yml` file to the repository containing a single line that sets the theme i.e. `theme: jekyll-theme-cayman`. This will be committed automatically to your default branch and rebuild your site with the new theme. +Please note that using the `Theme Chooser` is incompatible with subsequent episodes in this lesson and is only recommended if you don't expect to progress onto further episodes (in particular *Page Layouts*). + +## Episode: [Starting With Jekyll](starting-jekyll/index.html) + +## Episode: [Reusing Blocks of Content](includes/index.html) + +### `includes` vs `include` + +Learners sometimes get confused about when to use `includes` vs `include` in the +[Reusing Blocks of Content](includes/index.html) episode. Good to stress that the folder is `_includes` +(e.g. it contains several files that can be included hence the plural form) and when you want to use something from that folder you `include` it. + +## Episode: [Page Layouts](layouts/index.html) + +### Layout Names Confusion + +Learners sometimes get confused about conventional names of layouts used in Jekyll - for example `home` +layout vs. home page (`index.html`), `page` layout vs. page used as a term for 'webpage', `default` layout was not much better +either. While it is not a must, recommendation here is to stick with this conventional terminology as it is +reused across different Jekyll websites that learners may come across in future and to spend some time clarifying this. + +## Episode: [Working With Filters](filters/index.html) + +## Episode: [Loops and Collections](arrays/index.html) + +## Episode: [Wrap-up](wrap-up/index.html) + + + + diff --git a/learners/discuss.md b/learners/discuss.md new file mode 100644 index 00000000..515e3baf --- /dev/null +++ b/learners/discuss.md @@ -0,0 +1,9 @@ +--- +title: Discussion +--- + +FIXME + + + + diff --git a/learners/figures.md b/learners/figures.md new file mode 100644 index 00000000..52b23293 --- /dev/null +++ b/learners/figures.md @@ -0,0 +1,82 @@ +--- +title: Figures +--- + + +{% include manual\_episode\_order.html %} + + + +{% comment %} Create anchor for each one of the episodes. {% endcomment %} + +{% for lesson\_episode in lesson\_episodes %} +{% if site.episode\_order %} +{% assign episode = site.episodes | where: "slug", lesson\_episode | first %} +{% else %} +{% assign episode = lesson\_episode %} +{% endif %} + +
    +{% endfor %} + + + + diff --git a/learners/reference.md b/learners/reference.md new file mode 100644 index 00000000..f93ed96a --- /dev/null +++ b/learners/reference.md @@ -0,0 +1,22 @@ +--- +{} +--- + +## Glossary + +- Branch +- Commit +- CSS +- DRY (Don't repeat yourself) principles +- Git +- GitHub +- HTML +- Markdown +- README +- Repository/repo +- Version Control +- YAML + + + + diff --git a/learners/setup.md b/learners/setup.md new file mode 100644 index 00000000..e3a811f1 --- /dev/null +++ b/learners/setup.md @@ -0,0 +1,13 @@ +--- +title: Setup +--- + +# GitHub + +Prior to the workshop you will need to setup a free account for [GitHub](https://github.com/). +Please consider what personal information you'd like to reveal in your account. +For example, you may want to review these [instructions for keeping your email address private](https://help.github.com/articles/keeping-your-email-address-private/) provided at GitHub. + + + + diff --git a/profiles/learner-profiles.md b/profiles/learner-profiles.md new file mode 100644 index 00000000..434e335a --- /dev/null +++ b/profiles/learner-profiles.md @@ -0,0 +1,5 @@ +--- +title: FIXME +--- + +This is a placeholder file. Please add content here. diff --git a/site/README.md b/site/README.md new file mode 100644 index 00000000..42997e3d --- /dev/null +++ b/site/README.md @@ -0,0 +1,2 @@ +This directory contains rendered lesson materials. Please do not edit files +here.