diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..7d0b7de5f8 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: true +contact_links: + - name: 💬 Start a discussion + url: https://github.com/greenelab/lab-website-template/discussions + about: I need help, I have a question, or other discussion. + - name: 📚 Docs issue + url: https://github.com/greenelab/lab-website-template-docs/issues + about: I have a question or issue related to the template documentation. diff --git a/.github/ISSUE_TEMPLATE/issue.yaml b/.github/ISSUE_TEMPLATE/issue.yaml new file mode 100644 index 0000000000..4d09efb61a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue.yaml @@ -0,0 +1,34 @@ +name: 🐞 Create an issue +description: I think I've discovered a bug, I want to request a feature/change, or other issue. + +body: + - type: checkboxes + attributes: + label: Checks + options: + - label: I have searched **[the docs](https://greene-lab.gitbook.io/lab-website-template-docs)**, [existing issues](https://github.com/greenelab/lab-website-template/issues), and [existing discussions](https://github.com/greenelab/lab-website-template/discussions) for answers first. + required: true + + - type: input + id: repo + attributes: + label: Link to your website repo + description: "**Strongly recommended** so we can help troubleshoot your issue." + placeholder: ex. https://github.com/greenelab/greenelab.com + + - type: input + id: version + attributes: + label: Version of Lab Website Template you are using + description: See your `CITATION.cff` file. + placeholder: ex. 1.0.0 + + - type: textarea + id: description + attributes: + label: Description + description: | + Describe your issue in as much detail as possible. For example: What happened? What did you expect to happen? How can we reproduce the problem? What browser are you seeing the problem in? + placeholder: Description + validations: + required: true diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 286990ee46..c1339b18f4 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,8 +1,13 @@ - +FOR THE TEMPLATE MAINTAINER(S) + +Checklist: + +- [ ] I have updated CITATION and CHANGELOG. +- [ ] I have updated lab-website-template-docs as appropriate. +- [ ] I have checked the testbed as appropriate. diff --git a/.github/workflows/auto-cite.yaml b/.github/workflows/auto-cite.yaml deleted file mode 100644 index fe82fe3116..0000000000 --- a/.github/workflows/auto-cite.yaml +++ /dev/null @@ -1,40 +0,0 @@ -name: Auto Cite - -on: - push: - branches: - - main - paths: - - "_data/sources.yaml" - - "_data/orcid.yaml" - pull_request: - paths: - - "_data/sources.yaml" - - "_data/orcid.yaml" - # workflow_dispatch: - # schedule: - # - cron: "0 0 * * 1" - -jobs: - update_research: - name: Auto Cite - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - name: Checkout code - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: 3.7 - - name: Install packages - run: python -m pip install --upgrade --requirement ./auto-cite/requirements.txt - - name: Build updated citations - run: python ./auto-cite/auto-cite.py - timeout-minutes: 15 - - name: Commit updated citations - uses: stefanzweifel/git-auto-commit-action@v4 - with: - file_pattern: "_data/citations.yaml" - commit_message: "Generate citations" - push_options: --force diff --git a/.github/workflows/build-preview.yaml b/.github/workflows/build-preview.yaml new file mode 100644 index 0000000000..c449856fcd --- /dev/null +++ b/.github/workflows/build-preview.yaml @@ -0,0 +1,56 @@ +name: build-preview +run-name: build pull request preview + +on: + # run when called from another workflow + workflow_call: + + # run if user manually requests it + workflow_dispatch: + +# variables +env: + PREVIEWS_FOLDER: preview + +permissions: + contents: write + pull-requests: write + +jobs: + build-preview: + runs-on: ubuntu-latest + + steps: + - name: Print contexts + uses: crazy-max/ghaction-dump-context@v1 + + - name: Checkout branch contents + uses: actions/checkout@v3 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.head_ref }} + + - name: Install Ruby packages + if: github.event.action != 'closed' + uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.0" + bundler-cache: true + + - name: Get Pages url + if: github.event.action != 'closed' + id: pages + uses: actions/configure-pages@v2 + with: + enablement: false + + - name: Build preview version of site + if: github.event.action != 'closed' + run: | + bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path || '' }}/${{ env.PREVIEWS_FOLDER }}/pr-${{ github.event.number }}" + + - name: Commit preview to Pages branch + uses: rossjrw/pr-preview-action@v1 + with: + source-dir: _site + umbrella-dir: ${{ env.PREVIEWS_FOLDER }} diff --git a/.github/workflows/build-site.yaml b/.github/workflows/build-site.yaml new file mode 100644 index 0000000000..6d10739489 --- /dev/null +++ b/.github/workflows/build-site.yaml @@ -0,0 +1,50 @@ +name: build-site +run-name: build live site + +on: + # run when called from another workflow + workflow_call: + + # run if user manually requests it + workflow_dispatch: + +# variables +env: + PREVIEWS_FOLDER: preview + +permissions: + contents: write + +jobs: + build-site: + runs-on: ubuntu-latest + + steps: + - name: Print contexts + uses: crazy-max/ghaction-dump-context@v1 + + - name: Checkout branch contents + uses: actions/checkout@v3 + + - name: Install Ruby packages + uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.0" + bundler-cache: true + + - name: Get Pages url + id: pages + uses: actions/configure-pages@v2 + with: + enablement: false + + - name: Build live version of site + run: | + bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path || '' }}" + + - name: Commit live site to Pages branch + uses: JamesIves/github-pages-deploy-action@v4 + with: + folder: _site + clean-exclude: ${{ env.PREVIEWS_FOLDER }} + force: false diff --git a/.github/workflows/first-time-setup.yaml b/.github/workflows/first-time-setup.yaml new file mode 100644 index 0000000000..0b867cf5bf --- /dev/null +++ b/.github/workflows/first-time-setup.yaml @@ -0,0 +1,111 @@ +name: first-time-setup +run-name: first time setup of repo + +on: + # run if user manually requests it + workflow_dispatch: + +permissions: + contents: write + +jobs: + first-time-setup: + runs-on: ubuntu-latest + + steps: + - name: Print contexts + uses: crazy-max/ghaction-dump-context@v1 + + - name: Create Pages branch + uses: peterjgrainger/action-create-branch@v2.4.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + branch: "gh-pages" + + - name: Checkout Pages branch + uses: actions/checkout@v3 + with: + ref: gh-pages + + - name: Clear Pages branch + run: rm -rf * .github .gitignore + + - name: Make .nojekyll file + run: touch .nojekyll + + - name: Make placeholder homepage + run: echo "Placeholder homepage" > index.html + + - name: Commit changes to Pages branch + uses: stefanzweifel/git-auto-commit-action@v4 + with: + branch: gh-pages + commit_message: "Clear branch" + + - name: Checkout main branch + uses: actions/checkout@v3 + + - name: Remove unneeded files + run: | + rm -rf \ + README.md \ + CHANGELOG.md \ + testbed.md \ + .github/ISSUE_TEMPLATE \ + .github/workflows/versioning.yaml \ + .github/pull_request_template.md \ + + - name: Set vars for personalization + run: | + user="${{ github.repository_owner }}" + description="An engaging 1-3 sentence description of your lab." + echo "USER=${user}" >> $GITHUB_ENV + echo "DESCRIPTION=${description}" >> $GITHUB_ENV + + - name: Personalize readme for user + run: | + echo " + # ${{ env.USER }}'s Website + + Visit **[website url](#)** 🚀 + + _Built with [Lab Website Template](https://greene-lab.gitbook.io/lab-website-template-docs)_ + " > README.md + + - name: Install packages + run: yarn add yaml + + - name: Personalize Jekyll config for user + uses: actions/github-script@v6 + with: + script: | + const { readFileSync, writeFileSync } = require("fs"); + const { parse, stringify } = require("yaml"); + const file = "_config.yaml"; + const config = parse(readFileSync(file).toString()); + config.title = "${{ env.USER }}"; + config.description = "${{ env.DESCRIPTION }}"; + config.email = "contact@${{ env.USER }}.com"; + config.github = "${{ env.USER }}"; + config.twitter = "${{ env.USER }}"; + config.instagram = "${{ env.USER }}"; + config.youtube = "${{ env.USER }}"; + writeFileSync(file, stringify(config)); + + - name: Personalize homepage for user + uses: actions/github-script@v6 + with: + script: | + const { readFileSync, writeFileSync } = require("fs"); + const file = "index.md"; + let contents = readFileSync(file).toString(); + const find = /\# Lab Website Template[\s\S]+({% include section\.html)/; + const replace = `# ${{ env.USER }}'s Website\n\n${{ env.DESCRIPTION }}\n\n$1`; + contents = contents.replace(find, replace); + writeFileSync(file, contents); + + - name: Commit changed files + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: "Setup repo" diff --git a/.github/workflows/on-pages.yaml b/.github/workflows/on-pages.yaml new file mode 100644 index 0000000000..b61c13b20e --- /dev/null +++ b/.github/workflows/on-pages.yaml @@ -0,0 +1,27 @@ +name: on-pages +run-name: on pages deploy + +on: + workflow_run: + workflows: [pages-build-deployment] + types: + - completed + branches: + - gh-pages + + # run if user manually requests it + workflow_dispatch: + +permissions: + contents: write + +jobs: + update-url: + # only run on user instance of template, not template itself + if: github.repository != 'greenelab/lab-website-template' + uses: ./.github/workflows/update-url.yaml + + build-site: + needs: update-url + if: needs.update-url.outputs.changed == 'true' + uses: ./.github/workflows/build-site.yaml diff --git a/.github/workflows/on-pull-request.yml b/.github/workflows/on-pull-request.yml new file mode 100644 index 0000000000..5cdf21a22d --- /dev/null +++ b/.github/workflows/on-pull-request.yml @@ -0,0 +1,22 @@ +name: on-pull-request +run-name: on pull request activity + +on: + pull_request_target: + types: + - opened + - reopened + - synchronize + - closed + +permissions: + contents: write + pull-requests: write + +jobs: + update-citations: + uses: ./.github/workflows/update-citations.yaml + + build-preview: + needs: update-citations + uses: ./.github/workflows/build-preview.yaml diff --git a/.github/workflows/on-push.yml b/.github/workflows/on-push.yml new file mode 100644 index 0000000000..06dd0013b6 --- /dev/null +++ b/.github/workflows/on-push.yml @@ -0,0 +1,24 @@ +name: on-push +run-name: on push to main + +on: + push: + branches: + - main + + # run if user manually requests it + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + update-citations: + # skip first run because nothing enabled or setup yet + if: github.run_number != 1 + uses: ./.github/workflows/update-citations.yaml + + build-site: + needs: update-citations + uses: ./.github/workflows/build-site.yaml diff --git a/.github/workflows/on-schedule.yaml b/.github/workflows/on-schedule.yaml new file mode 100644 index 0000000000..ad1fe95a7a --- /dev/null +++ b/.github/workflows/on-schedule.yaml @@ -0,0 +1,27 @@ +name: on-schedule +run-name: on schedule + +on: + schedule: + # weekly + - cron: "0 0 * * 1" + + # run if user manually requests it + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + update-citations: + # only run on user instance of template, not template itself + if: github.repository != 'greenelab/lab-website-template' + uses: ./.github/workflows/update-citations.yaml + with: + open-pr: true + + build-preview: + needs: update-citations + if: needs.update-citations.outputs.changed == 'true' + uses: ./.github/workflows/build-preview.yaml diff --git a/.github/workflows/update-citations.yaml b/.github/workflows/update-citations.yaml new file mode 100644 index 0000000000..21775acfec --- /dev/null +++ b/.github/workflows/update-citations.yaml @@ -0,0 +1,80 @@ +name: update-citations +run-name: update citations + +on: + # run when called from another workflow + workflow_call: + inputs: + open-pr: + type: boolean + outputs: + changed: + value: ${{ jobs.update-citations.outputs.changed }} + + # run if user manually requests it + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +env: + FORCE_COLOR: true + GOOGLE_SCHOLAR_API_KEY: ${{ secrets.GOOGLE_SCHOLAR_API_KEY }} + +jobs: + update-citations: + runs-on: ubuntu-latest + timeout-minutes: 15 + + steps: + - name: Print contexts + uses: crazy-max/ghaction-dump-context@v1 + + - name: Checkout branch contents + uses: actions/checkout@v3 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.head_ref }} + + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: "3.11" + cache: "pip" + cache-dependency-path: "**/requirements.txt" + + - name: Install Python packages + run: | + python -m pip install --upgrade --requirement ./_cite/requirements.txt + + - name: Build updated citations + run: python _cite/cite.py + timeout-minutes: 15 + + - name: Check if citations changed + id: changed + uses: tj-actions/verify-changed-files@v13 + with: + files: | + _data/citations.yaml + + - name: Commit updated citations to branch + if: | + steps.changed.outputs.files_changed == 'true' && + inputs.open-pr != true + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: "Update citations" + + - name: Open pull request with updated citations + if: | + steps.changed.outputs.files_changed == 'true' && + inputs.open-pr == true + uses: peter-evans/create-pull-request@v4 + with: + branch: citation-update + title: Periodic citation update + + outputs: + changed: ${{ steps.changed.outputs.files_changed }} diff --git a/.github/workflows/update-url.yaml b/.github/workflows/update-url.yaml new file mode 100644 index 0000000000..f1aba59193 --- /dev/null +++ b/.github/workflows/update-url.yaml @@ -0,0 +1,66 @@ +name: update-url +run-name: update site after url change + +on: + # run when called from another workflow + workflow_call: + outputs: + changed: + value: ${{ jobs.update-url.outputs.changed }} + + # run if user manually requests it + workflow_dispatch: + +permissions: + contents: write + +jobs: + update-url: + runs-on: ubuntu-latest + + steps: + - name: Print contexts + uses: crazy-max/ghaction-dump-context@v1 + + - name: Get Pages url + id: pages + uses: actions/configure-pages@v2 + with: + enablement: false + + - name: Checkout branch contents + uses: actions/checkout@v3 + + - name: Update readme + uses: actions/github-script@v6 + with: + script: | + const { readFileSync, writeFileSync } = require("fs"); + const file = "README.md"; + let contents = readFileSync(file).toString(); + const find = /\*\*\[.*\]\(.*\)\*\*/; + const host = "${{ steps.pages.outputs.host }}"; + const path = "${{ steps.pages.outputs.base_path }}"; + const url = "${{ steps.pages.outputs.base_url }}"; + const replace = `**[${host}${path}](${url})**`; + if (contents.match(find)) + contents = contents.replace(find, replace); + else + contents = `Visit ${replace} 🚀\n\n` + contents; + writeFileSync(file, contents); + + - name: Check if readme changed + id: changed + uses: tj-actions/verify-changed-files@v13 + with: + files: | + README.md + + - name: Commit changed files + if: steps.changed.outputs.files_changed == 'true' + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: "Update url" + + outputs: + changed: ${{ steps.changed.outputs.files_changed }} diff --git a/.github/workflows/versioning.yaml b/.github/workflows/versioning.yaml new file mode 100644 index 0000000000..f096235847 --- /dev/null +++ b/.github/workflows/versioning.yaml @@ -0,0 +1,135 @@ +name: versioning +run-name: versioning tasks + +on: + pull_request: + branches: + - main + push: + branches: + - main + +permissions: + contents: write + +jobs: + pull-request: + # only run on template itself, not user instance of template + if: | + github.repository == 'greenelab/lab-website-template' && + github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - name: Print contexts + uses: crazy-max/ghaction-dump-context@v1 + + - name: Checkout base branch contents + uses: actions/checkout@v3 + with: + ref: main + path: base + + - name: Checkout pr branch contents + uses: actions/checkout@v3 + with: + path: pr + + - name: Install packages + run: yarn add yaml semver + + - name: Check version, date, changelog + uses: actions/github-script@v6 + with: + script: | + const { readFileSync } = require("fs"); + const { lte, valid } = require("semver"); + const { parse } = require("yaml"); + + // load and parse file contents + const { version: oldVersion, "date-released": oldDate } = parse( + readFileSync("base/CITATION.cff").toString() + ); + const { version: newVersion, "date-released": newDate } = parse( + readFileSync("pr/CITATION.cff").toString() + ); + const changelog = readFileSync("pr/CHANGELOG.md") + .toString() + .split(/^##?#?#?/m) + .map((section) => { + const [heading, ...body] = section.split("\n"); + return [heading.trim(), body.join("\n").trim()]; + }); + + // check version + if (!valid(newVersion)) throw Error("Version not valid"); + if (lte(newVersion, oldVersion)) throw Error("Version not updated"); + + // check date + if (new Date(newDate).toISOString().split("T")[0] !== newDate) + throw Error("Date not valid"); + if (new Date(newDate) <= new Date(oldDate)) throw Error("Date not updated"); + + // check changelog + const newSection = changelog.find( + ([heading, body]) => + heading.includes(newVersion) && heading.includes(newDate) && body + ); + if (!newSection) throw Error("Changelog not updated or not valid"); + + push: + # only run on template itself, not user instance of template + if: | + github.repository == 'greenelab/lab-website-template' && + github.event_name == 'push' + runs-on: ubuntu-latest + steps: + - name: Print contexts + uses: crazy-max/ghaction-dump-context@v1 + + - name: Checkout branch contents + uses: actions/checkout@v3 + + - name: Install packages + run: yarn add yaml semver + + - name: Get version and body + id: version + uses: actions/github-script@v6 + with: + script: | + const { readFileSync } = require("fs"); + const { parse } = require("yaml"); + + // load and parse file contents + const { version, "date-released": date } = parse( + readFileSync("CITATION.cff").toString() + ); + const changelog = readFileSync("CHANGELOG.md") + .toString() + .split(/^##?#?#?/m) + .map((section) => { + const [heading, ...body] = section.split("\n"); + return [heading.trim(), body.join("\n").trim()]; + }); + + // find changelog body for version + const body = + changelog.find( + ([heading]) => heading.includes(version) && heading.includes(date) + )?.body || ""; + + return { version, body }; + + - name: Create a tag + id: tag + uses: mathieudutour/github-tag-action@v6.1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + custom_tag: ${{ fromJson(steps.version.outputs.result).version }} + + - name: Create a GitHub release + uses: ncipollo/release-action@v1 + with: + tag: ${{ fromJson(steps.version.outputs.result).version }} + name: ${{ fromJson(steps.version.outputs.result).version }} + body: ${{ fromJson(steps.version.outputs.result).body }} diff --git a/.gitignore b/.gitignore index 1a44b092e6..ce175e3fcf 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,10 @@ _site .jekyll-metadata vendor debug.log -__pycache__/ +__pycache__ .DS_STORE +.env* +package.json +package-lock.json +yarn.lock +node_modules diff --git a/404.md b/404.md index 2e8b91e20e..64b5a4abbe 100644 --- a/404.md +++ b/404.md @@ -3,7 +3,7 @@ title: 404 permalink: /404.html --- -## Page Not Found +## {% include icon.html icon="fa-solid fa-heart-crack" %} Page Not Found Try searching the whole site for the content you want: {:.center} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..cc0b7b3ae5 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,60 @@ +# Changelog + +Reference: common-changelog.org + +## 1.0.0 - 2023-02-28 + +First official release. + +High-level comparison with pre-releases: + +- Simpler configuration. +- More automation, less setup. +- More customization and flexibility. +- Redesigned components. +- New docs. +- Complete rewrite. +- Culmination of years of feedback. + +### Changed + +- Template is no longer limited to GitHub Pages white-listed Jekyll plugins. Any plugins possible. +- Pull request previews happen right within GitHub instead of needing Netlify. +- Better versioning. `CITATION.cff` file now source of truth for version, and tags/releases enforced. +- Citation-related files in `/_data` must now be named prefixed with the cite plugin they are to be run with, e.g. `sources-2020.yaml` or `orcid-students.yaml`. +- Folder renames for clarity and for better separation of template and user content: `/auto-cite` → `/_cite`, `/css` → `/_styles`, `/js` → `/_scripts`. +- Rename "Tools" page to "Projects" to be more clear and general purpose. +- Rename `extra-links` to `buttons` in `sources.yaml` files. +- Rename `theme.scss` to `-theme.scss`. +- Rename/repurpose components: link → button, two-col → cols, gallery → grid. +- Combine "link" and "role" data lists into single `types.yaml` map. +- Redesign components, change parameters and behavior. +- Update Font Awesome icon names from v5 to v6. +- Change placeholder text, images, and other images. +- Use CSS variables instead of Sass variables. +- Simplify caching method in cite process. +- Simplify Liquid code by including custom Ruby plugins. +- Simplify styles and scripts. + +### Added + +- New docs at greene-lab.gitbook.io/lab-website-template-docs. +- Add automations for first time setup and URL change. +- Write PubMed and Google Scholar automatic citation plugins. +- Automatic citations through GitHub Actions should now work from (most) forks. +- Add optional description and type params for citations. +- Add periodic cite process run that opens a pull request. +- List component filters can now accept arbitrary regex. +- Add light/dark mode toggle. +- Pre-install selection of useful Jekyll plugins, namely Jekyll Spaceship. +- Add author portrait and updated date for blog posts. +- Add richer metadata for SEO. +- Google Fonts link determined automatically from theme file. + +### Removed + +- Remove options from `_config.yaml` to simplify configuration: `baseurl`, `auto-cite`, `logo`. +- Remove `/favicons` folder, hardcode files for logo, icon, and share in `/images`. +- Remove `palettes.scss` and `mixins.scss`. +- Remove banner component (same thing can be achieved with full width section and figure components). +- Remove role component. Combine with portrait component. diff --git a/CITATION.cff b/CITATION.cff index d2c9a12041..62006acb90 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -1,6 +1,9 @@ -# GitHub citation metadata for lab-website-template itself +# citation metadata for the template itself -cff-version: 1.2.0 +title: "Lab Website Template" +version: 1.0.0 +date-released: 2023-02-28 +url: "https://github.com/greenelab/lab-website-template" authors: - family-names: "Rubinetti" given-names: "Vincent" @@ -8,7 +11,4 @@ authors: - family-names: "Greene" given-names: "Casey" orcid: "https://orcid.org/0000-0001-8713-9213" -title: "Lab Website Template" -version: 0.6.1 -date-released: 2022-06-22 -url: "https://github.com/greenelab/lab-website-template" +cff-version: 1.2.0 diff --git a/Gemfile b/Gemfile index 14ef227417..b39f041e80 100644 --- a/Gemfile +++ b/Gemfile @@ -1,29 +1,14 @@ source "https://rubygems.org" # jekyll -gem "jekyll" +gem "jekyll", "~> 4.3" gem "webrick", "~> 1.7" # plugins group :jekyll_plugins do + gem "jekyll-spaceship" + gem "jekyll-sitemap" gem "jekyll-redirect-from" gem "jekyll-feed" - gem "jekyll-sitemap" - - # other potentially useful plugins - # gem "jekyll-github-metadata" - # gem "jekyll-avatar" - # gem "jekyll-gist" - # gem "jekyll-mentions" - # gem "jekyll-relative-links" - # gem "jemoji" + gem "jekyll-last-modified-at" end - -# Windows stuff -platforms :mingw, :x64_mingw, :mswin, :jruby do - gem "tzinfo", "~> 1.2" - gem "tzinfo-data" -end -gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin] -gem "eventmachine", "1.2.7", git: "git@github.com:eventmachine/eventmachine", tag: "v1.2.7" if Gem.win_platform? # https://github.com/oneclick/rubyinstaller2/issues/96 - diff --git a/Gemfile.lock b/Gemfile.lock index 5b42ad9e41..cb7453394d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,92 +1,102 @@ GEM remote: https://rubygems.org/ specs: - addressable (2.7.0) - public_suffix (>= 2.0.2, < 5.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) colorator (1.1.0) - concurrent-ruby (1.1.8) - em-websocket (0.5.2) + concurrent-ruby (1.2.2) + em-websocket (0.5.3) eventmachine (>= 0.12.9) - http_parser.rb (~> 0.6.0) + http_parser.rb (~> 0) eventmachine (1.2.7) - eventmachine (1.2.7-x64-mingw32) - ffi (1.15.0) - ffi (1.15.0-x64-mingw32) + ffi (1.15.5) forwardable-extended (2.6.0) - http_parser.rb (0.6.0) - i18n (1.8.10) + gemoji (3.0.1) + google-protobuf (3.22.0-arm64-darwin) + http_parser.rb (0.8.0) + i18n (1.12.0) concurrent-ruby (~> 1.0) - jekyll (4.2.0) + jekyll (4.3.2) addressable (~> 2.4) colorator (~> 1.0) em-websocket (~> 0.5) i18n (~> 1.0) - jekyll-sass-converter (~> 2.0) + jekyll-sass-converter (>= 2.0, < 4.0) jekyll-watch (~> 2.0) - kramdown (~> 2.3) + kramdown (~> 2.3, >= 2.3.1) kramdown-parser-gfm (~> 1.0) liquid (~> 4.0) - mercenary (~> 0.4.0) + mercenary (>= 0.3.6, < 0.5) pathutil (~> 0.9) - rouge (~> 3.0) + rouge (>= 3.0, < 5.0) safe_yaml (~> 1.0) - terminal-table (~> 2.0) - jekyll-feed (0.15.1) + terminal-table (>= 1.8, < 4.0) + webrick (~> 1.7) + jekyll-feed (0.17.0) jekyll (>= 3.7, < 5.0) + jekyll-last-modified-at (1.3.0) + jekyll (>= 3.7, < 5.0) + posix-spawn (~> 0.3.9) jekyll-redirect-from (0.16.0) jekyll (>= 3.3, < 5.0) - jekyll-sass-converter (2.1.0) - sassc (> 2.0.1, < 3.0) + jekyll-sass-converter (3.0.0) + sass-embedded (~> 1.54) jekyll-sitemap (1.4.0) jekyll (>= 3.7, < 5.0) + jekyll-spaceship (0.10.2) + gemoji (~> 3.0) + jekyll (>= 3.6, < 5.0) + nokogiri (~> 1.6) + rainbow (~> 3.0) jekyll-watch (2.2.1) listen (~> 3.0) - kramdown (2.3.1) + kramdown (2.4.0) rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) - liquid (4.0.3) - listen (3.5.1) + liquid (4.0.4) + listen (3.8.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) mercenary (0.4.0) + nokogiri (1.13.10-arm64-darwin) + racc (~> 1.4) pathutil (0.16.2) forwardable-extended (~> 2.6) - public_suffix (4.0.6) - rb-fsevent (0.10.4) + posix-spawn (0.3.15) + public_suffix (5.0.1) + racc (1.6.2) + rainbow (3.1.1) + rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) rexml (3.2.5) - rouge (3.26.0) + rouge (3.30.0) safe_yaml (1.0.5) - sassc (2.4.0) - ffi (~> 1.9) - sassc (2.4.0-x64-mingw32) - ffi (~> 1.9) - terminal-table (2.0.0) - unicode-display_width (~> 1.1, >= 1.1.1) - thread_safe (0.3.6) - tzinfo (1.2.9) - thread_safe (~> 0.1) - tzinfo-data (1.2021.5) - tzinfo (>= 1.0.0) - unicode-display_width (1.7.0) - wdm (0.1.1) - webrick (1.7.0) + sass-embedded (1.58.3-arm64-darwin) + google-protobuf (~> 3.21) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + unicode-display_width (2.4.2) + webrick (1.8.1) PLATFORMS + aarch64-linux + linux universal-darwin-21 + universal-darwin-22 x64-mingw32 + x64-unknown + x86_64-linux DEPENDENCIES - jekyll + jekyll (~> 4.3) jekyll-feed + jekyll-last-modified-at jekyll-redirect-from jekyll-sitemap - tzinfo (~> 1.2) - tzinfo-data - wdm (~> 0.1.1) + jekyll-spaceship webrick (~> 1.7) BUNDLED WITH - 2.3.5 + 2.4.7 diff --git a/README.md b/README.md index a8fd55edb7..d8bac4da8b 100644 --- a/README.md +++ b/README.md @@ -1,59 +1,30 @@ -![GitHub last commit](https://img.shields.io/github/last-commit/greenelab/lab-website-template) -
- +
-An easy-to-use, flexible website template for labs, including automatic citations, GitHub tag imports, pre-built components, and more. -Spend less time reinventing the wheel and more time running your lab. - -#### 🔔 Still in pre-release/preview. We need testers! 🔔 - -Please help us out! -How easy is the template to use? -How flexible is it? -How's our documentation? - -## Features - -- **Automatically generated citations** (using [Manubot](https://manubot.org)) from **just an identifier** (DOI, PubMed ID, and many more) -- Automatically pull in and display tags from GitHub repositories -- Works and looks good on all major desktop and mobile browsers -- A suite of pre-built components: - - formatted tables and code blocks - - social media links with icons - - figures with captions - - image galleries - - multi-size cards with image and text - - citations - - ...and many more! -- A **home page**, where you can highlight the most important things that make your lab special -- A **research page**, with a sorted, searchable list of all your published works -- A **tools page**, where you can show off your software, datasets, or other useful things -- A **team** page, compiled automatically from individual members -- Individual **team member pages** with bios, assignable roles, and social media links -- A **blog page**, with a sorted, grouped, tagged list of all your posts - -## Gallery -[🖼️ See who else is using the template and what it can do!](https://github.com/greenelab/lab-website-template/wiki/Gallery) +Lab Website Template (LWT) is an easy-to-use, flexible website template for labs. +Spend less time worrying about managing a website and citations, and more time running your lab. -## Documentation +👇👇 **Get Started** 👇👇 -[▶️ Get Started](https://github.com/greenelab/lab-website-template/wiki/Get-Started) +[**📚 Documentation 📚**](https://greene-lab.gitbook.io/lab-website-template-docs) -[🗚 Basic Formatting](https://github.com/greenelab/lab-website-template/wiki/Basic-Formatting) +## Key Features -[📝 Basic Editing](https://github.com/greenelab/lab-website-template/wiki/Basic-Editing) +- 🤖 Based on Git, GitHub, and Jekyll. +- 📜 Automatically generated citations from simple identifiers (DOI, PubMed, ORCID, and many more) using Manubot. E.g. `doi:1234/5678` -> `title`, `authors`, `publisher`, `date`, etc. +- 🧱 A comprehensive and flexible suite of pre-made components (building blocks) for structuring and styling your website: + - Formatted tables, code blocks, figures, and other basic elements. + - Citations with thumbnails and other rich details. + - List large sets of data with flexible filters and components. + - ...many more +- 👁️ Automatic pull request previews. +- ⚙️ Easy and automated configuration. +- 👥 Team member pages with bios, roles, and social media links. +- 🖋️ Blog posts with tags and rich content. +- 📱 Works and looks good on desktop and mobile. +- 🤝 Great documentation and support (if we do say so ourselves). +- ... and much more! -[🤖 Citations](https://github.com/greenelab/lab-website-template/wiki/Citations) - -[⚙️ Advanced Editing](https://github.com/greenelab/lab-website-template/wiki/Advanced-Editing) - -[🧱 Components](https://github.com/greenelab/lab-website-template/wiki/Components) - -[🧠 Background Knowledge](https://github.com/greenelab/lab-website-template/wiki/Background-Knowledge) - -[💡 Tips](https://github.com/greenelab/lab-website-template/wiki/Tips) - -[❓ Support](https://github.com/greenelab/lab-website-template/wiki/Support) +![GitHub last commit](https://img.shields.io/github/last-commit/greenelab/lab-website-template) diff --git a/_cite/.cache/cache.db b/_cite/.cache/cache.db new file mode 100644 index 0000000000..13745ac887 Binary files /dev/null and b/_cite/.cache/cache.db differ diff --git a/_cite/cite.py b/_cite/cite.py new file mode 100644 index 0000000000..d6586c5cae --- /dev/null +++ b/_cite/cite.py @@ -0,0 +1,165 @@ +from importlib import import_module +from pathlib import Path +from dotenv import load_dotenv +from util import * + + +# load environment variables +load_dotenv() + + +# error flag +error = False + +# output citations file +output_file = "_data/citations.yaml" + + +log() + +log("Compiling sources") + +# master list of sources +sources = [] + +# in-order list of plugins to run +plugins = ["google-scholar", "pubmed", "orcid", "sources"] + +# loop through plugins +for plugin in plugins: + # convert into path object + plugin = Path(f"plugins/{plugin}.py") + + log(f"Running {plugin.stem} plugin") + + # get all data files to process with current plugin + files = Path.cwd().glob(f"_data/{plugin.stem}*.*") + files = list(filter(lambda p: p.suffix in [".yaml", ".yml", ".json"], files)) + + log(f"Found {len(files)} {plugin.stem}* data file(s)", 1) + + # loop through data files + for file in files: + log(f"Processing data file {file.name}", 1) + + # load data from file + try: + data = load_data(file) + # check if file in correct format + if not list_of_dicts(data): + raise Exception("File not a list of dicts") + except Exception as e: + log(e, 2, "ERROR") + error = True + continue + + # loop through data entries + for index, entry in enumerate(data): + log(f"Processing entry {index + 1} of {len(data)}, {label(entry)}", 2) + + # run plugin on data entry to expand into multiple sources + try: + entry = import_module(f"plugins.{plugin.stem}").main(entry) + # check that plugin returned correct format + if not list_of_dicts(entry): + raise Exception("Plugin didn't return list of dicts") + except Exception as e: + log(e, 3, "ERROR") + error = True + continue + + # loop through sources + for source in entry: + if plugin.stem != "sources": + log(label(source), 3) + + # include meta info about source + source["plugin"] = plugin.name + source["file"] = file.name + # add source to master list + sources.append(source) + + if plugin.stem != "sources": + log(f"{len(entry)} source(s)", 3) + + +# merge sources with matching (non-blank) ids +for a in range(0, len(sources)): + id = sources[a].get("id") + if not id: + continue + for b in range(a + 1, len(sources)): + if sources[b].get("id") == id: + sources[a].update(sources[b]) + sources[b] = {} +sources = [entry for entry in sources if entry] + + +log(f"{len(sources)} total source(s) to cite") + + +log() + +log("Generating citations") + +# list of new citations +citations = [] + +# loop through compiled sources +for index, source in enumerate(sources): + log(f"Processing source {index + 1} of {len(sources)}, {label(source)}") + + # new citation data for source + citation = {} + + # source id + id = source.get("id", "").strip() + + # Manubot doesn't work without an id + if id: + log("Using Manubot to generate citation", 1) + + try: + # run Manubot and set citation + citation = cite_with_manubot(source) + + except Exception as e: + # if manually-entered source, throw error on cite failure + if source.get("plugin") == "sources.py": + log(e, 3, "ERROR") + error = True + # otherwise, just warn + # (Manubot might not know how to cite every type of source from orcid, e.g.) + else: + log(e, 3, "WARNING") + + # preserve fields from input source, overriding existing fields + citation.update(source) + + # ensure date in proper format for correct date sorting + citation["date"] = format_date(citation.get("date")) + + # add new citation to list + citations.append(citation) + + +log() + +log("Saving updated citations") + +# save new citations +try: + save_data(output_file, citations) +except Exception as e: + log(e, level="ERROR") + error = True + + +# exit at end, so user can see all errors in one run +if error: + log("Error(s) occurred above", level="ERROR") + exit(1) +else: + log("All done!", level="SUCCESS") + +log("\n") diff --git a/_cite/plugins/google-scholar.py b/_cite/plugins/google-scholar.py new file mode 100644 index 0000000000..7132e5af7a --- /dev/null +++ b/_cite/plugins/google-scholar.py @@ -0,0 +1,61 @@ +import os +from serpapi import GoogleSearch +from util import * + + +def main(entry): + """ + receives single list entry from google-scholar data file + returns list of sources to cite + """ + + # get id from entry + id = entry.get("gsid") + if not id: + raise Exception('No "gsid" key') + + # get api key + api_key = os.environ.get("GOOGLE_SCHOLAR_API_KEY") + if not api_key: + raise Exception('No "GOOGLE_SCHOLAR_API_KEY" env var') + + # serp api + params = { + "engine": "google_scholar_author", + "author_id": id, + "api_key": api_key, + "num": 100, + } + + # query api + @log_cache + @cache.memoize(name=__file__, expire=1 * (60 * 60 * 24)) + def query(): + return GoogleSearch(params).get_dict().get("articles", []) + + response = query() + + # list of sources to return + sources = [] + + # go through response and format sources + for work in response: + + # create source + source = {} + + # format source fields + source["id"] = work.get("citation_id", "") + source["title"] = work.get("title", "") + source["authors"] = list(map(str.strip, work.get("authors", "").split(","))) + source["publisher"] = work.get("publication", "") + source["date"] = work.get("year", "") + "-01-01" + source["link"] = work.get("link", "") + + # copy fields from entry to source + source.update(entry) + + # add source to list + sources.append(source) + + return sources diff --git a/_cite/plugins/orcid.py b/_cite/plugins/orcid.py new file mode 100644 index 0000000000..28817482e5 --- /dev/null +++ b/_cite/plugins/orcid.py @@ -0,0 +1,51 @@ +import json +from urllib.request import Request, urlopen +from util import * + + +def main(entry): + """ + receives single list entry from orcid data file + returns list of sources to cite + """ + + # orcid api + endpoint = "https://pub.orcid.org/v2.0/$ORCID/works" + headers = {"Accept": "application/json"} + + # get id from entry + id = entry.get("orcid") + if not id: + raise Exception('No "orcid" key') + + # query api + @log_cache + @cache.memoize(name=__file__, expire=1 * (60 * 60 * 24)) + def query(): + url = endpoint.replace("$ORCID", id) + request = Request(url=url, headers=headers) + response = json.loads(urlopen(request).read()) + return response.get("group") + + response = query() + + # list of sources to return + sources = [] + + # go through response structure and pull out ids e.g. doi:1234/56789 + for work in response: + for id in work["external-ids"]["external-id"]: + # get id and id-type from response + id_type = id["external-id-type"] + id_value = id["external-id-value"] + + # create source + source = {"id": f"{id_type}:{id_value}"} + + # copy fields from entry to source + source.update(entry) + + # add source to list + sources.append(source) + + return sources diff --git a/_cite/plugins/pubmed.py b/_cite/plugins/pubmed.py new file mode 100644 index 0000000000..ac9fac7c66 --- /dev/null +++ b/_cite/plugins/pubmed.py @@ -0,0 +1,46 @@ +import json +from urllib.request import Request, urlopen +from urllib.parse import quote +from util import * + + +def main(entry): + """ + receives single list entry from pubmed data file + returns list of sources to cite + """ + + # ncbi api + endpoint = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=$TERM&retmode=json&retmax=1000&usehistory=y" + + # get id from entry + id = entry.get("term") + if not id: + raise Exception('No "term" key') + + # query api + @log_cache + @cache.memoize(name=__file__, expire=1 * (60 * 60 * 24)) + def query(): + url = endpoint.replace("$TERM", quote(id)) + request = Request(url=url) + response = json.loads(urlopen(request).read()) + return response.get("esearchresult", {}).get("idlist") + + response = query() + + # list of sources to return + sources = [] + + # go through response and format sources + for id in response: + # create source + source = {"id": f"pubmed:{id}"} + + # copy fields from entry to source + source.update(entry) + + # add source to list + sources.append(source) + + return sources diff --git a/_cite/plugins/sources.py b/_cite/plugins/sources.py new file mode 100644 index 0000000000..9dde4fa943 --- /dev/null +++ b/_cite/plugins/sources.py @@ -0,0 +1,6 @@ +def main(entry): + """ + receives single list entry from sources data file + returns list of sources to cite + """ + return [entry] diff --git a/_cite/requirements.txt b/_cite/requirements.txt new file mode 100644 index 0000000000..ce4f5d2822 --- /dev/null +++ b/_cite/requirements.txt @@ -0,0 +1,6 @@ +manubot==0.5.5 +PyYAML==6.0 +diskcache==5.4.0 +rich==12.6.0 +python-dotenv==0.21.0 +google-search-results==2.4.1 diff --git a/_cite/util.py b/_cite/util.py new file mode 100644 index 0000000000..c46ea0c241 --- /dev/null +++ b/_cite/util.py @@ -0,0 +1,213 @@ +import subprocess +import json +import yaml +from yaml.loader import SafeLoader +from pathlib import Path +from datetime import datetime +from rich import print +from diskcache import Cache + + +# cache for time-consuming network requests +cache = Cache("./_cite/.cache") + + +# clear expired items from cache +cache.expire() + + +def log_cache(func): + """ + decorator to use around memoized function to log if cached or or not + """ + + def wrap(*args): + key = func.__cache_key__(*args) + if key in cache: + log(" (from cache)", level="INFO", newline=False) + return func(*args) + + return wrap + + +def log(message="\n--------------------\n", indent=0, level="", newline=True): + """ + log to terminal, color determined by indent and level + """ + + palette = { + 0: "[orange1]", + 1: "[salmon1]", + 2: "[violet]", + 3: "[sky_blue1]", + "ERROR": "[white on #F43F5E]", + "WARNING": "[black on #EAB308]", + "SUCCESS": "[black on #10B981]", + "INFO": "[grey70]", + } + color = palette.get(level) or palette.get(indent) or "[white]" + if newline: + print() + print(indent * " " + color + str(message) + "[/]", end="", flush=True) + + +def label(entry): + """ + get "label" of dict entry + """ + + return list(entry.keys())[0] + ": " + list(entry.values())[0] + + +def list_of_dicts(data): + """ + check if data is list of dicts + """ + + return type(data) == list and all(type(entry) == dict for entry in data) + + +def format_date(date): + """ + format date as YYYY-MM-DD, or no date if malformed + """ + + try: + return datetime.strptime(date, "%Y-%m-%d").strftime("%Y-%m-%d") + except Exception: + return "" + + +def load_data(path): + """ + read data from yaml or json file + """ + + # convert to path object + path = Path(path) + + # check if file exists + if not path.is_file(): + raise Exception("Can't find file") + + # try to open file + try: + file = open(path, encoding="utf8") + except Exception as e: + raise Exception(e or "Can't open file") + + # try to parse as yaml + try: + with file: + data = yaml.load(file, Loader=SafeLoader) + except Exception: + raise Exception("Can't parse file. Make sure it's valid YAML.") + + # if no errors, return data + return data + + +def save_data(path, data): + """ + write data to yaml file + """ + + # convert to path object + path = Path(path) + + # try to open file + try: + file = open(path, mode="w") + except Exception: + raise Exception("Can't open file for writing") + + # prevent yaml anchors/aliases (pointers) + yaml.Dumper.ignore_aliases = lambda *args: True + + # try to save data as yaml + try: + with file: + yaml.dump(data, file, default_flow_style=False, sort_keys=False) + except Exception: + raise Exception("Can't save YAML to file") + + # write warning note to top of file + note = "# DO NOT EDIT, GENERATED AUTOMATICALLY" + try: + with open(path, "r") as file: + data = file.read() + with open(path, "w") as file: + file.write(f"{note}\n\n{data}") + except Exception: + raise Exception("Can't write to file") + + +@log_cache +@cache.memoize(name="manubot", expire=90 * (60 * 60 * 24)) +def cite_with_manubot(source): + """ + generate citation data for source with Manubot + """ + + # source id + id = source.get("id") + + # run Manubot + try: + commands = ["manubot", "cite", id, "--log-level=WARNING"] + output = subprocess.Popen(commands, stdout=subprocess.PIPE).communicate() + except Exception as e: + log(e, 3) + raise Exception("Manubot could not generate citation") + + # parse results as json + try: + manubot = json.loads(output[0])[0] + except Exception: + raise Exception("Couldn't parse Manubot response") + + # new citation with only needed info + citation = {} + + # original id + citation["id"] = id + + # title + citation["title"] = manubot.get("title", "") + + # authors + citation["authors"] = [] + for author in manubot.get("author", []): + given = author.get("given", "") + family = author.get("family", "") + citation["authors"].append(given + " " + family) + + # publisher + container = manubot.get("container-title", "") + collection = manubot.get("collection-title", "") + publisher = manubot.get("publisher", "") + citation["publisher"] = container or publisher or collection or "" + + # extract date part + def date_part(citation, index): + try: + return citation.get("issued").get("date-parts")[0][index] + except Exception: + return "" + + # date + year = date_part(manubot, 0) + if year: + # fallbacks for no month or day + month = date_part(manubot, 1) or "1" + day = date_part(manubot, 2) or "1" + citation["date"] = format_date(f"{year}-{month}-{day}") + else: + # if no year, consider date missing data + citation["date"] = "" + + # link + citation["link"] = manubot.get("URL", "") + + # return citation data + return citation diff --git a/_config.yaml b/_config.yaml index 32a5edf60a..a591c3e9a7 100644 --- a/_config.yaml +++ b/_config.yaml @@ -1,33 +1,23 @@ -### basic settings - # site properties and page defaults title: Lab Website Template +subtitle: by the Greene Lab description: An easy-to-use, flexible website template for labs, with automatic citations, GitHub tag imports, pre-built components, and more. -logo: images/logo.svg header: images/background.jpg footer: images/background.jpg -baseurl: /lab-website-template # site social media and other links links: - email: jane.smith@your-lab.com + email: contact@your-lab.com + orcid: 0000-0001-8713-9213 google-scholar: ETJoidYAAAAJ github: your-lab twitter: YourLabHandle instagram: YourLabHandle youtube: YourLabChannel -### advanced settings - -# automatic citations -auto-cite: - plugins: - - name: sources - input: - - ../_data/sources.yaml - output: ../_data/citations.yaml +### jekyll settings -# default front matter parameters for markdown files +# front matter defaults defaults: # all markdown files - scope: @@ -45,29 +35,39 @@ defaults: values: layout: post -# collections collections: + # generate page for each member members: output: true + # generate page for each post + posts: + output: true -# sass settings -sass: - sass_dir: css - -# syntax highlighting -highlighter: rouge - -# plugins +# jekyll plugins plugins: + - jekyll-spaceship + - jekyll-sitemap - jekyll-redirect-from - jekyll-feed - - jekyll-sitemap - # - jekyll-github-metadata - # - jekyll-avatar - # - jekyll-gist - # - jekyll-mentions - # - jekyll-relative-links - # - jemoji + - jekyll-last-modified-at + +# code block syntax highlighting +highlighter: rouge # jekyll theme theme: null + +# sass settings +sass: + sass_dir: _styles + +# force jekyll to include certain files/folders +include: + - _styles + - _scripts + +# force jekyll to exclude certain files/folders +exclude: + - README.md + - LICENSE.md + - CITATION.cff diff --git a/_data/citations.yaml b/_data/citations.yaml index 3f2716dbfa..b433cd7e77 100644 --- a/_data/citations.yaml +++ b/_data/citations.yaml @@ -1,21 +1,42 @@ -# DO NOT EDIT, GENERATED AUTOMATICALLY FROM SOURCES.YAML (AND ELSEWHERE) -# See https://github.com/greenelab/lab-website-template/wiki/Citations +# DO NOT EDIT, GENERATED AUTOMATICALLY -- id: doi:10.1016/j.csbj.2020.05.017 - title: Constructing knowledge graphs and their biomedical applications +- id: doi:10.1101/2023.01.05.522941 + title: Hetnet connectivity search provides rapid insights into how two biomedical + entities are related authors: + - Daniel S. Himmelstein + - Michael Zietz + - Vincent Rubinetti + - Kyle Kloster + - Benjamin J. Heil + - Faisal Alquaddoomi + - Dongbo Hu - David N. Nicholson + - Yun Hao + - Blair D. Sullivan + - Michael W. Nagle - Casey S. Greene - publisher: Computational and Structural Biotechnology Journal - date: '2020-06-02' - link: https://doi.org/gg7m48 - image: https://ars.els-cdn.com/content/image/1-s2.0-S2001037020302804-gr1.jpg - extra-links: - - type: manubot - link: https://greenelab.github.io/knowledge-graph-review/ - tags: - - knowledge graphs - _cache: 2b8aa76c98be2f26481ab15dc135eb446fa9ef6f94af175c9639d1a45d538cf4 + publisher: Cold Spring Harbor Laboratory + date: '2023-01-07' + link: https://doi.org/grmcb9 + orcid: 0000-0002-4655-3773 + plugin: orcid.py + file: orcid.yaml +- id: doi:10.1186/s13059-020-02021-3 + title: Compressing gene expression data using multiple latent space dimensionalities + learns complementary biological representations + authors: + - Gregory P. Way + - Michael Zietz + - Vincent Rubinetti + - Daniel S. Himmelstein + - Casey S. Greene + publisher: Genome Biology + date: '2020-05-11' + link: https://doi.org/gg2mjh + orcid: 0000-0002-4655-3773 + plugin: orcid.py + file: orcid.yaml - id: doi:10.1371/journal.pcbi.1007128 title: Open collaborative writing with Manubot authors: @@ -27,18 +48,53 @@ - Casey S. Greene - Anthony Gitter publisher: PLOS Computational Biology - date: '2019-06-24' + date: '2020-12-04' link: https://doi.org/c7np + orcid: 0000-0002-4655-3773 + plugin: sources.py + file: sources.yaml + type: paper + description: Lorem ipsum _dolor sit amet_, consectetur adipiscing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. image: https://journals.plos.org/ploscompbiol/article/figure/image?size=inline&id=info:doi/10.1371/journal.pcbi.1007128.g001&rev=2 - repo: greenelab/meta-review - extra-links: + buttons: - type: manubot link: https://greenelab.github.io/meta-review/ - type: source + text: Manuscript Source link: https://github.com/greenelab/meta-review - type: website link: http://manubot.org/ - _cache: 189b56e366896b6a90ae8d64fc4e605797d2bdd07674653d81ae533b2f1e4672 + tags: + - open science + - collaboration + repo: greenelab/meta-review +- id: doi:10.1101/573782 + title: Sequential compression of gene expression across dimensionalities and methods + reveals no single best method or dimensionality + authors: + - Gregory P. Way + - Michael Zietz + - Vincent Rubinetti + - Daniel S. Himmelstein + - Casey S. Greene + publisher: Cold Spring Harbor Laboratory + date: '2019-03-11' + link: https://doi.org/gfxjxf + orcid: 0000-0002-4655-3773 + plugin: orcid.py + file: orcid.yaml +- id: doi:10.1016/j.csbj.2020.05.017 + title: Constructing knowledge graphs and their biomedical applications + authors: + - David N. Nicholson + - Casey S. Greene + publisher: Computational and Structural Biotechnology Journal + date: '2020-01-01' + link: https://doi.org/gg7m48 + image: https://ars.els-cdn.com/content/image/1-s2.0-S2001037020302804-gr1.jpg + plugin: sources.py + file: sources.yaml - id: doi:10.7554/eLife.32822 title: Sci-Hub provides access to nearly all scholarly literature authors: @@ -53,15 +109,5 @@ date: '2018-03-01' link: https://doi.org/ckcj image: https://iiif.elifesciences.org/lax:32822%2Felife-32822-fig8-v3.tif/full/863,/0/default.webp - extra-links: - - type: preprint - link: https://doi.org/10.7287/peerj.preprints.3100v1 - - type: manubot - link: https://greenelab.github.io/scihub-manuscript/ - - type: source - link: https://github.com/greenelab/scihub-manuscript - text: Manuscript source - - type: source - link: https://github.com/greenelab/scihub - text: Analyses source - _cache: 483a564e9ddf847e6372cafb31de4673771c3e4da664c0d86a7ea7c38c20318d + plugin: sources.py + file: sources.yaml diff --git a/_data/links.yaml b/_data/links.yaml deleted file mode 100644 index 1f3b07f09b..0000000000 --- a/_data/links.yaml +++ /dev/null @@ -1,151 +0,0 @@ -# general - -link: - icon: fas fa-globe - text: Link - tooltip: Link - link: $LINK - -external: - icon: fas fa-external-link-alt - text: External Link - tooltip: External link - link: $LINK - -home-page: - icon: fas fa-home - text: Home Page - tooltip: Home page - link: $LINK - -email: - icon: fas fa-envelope - text: Email - tooltip: Email - link: mailto:$LINK - -phone: - icon: fas fa-phone - text: Phone Number - tooltip: Phone number - link: tel:$LINK - -address: - icon: fas fa-map-marked-alt - text: Address - tooltip: Address - link: $LINK - -search: - icon: fas fa-search - text: Search - tooltip: Search - link: $LINK - -# social media - -orcid: - icon: orcid-logo.svg - text: ORCID - tooltip: ORCID - link: https://orcid.org/$LINK - -google-scholar: - icon: fab fa-google - text: Google Scholar - tooltip: Google Scholar - link: https://scholar.google.com/citations?user=$LINK - -github: - icon: fab fa-github - text: GitHub - tooltip: GitHub - link: https://github.com/$LINK - -twitter: - icon: fab fa-twitter - text: Twitter - tooltip: Twitter - link: https://twitter.com/$LINK - -facebook: - icon: fab fa-facebook - text: Facebook - tooltip: Facebook - link: https://facebook.com/$LINK - -instagram: - icon: fab fa-instagram - text: Instagram - tooltip: Instagram - link: https://instagram.com/$LINK - -youtube: - icon: fab fa-youtube - text: YouTube - tooltip: YouTube - link: https://youtube.com/$LINK - -linkedin: - icon: fab fa-linkedin - text: LinkedIn - tooltip: LinkedIn - link: https://www.linkedin.com/in/$LINK - -# publications - -journal: - icon: far fa-newspaper - text: Journal - tooltip: Journal - link: $LINK - -preprint: - icon: far fa-eye - text: Preprint - tooltip: Preprint - link: $LINK - -manubot: - icon: manubot-logo.svg - text: Manubot - tooltip: Manubot - link: $LINK - -# software - -docs: - icon: fas fa-book - text: Docs - tooltip: Documentation - link: $LINK - -source: - icon: fas fa-code - text: Source - tooltip: Source code - link: $LINK - -server: - icon: fas fa-server - text: Server - tooltip: Server - link: $LINK - -app: - icon: fas fa-hand-pointer - text: App - tooltip: App - link: $LINK - -data: - icon: fas fa-database - text: Data - tooltip: Data - link: $LINK - -package: - icon: fas fa-box - text: Package - tooltip: Package - link: $LINK diff --git a/_data/orcid.yaml b/_data/orcid.yaml new file mode 100644 index 0000000000..005d3808fe --- /dev/null +++ b/_data/orcid.yaml @@ -0,0 +1 @@ +- orcid: 0000-0002-4655-3773 diff --git a/_data/tools.yaml b/_data/projects.yaml similarity index 50% rename from _data/tools.yaml rename to _data/projects.yaml index 8088f14479..b3eb2a7421 100644 --- a/_data/tools.yaml +++ b/_data/projects.yaml @@ -3,7 +3,7 @@ group: featured image: images/photo.jpg link: https://github.com/ - description: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + description: Lorem ipsum _dolor sit amet_, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. repo: greenelab/lab-website-template tags: - resource @@ -13,35 +13,35 @@ group: featured image: images/photo.jpg link: https://github.com/ - description: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + description: Lorem ipsum _dolor sit amet_, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. repo: greenelab/lab-website-template tags: - resource - title: Cool Tutorial - group: more + subtitle: a subtitle image: images/photo.jpg link: https://github.com/ - description: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + description: Lorem ipsum _dolor sit amet_, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. repo: greenelab/lab-website-template tags: - resource - publication - title: Cool Web App - group: more + subtitle: a subtitle image: images/photo.jpg link: https://github.com/ - description: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + description: Lorem ipsum _dolor sit amet_, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. repo: greenelab/lab-website-template tags: - software - title: Cool Web Server - group: more + subtitle: a subtitle image: images/photo.jpg link: https://github.com/ - description: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + description: Lorem ipsum _dolor sit amet_, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. repo: greenelab/lab-website-template tags: - software diff --git a/_data/roles.yaml b/_data/roles.yaml deleted file mode 100644 index 0ea8adbee8..0000000000 --- a/_data/roles.yaml +++ /dev/null @@ -1,23 +0,0 @@ -pi: - icon: fas fa-microscope - text: Principal Investigator - -postdoc: - icon: fas fa-glasses - text: Postdoctoral Researcher - -phd: - icon: fas fa-graduation-cap - text: PhD Student - -undergrad: - icon: fas fa-user-graduate - text: Undergraduate Student - -programmer: - icon: fas fa-code - text: Programmer - -mascot: - icon: fas fa-dog - text: Mascot diff --git a/_data/sources.yaml b/_data/sources.yaml index a054d27886..a1ddfed372 100644 --- a/_data/sources.yaml +++ b/_data/sources.yaml @@ -1,33 +1,23 @@ -- id: doi:10.1016/j.csbj.2020.05.017 - image: https://ars.els-cdn.com/content/image/1-s2.0-S2001037020302804-gr1.jpg - date: 2020-6-2 - extra-links: - - type: manubot - link: https://greenelab.github.io/knowledge-graph-review/ - tags: - - knowledge graphs - - id: doi:10.1371/journal.pcbi.1007128 + type: paper + description: Lorem ipsum _dolor sit amet_, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. + date: 2020-12-4 image: https://journals.plos.org/ploscompbiol/article/figure/image?size=inline&id=info:doi/10.1371/journal.pcbi.1007128.g001&rev=2 - repo: greenelab/meta-review - extra-links: + buttons: - type: manubot link: https://greenelab.github.io/meta-review/ - type: source + text: Manuscript Source link: https://github.com/greenelab/meta-review - type: website link: http://manubot.org/ + tags: + - open science + - collaboration + repo: greenelab/meta-review + +- id: doi:10.1016/j.csbj.2020.05.017 + image: https://ars.els-cdn.com/content/image/1-s2.0-S2001037020302804-gr1.jpg - id: doi:10.7554/eLife.32822 image: https://iiif.elifesciences.org/lax:32822%2Felife-32822-fig8-v3.tif/full/863,/0/default.webp - extra-links: - - type: preprint - link: https://doi.org/10.7287/peerj.preprints.3100v1 - - type: manubot - link: https://greenelab.github.io/scihub-manuscript/ - - type: source - link: https://github.com/greenelab/scihub-manuscript - text: Manuscript source - - type: source - link: https://github.com/greenelab/scihub - text: Analyses source diff --git a/_data/types.yaml b/_data/types.yaml new file mode 100644 index 0000000000..e733fee37b --- /dev/null +++ b/_data/types.yaml @@ -0,0 +1,190 @@ +# map general type to default/fallback icon, text, etc. + +# team member roles + +pi: + icon: fa-solid fa-microscope + description: Principal Investigator + +postdoc: + icon: fa-solid fa-glasses + description: Postdoctoral Researcher + +phd: + icon: fa-solid fa-graduation-cap + description: PhD Student + +undergrad: + icon: fa-solid fa-user-graduate + description: Undergraduate Student + +programmer: + icon: fa-solid fa-code + description: Programmer + +mascot: + icon: fa-solid fa-dog + description: Mascot + +# general + +link: + icon: fa-solid fa-globe + text: Link + tooltip: Link + +website: + icon: fa-solid fa-globe + text: Website + tooltip: Website + +external: + icon: fa-solid fa-up-right-from-square + text: External Link + tooltip: External link + +home-page: + icon: fa-solid fa-house-user + text: Home Page + tooltip: Home page + +email: + icon: fa-solid fa-envelope + text: Email + tooltip: Email + link: mailto:$VALUE + +phone: + icon: fa-solid fa-phone + text: Phone Number + tooltip: Phone number + link: tel:$VALUE + +address: + icon: fa-solid fa-map-location-dot + text: Address + tooltip: Address + +search: + icon: fa-solid fa-magnifying-glass + text: Search + tooltip: Search + +# social media + +orcid: + icon: orcid.svg + text: ORCID + tooltip: ORCID + link: https://orcid.org/$VALUE + +google-scholar: + icon: fa-brands fa-google + text: Google Scholar + tooltip: Google Scholar + link: https://scholar.google.com/citations?user=$VALUE + +github: + icon: fa-brands fa-github + text: GitHub + tooltip: GitHub + link: https://github.com/$VALUE + +twitter: + icon: fa-brands fa-twitter + text: Twitter + tooltip: Twitter + link: https://twitter.com/$VALUE + +facebook: + icon: fa-brands fa-facebook + text: Facebook + tooltip: Facebook + link: https://facebook.com/$VALUE + +instagram: + icon: fa-brands fa-instagram + text: Instagram + tooltip: Instagram + link: https://instagram.com/$VALUE + +youtube: + icon: fa-brands fa-youtube + text: YouTube + tooltip: YouTube + link: https://youtube.com/$VALUE + +linkedin: + icon: fa-brands fa-linkedin + text: LinkedIn + tooltip: LinkedIn + link: https://www.linkedin.com/in/$VALUE + +# publications + +paper: + icon: fa-solid fa-scroll + text: Paper + tooltip: Paper + +book: + icon: fa-solid fa-book + text: Book + tooltip: Book + +article: + icon: fa-solid fa-newspaper + text: Article + tooltip: Article + +journal: + icon: fa-regular fa-newspaper + text: Journal + tooltip: Journal + +preprint: + icon: fa-regular fa-eye + text: Preprint + tooltip: Preprint + +unpublished: + icon: fa-regular fa-eye + text: Unpublished + tooltip: Unpublished + +manubot: + icon: manubot.svg + text: Manubot + tooltip: Manubot + +# software + +docs: + icon: fa-solid fa-book + text: Documentation + tooltip: Documentation + +source: + icon: fa-solid fa-code + text: Source + tooltip: Source code + +server: + icon: fa-solid fa-server + text: Server + tooltip: Server + +app: + icon: fa-solid fa-hand-pointer + text: App + tooltip: App + +data: + icon: fa-solid fa-database + text: Data + tooltip: Data + +package: + icon: fa-solid fa-box + text: Package + tooltip: Package diff --git a/_includes/analytics.html b/_includes/analytics.html index 9ee4f444fc..6af67881a1 100644 --- a/_includes/analytics.html +++ b/_includes/analytics.html @@ -1 +1,3 @@ - + diff --git a/_includes/banner.html b/_includes/banner.html deleted file mode 100644 index 46d51fa578..0000000000 --- a/_includes/banner.html +++ /dev/null @@ -1,8 +0,0 @@ -{::nomarkdown} - -{:/} diff --git a/_includes/button.html b/_includes/button.html new file mode 100644 index 0000000000..913ab811c6 --- /dev/null +++ b/_includes/button.html @@ -0,0 +1,25 @@ +{% assign button = include %} +{% assign button = button | hash_default: site.data.types[include.type] %} + +{% if button.link or button.icon or button.text %} + +{% endif %} diff --git a/_includes/card.html b/_includes/card.html index b44f34d9a9..734782ac78 100644 --- a/_includes/card.html +++ b/_includes/card.html @@ -1,45 +1,44 @@ -{%- if include.style == "small" -%} - {%- assign width = 200 -%} -{%- else -%} - {%- assign width = 350 -%} -{%- endif -%} - -{%- assign placeholder = "images/placeholder.svg" | relative_url -%} - -{%- if include.link -%} - {%- assign tag = "a" -%} -{%- else -%} - {%- assign tag = "span" -%} -{%- endif -%} - -{::nomarkdown} - - <{{ tag }} href="{{ include.link | relative_url }}" class="card_image"> +{% if include.link %} + {% assign tag = "a" %} +{% else %} + {% assign tag = "span" %} +{% endif %} + +" + | remove: "
" + }} +{{ include.title }}
- {%- endif -%} +{{ include.title }}
+ {% endif %} {{ include.text | markdownify }}