diff --git a/.github/workflows/update-workshops.yml b/.github/workflows/update-workshops.yml new file mode 100644 index 0000000..82f2b35 --- /dev/null +++ b/.github/workflows/update-workshops.yml @@ -0,0 +1,41 @@ +name: Update Workshop Page + +on: + schedule: + - cron: '0 6 * * *' # Every day at 06:00 UTC + workflow_dispatch: # Optional: allows manual runs from the Actions tab + +jobs: + update-html: + runs-on: ubuntu-latest + + steps: + - name: Checkout main branch + uses: actions/checkout@v4 + with: + persist-credentials: false # We'll use a deploy token + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm install + + - name: Generate all_test.html + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: npm run generate + + - name: Commit and push if changed + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git config user.name "GitHub Actions" + git config user.email "actions@github.com" + git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }} + git add all_test.html featured_workshops.html + git diff --cached --quiet || git commit -m "Update workshop lists [auto]" + git push origin HEAD:master + diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index 6a6a3d8..0000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -2.6.1 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9198018..0000000 --- a/.travis.yml +++ /dev/null @@ -1,16 +0,0 @@ -language: ruby -rvm: - - current - -env: - global: - # speeds up installation of html-proofer - - NOKOGIRI_USE_SYSTEM_LIBRARIES=true - -# build and validate HTML files -# more info at https://github.com/gjtorikian/html-proofer -script: bundle exec jekyll build #&& bundle exec htmlproofer ./_site --alt-ignore '/.*/' - -cache: - directories: - - $TRAVIS_BUILD_DIR/tmp/.htmlproofer diff --git a/Gemfile b/Gemfile deleted file mode 100644 index 37f8c18..0000000 --- a/Gemfile +++ /dev/null @@ -1,7 +0,0 @@ -source 'https://rubygems.org' - -gem 'jekyll' - -group :test do - gem 'html-proofer' -end diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index 8d12910..0000000 --- a/Gemfile.lock +++ /dev/null @@ -1,88 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - addressable (2.7.0) - public_suffix (>= 2.0.2, < 5.0) - colorator (1.1.0) - concurrent-ruby (1.1.7) - em-websocket (0.5.2) - eventmachine (>= 0.12.9) - http_parser.rb (~> 0.6.0) - ethon (0.12.0) - ffi (>= 1.3.0) - eventmachine (1.2.7) - ffi (1.13.1) - forwardable-extended (2.6.0) - html-proofer (3.16.0) - addressable (~> 2.3) - mercenary (~> 0.3) - nokogumbo (~> 2.0) - parallel (~> 1.3) - rainbow (~> 3.0) - typhoeus (~> 1.3) - yell (~> 2.0) - http_parser.rb (0.6.0) - i18n (1.8.5) - concurrent-ruby (~> 1.0) - jekyll (4.1.1) - addressable (~> 2.4) - colorator (~> 1.0) - em-websocket (~> 0.5) - i18n (~> 1.0) - jekyll-sass-converter (~> 2.0) - jekyll-watch (~> 2.0) - kramdown (~> 2.1) - kramdown-parser-gfm (~> 1.0) - liquid (~> 4.0) - mercenary (~> 0.4.0) - pathutil (~> 0.9) - rouge (~> 3.0) - safe_yaml (~> 1.0) - terminal-table (~> 1.8) - jekyll-sass-converter (2.1.0) - sassc (> 2.0.1, < 3.0) - jekyll-watch (2.2.1) - listen (~> 3.0) - kramdown (2.3.0) - rexml - kramdown-parser-gfm (1.1.0) - kramdown (~> 2.0) - liquid (4.0.3) - listen (3.2.1) - rb-fsevent (~> 0.10, >= 0.10.3) - rb-inotify (~> 0.9, >= 0.9.10) - mercenary (0.4.0) - mini_portile2 (2.4.0) - nokogiri (1.10.10) - mini_portile2 (~> 2.4.0) - nokogumbo (2.0.2) - nokogiri (~> 1.8, >= 1.8.4) - parallel (1.19.2) - pathutil (0.16.2) - forwardable-extended (~> 2.6) - public_suffix (4.0.6) - rainbow (3.0.0) - rb-fsevent (0.10.4) - rb-inotify (0.10.1) - ffi (~> 1.0) - rexml (3.2.4) - rouge (3.23.0) - safe_yaml (1.0.5) - sassc (2.4.0) - ffi (~> 1.9) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - typhoeus (1.4.0) - ethon (>= 0.9.0) - unicode-display_width (1.7.0) - yell (2.2.2) - -PLATFORMS - ruby - -DEPENDENCIES - html-proofer - jekyll - -BUNDLED WITH - 1.17.3 diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 1f78246..b2db644 100644 --- a/README.md +++ b/README.md @@ -1,52 +1,26 @@ -Square Open Source Portal -========================= +## About -[![Build Status](https://travis-ci.org/square/square.github.io.svg?branch=master)](https://travis-ci.org/square/square.github.io) +This repository is a landing page for UBC Library Research Commons workshops. -A simple, static portal which outlines our open source offerings. Intentionally -themed to look like a Square merchant page on the directory. +View the main page here: https://ubc-library-rc.github.io/ and a listing of all workshops here: https://ubc-library-rc.github.io/all.html. +## Code +Code for this landing page is forked from . The source material is published with an Apache 2.0 license and was modified in these ways: +- deleted files not required in the Research Commons context +- added *all.html* file (includes code from *index.html*) +- edited *index.html* file -Development ------------ +## License +Copyright 2023 UBC Library Research Commons. -### Run the site locally -```bash -gem install bundler # first time only -bundle install # first time only -bundle exec jekyll serve -``` +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + -### Update list of repos: -```bash -pip install pystache requests pygithub3 # first time only -./generate.py -``` - -About the code ------------ -Due to the use of absolute URLs in CSS files that are (essentially) out of our -control, the easiest way to develop is by running with Jekyll. - -Repositories are listed in the `repos.json` file as a map of repository names -to a list of their categories. Invoking the `generate.py` script will update -the `index.html` page with the latest repos by using the `index.mustache` file -as a template. - -Repository data is pulled via the GitHub API (e.g., website). By default the -script performs unauthenticated requests, so it's easy to run up against -GitHub's limit of [60 unauthenticated requests per -hour](http://developer.github.com/v3/#rate-limiting). To make authenticated -requests and work around the rate-limiting, add an entry for api.github.com to -your ~/.netrc file, preferably with a Personal Access Token from -https://github.com/settings/tokens - - machine api.github.com - login YourUsername - password PersonalAccessToken - -Images are loaded by convention from the `repo_images/` directory. Ensure the -name is the same as the repo name in the `repos.json` file and has a `.jpg` -extension. Currently all images are rotated 10 degrees counter-clockwise to -break up the overwhelming horizontal and vertical visual lines on the page. +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/all.html b/all.html new file mode 100644 index 0000000..381f271 --- /dev/null +++ b/all.html @@ -0,0 +1,429 @@ + + + + + + Codestin Search App + + + + + + + + +
+
+
+ + +
+ +
+ + +
+

+ List of past and present workshops offered by the Research Commons +

+
+ + +
+
+
+ +
+ +
+ + + + diff --git a/all_test.html b/all_test.html new file mode 100644 index 0000000..1907fdd --- /dev/null +++ b/all_test.html @@ -0,0 +1,122 @@ + + + + + Codestin Search App + + + +
+
+
+ UBC Research Commons logo +
+
+ UBC Library Research Commons +
+ +
+
+

Past and present workshops offered by the Research Commons

+

For currently scheduled workshops visit https://researchcommons.library.ubc.ca/events/

+
+

Data analysis and visualization

+ +
+ +
+

Digital scholarship

+ +
+ +
+

Geographic information systems (GIS) and mapping

+ +
+
+

Research Data Management (RDM)

+ +
+
+

Citation management

+ +
+ + + + \ No newline at end of file diff --git a/assets/public/favicon.ico b/assets/public/favicon.ico index 160f8a7..18a4870 100644 Binary files a/assets/public/favicon.ico and b/assets/public/favicon.ico differ diff --git a/featured_workshops.html b/featured_workshops.html new file mode 100644 index 0000000..7b8cfea --- /dev/null +++ b/featured_workshops.html @@ -0,0 +1,143 @@ + + + + + Codestin Search App + + + +
+
+
+ UBC Research Commons logo +
+
+ UBC Library Research Commons +
+ +
+
+

Featured Workshops

+
+

Data analysis and visualization

+
+
+ AI for coding (beginner) +

This beginner workshop provides bite-sized overviews of how ChatGPT and other LLMs can help with various aspects of coding in R. These principles can be transferred to other coding languages.

+
+
+ Data manipulation with *dplyr* +

Data manipulation is a crucial part of data visualization and analysis. This workshop introduces common functions in the dplyr package to manipulate rows and columns.

+
+
+ Data visualization with ggplot2 +

Through this workshop introduces participants to the skills to make effective, eye-catching, and reproducible visualizations using the ggplot2 package in R.

+
+
+ Intro to data visualization with Tableau +

This workshop introduces the basics of visualizing data in Tableau software. It includes hands on practice with a Statistics Canada dataset about labour and employment in Canada for selected months in 2020. By the end of the session participants will be able to create simple, clear graphs from the data.

+
+
+ R showcase: Statistics Canada microdata +

This workshop demonstrates how to access, explore, and analyze Statistics Canada microdata using R.

+
+
+
+ +
+

Digital scholarship

+
+
+ Introduction to Docker +

Introduces the set of virtualization tools referred to as Docker, to create and share small reproducible computing environments.

+
+
+ Introduction to Git and GitHub +

Adapted from the Carpentries, introduces the basics of Git and GitHub for version control and collaboration.

+
+
+ Introduction to Jekyll and GitHub Pages +

Teaches participants how to use Jekyll and GitHub Pages to quickly and easily publish a static website using only a browser.

+
+
+ Introduction to the Unix Shell +

Adapted from the Carpentries, this workshop is intended to orient complete beginners to the Unix shell.

+
+
+
+ +
+

Geographic information systems (GIS) and mapping

+
+
+ Introduction to StoryMaps with ArcGIS Online +

This workshop is a gentle introduction to creating StoryMaps using the ArcGIS Online platform. StoryMaps offer a low-barrier way to visualize spatial narratives that can be shared with your friends, community, or stakeholders. The StoryMaps interface is quite intuitive, with drag and drop options that result in an aesthetic output. No prior experience necessary. This workshop makes use of the **free** account option, though you are welcome to work within a personal or organizational account if you have a paid subscription.

+
+
+ Introduction to Web Maps with Leaflet.js +

This beginner-level workshop guides participants on how to make interactive maps, with a focus on Leaflet.js as a tool to do so.

+
+
+ Map Production with QGIS +

This is an introductory workshop focusing on the fundamental concepts and skills needed to begin using QGIS to explore and analyze spatial data.

+
+
+ Plugins in QGIS +

This workshop is meant to extend basic knowledge of QGIS by exploring common plugins.

+
+
+ Telling Spatial Stories +

This workshop introduces a variety of mapping tools and processes for novices wanting to get started with creating maps and spatial visualizations.

+
+
+ Tools and Workflows in QGIS +

This intermediate-level workshop is focused on common tools and workflows in QGIS. By the end of this workshop, participants will be able to set up a QGIS project, find and load data onto a basemap, edit vector data from inside the GIS interface, perform joins and selections, and answer spatial questions using basic vector analysis. Familiarity with GIS is prerequisite for this workshop.

+
+
+
+
+

Research Data Management (RDM)

+
+
+ File naming +

Learn how to name your data files

+
+
+ File formatting +

Learn what data formats to use

+
+
+ Create a README file +

Learn how to create good README files

+
+
+ Create a data dictionary +

Learn how to create a good data dictionary or a code book

+
+
+ Directories structure +

Learn to organize your data directories

+
+
+ Introduction to Markdown for research data +

Learn how to use Markdown with research data

+
+
+ Deposit in UBC Dataverse Collection: Basic deposit +

Learn how to deposit your data in Borealis repository

+
+
+ Create a Data Management Plan (DMP) +

Learn how to create a variety of Data Management Plans

+
+
+ Create a Simplified Data Management Plan +

Learn how to create a Simplified Data Management Plan for the Tri-Agency grant applications

+
+
+
+ + + \ No newline at end of file diff --git a/generate.py b/generate.py deleted file mode 100755 index de2631c..0000000 --- a/generate.py +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env python - -from collections import defaultdict -import codecs -import json -import os -import pystache -import requests -import time -import netrc -from pygithub3 import Github - -repos_in = 'repos.json' -index_in = 'index.mustache' -index_out = 'index.html' - -auth = netrc.netrc() -try: - (login, _, password) = auth.authenticators('api.github.com') - ghclient = Github(login=login, password=password) - logged_in = True -except: - ghclient = Github() - logged_in = False - -def gh_repo(name): - print('Fetching "%s" repo information...' % name) - # Use the following for development so you do not hammer the GitHub API. - #return {'name': name, 'html_url': 'http://google.com', 'homepage': 'http://example.com', 'description': 'Description!'} - - if not logged_in: - time.sleep(2.0) # Take a nap so GitHub doesn't aggressively throttle us. - - repo = ghclient.repos.get(user='square', repo=name) - return dict( - name=repo.name, - homepage=repo.homepage, - html_url=repo.html_url, - description=repo.description - ) - -with codecs.open(index_in, 'r', 'utf-8') as f: - template = pystache.parse(f.read()) -with codecs.open(repos_in, 'r', 'utf-8') as f: - repo_config = json.loads(f.read()) - -repos = repo_config['repos'] -custom = repo_config['custom'] - -# Multimap of categories to their repos. -categories = defaultdict(list) - -# Loop through declared repos, looking up their info on GitHub and adding to the specified categories. -for repo in repos.keys(): - repo_cats = repos[repo] - repo_data = gh_repo(repo) - if repo_cats is None: - repo_cats = ['Other'] - for repo_cat in repo_cats: - categories[repo_cat].append(repo_data) - -# Loop though custom repos adding their data (faked to look like GitHub's) to the specified categories. -for repo_data in custom: - repo_cats = repo_data['categories'] - if repo_cats is None: - repo_cats = ['Other'] - for repo_cat in repo_cats: - categories[repo_cat].append(repo_data) - - -# Template context that will be used for rendering. -context = { - 'categories': [] -} - -# Loop over the category names sorted alphabetically (case-insensitive) with 'Other' last. -for category_name in sorted(categories.keys(), key=lambda s: s.lower() if s is not 'Other' else 'z'*10): - data = { - 'name': category_name, - 'index': category_name.lower(), - 'has_repos_with_images': False, - 'has_repos_without_images': False, - 'repos_with_images': [], - 'repos_without_images': [], - } - - # Loop over category repos sorted alphabetically (case-insensitive). - for repo_data in sorted(categories[category_name], key=lambda s: s['name'].lower()): - name = repo_data['name'] - repo = { - 'name': name, - 'href': repo_data['html_url'], - 'website': repo_data.get('homepage', None), - 'description': repo_data.get('description', None) - } - if os.path.exists(os.path.join('repo_images', '%s.jpg' % name)): - data['repos_with_images'].append(repo) - data['has_repos_with_images'] = True - else: - data['repos_without_images'].append(repo) - data['has_repos_without_images'] = True - - context['categories'].append(data) - -# Render the page HTML using MOOOUUSSTTAACCCCHHEEEEE! -renderer = pystache.Renderer() -html = renderer.render(template, context) - -with codecs.open(index_out, 'w', 'utf-8') as f: - f.write(html) - -# Rejoice. If you got this far, it worked! diff --git a/images/rc-logo-square.png b/images/rc-logo-square.png new file mode 100644 index 0000000..6fd7dcb Binary files /dev/null and b/images/rc-logo-square.png differ diff --git a/images/rc-logo.png b/images/rc-logo.png new file mode 100644 index 0000000..3ec3046 Binary files /dev/null and b/images/rc-logo.png differ diff --git a/images/ubc-logo.png b/images/ubc-logo.png new file mode 100644 index 0000000..ddcdac8 Binary files /dev/null and b/images/ubc-logo.png differ diff --git a/index.html b/index.html index e14ae9b..81529a8 100644 --- a/index.html +++ b/index.html @@ -1,11 +1,20 @@ + - - Codestin Search App - + + Codestin Search App + - + @@ -16,15 +25,20 @@
@@ -33,735 +47,678 @@

Square Open Source

-

As a company built on open source, here are some of the internally-developed libraries we have contributed back to the community.

+

+ Selected workshop materials in open formats to view and use + anytime +

+ + + + + + +
+ View full list of GitHub repositories + +
+ + diff --git a/index.mustache b/index.mustache deleted file mode 100644 index ec23a2a..0000000 --- a/index.mustache +++ /dev/null @@ -1,142 +0,0 @@ - - - - - Codestin Search App - - - - - - - - -
-
-
- - -
- -
- - -
-

As a company built on open source, here are some of the internally-developed libraries we have contributed back to the community.

-
- - - -
- -
-
-
-
- - - - - - diff --git a/non_repo_featured_workshops.html b/non_repo_featured_workshops.html new file mode 100644 index 0000000..067f77a --- /dev/null +++ b/non_repo_featured_workshops.html @@ -0,0 +1,41 @@ +
+

Research Data Management (RDM)

+
+
+ File naming +

Learn how to name your data files

+
+
+ File formatting +

Learn what data formats to use

+
+
+ Create a README file +

Learn how to create good README files

+
+
+ Create a data dictionary +

Learn how to create a good data dictionary or a code book

+
+
+ Directories structure +

Learn to organize your data directories

+
+
+ Introduction to Markdown for research data +

Learn how to use Markdown with research data

+
+
+ Deposit in UBC Dataverse Collection: Basic deposit +

Learn how to deposit your data in Borealis repository

+
+
+ Create a Data Management Plan (DMP) +

Learn how to create a variety of Data Management Plans

+
+
+ Create a Simplified Data Management Plan +

Learn how to create a Simplified Data Management Plan for the Tri-Agency grant applications

+
+
+
diff --git a/non_repo_workshops.html b/non_repo_workshops.html new file mode 100644 index 0000000..818a5ef --- /dev/null +++ b/non_repo_workshops.html @@ -0,0 +1,30 @@ +
+

Research Data Management (RDM)

+ +
+
+

Citation management

+ +
+ diff --git a/package.json b/package.json new file mode 100644 index 0000000..6ab8f8a --- /dev/null +++ b/package.json @@ -0,0 +1,7 @@ +{ + "name": "ubc-rc-html-builder", + "type": "module", + "scripts": { + "generate": "node scripts/generate.js" + } +} diff --git a/repo_images/PonyDebugger.jpg b/repo_images/PonyDebugger.jpg deleted file mode 100644 index 38e3fb0..0000000 Binary files a/repo_images/PonyDebugger.jpg and /dev/null differ diff --git a/repo_images/android-times-square.jpg b/repo_images/android-times-square.jpg deleted file mode 100644 index a3e9a8d..0000000 Binary files a/repo_images/android-times-square.jpg and /dev/null differ diff --git a/repo_images/assertj-android.jpg b/repo_images/assertj-android.jpg deleted file mode 100644 index 211bf14..0000000 Binary files a/repo_images/assertj-android.jpg and /dev/null differ diff --git a/repo_images/beancounter.jpg b/repo_images/beancounter.jpg deleted file mode 100644 index f561abc..0000000 Binary files a/repo_images/beancounter.jpg and /dev/null differ diff --git a/repo_images/crossfilter.jpg b/repo_images/crossfilter.jpg deleted file mode 100644 index a8bf457..0000000 Binary files a/repo_images/crossfilter.jpg and /dev/null differ diff --git a/repo_images/cube.jpg b/repo_images/cube.jpg deleted file mode 100644 index 2f5486b..0000000 Binary files a/repo_images/cube.jpg and /dev/null differ diff --git a/repo_images/cubism.jpg b/repo_images/cubism.jpg deleted file mode 100644 index 9e45303..0000000 Binary files a/repo_images/cubism.jpg and /dev/null differ diff --git a/repo_images/dagger.jpg b/repo_images/dagger.jpg deleted file mode 100644 index a46f0ed..0000000 Binary files a/repo_images/dagger.jpg and /dev/null differ diff --git a/repo_images/es6-module-transpiler.jpg b/repo_images/es6-module-transpiler.jpg deleted file mode 100644 index a037ae3..0000000 Binary files a/repo_images/es6-module-transpiler.jpg and /dev/null differ diff --git a/repo_images/field-kit.jpg b/repo_images/field-kit.jpg deleted file mode 100644 index 1873d36..0000000 Binary files a/repo_images/field-kit.jpg and /dev/null differ diff --git a/repo_images/kotlinpoet.jpg b/repo_images/kotlinpoet.jpg deleted file mode 100644 index b81a91f..0000000 Binary files a/repo_images/kotlinpoet.jpg and /dev/null differ diff --git a/repo_images/leakcanary.jpg b/repo_images/leakcanary.jpg deleted file mode 100644 index 41fbc06..0000000 Binary files a/repo_images/leakcanary.jpg and /dev/null differ diff --git a/repo_images/lgtm.jpg b/repo_images/lgtm.jpg deleted file mode 100644 index 96f99aa..0000000 Binary files a/repo_images/lgtm.jpg and /dev/null differ diff --git a/repo_images/moshi.jpg b/repo_images/moshi.jpg deleted file mode 100644 index bd31fa6..0000000 Binary files a/repo_images/moshi.jpg and /dev/null differ diff --git a/repo_images/objc-TimesSquare.jpg b/repo_images/objc-TimesSquare.jpg deleted file mode 100644 index a53f4bf..0000000 Binary files a/repo_images/objc-TimesSquare.jpg and /dev/null differ diff --git a/repo_images/okhttp.jpg b/repo_images/okhttp.jpg deleted file mode 100644 index e2a8c8f..0000000 Binary files a/repo_images/okhttp.jpg and /dev/null differ diff --git a/repo_images/okio.jpg b/repo_images/okio.jpg deleted file mode 100644 index bfda06b..0000000 Binary files a/repo_images/okio.jpg and /dev/null differ diff --git a/repo_images/otto.jpg b/repo_images/otto.jpg deleted file mode 100644 index 0af4568..0000000 Binary files a/repo_images/otto.jpg and /dev/null differ diff --git a/repo_images/picasso.jpg b/repo_images/picasso.jpg deleted file mode 100644 index d66bf4f..0000000 Binary files a/repo_images/picasso.jpg and /dev/null differ diff --git a/repo_images/pollexor.jpg b/repo_images/pollexor.jpg deleted file mode 100644 index b55b9c5..0000000 Binary files a/repo_images/pollexor.jpg and /dev/null differ diff --git a/repo_images/retrofit.jpg b/repo_images/retrofit.jpg deleted file mode 100644 index c5eff1e..0000000 Binary files a/repo_images/retrofit.jpg and /dev/null differ diff --git a/repo_images/shuttle.jpg b/repo_images/shuttle.jpg deleted file mode 100644 index 7c2569c..0000000 Binary files a/repo_images/shuttle.jpg and /dev/null differ diff --git a/repo_images/spacecommander.jpg b/repo_images/spacecommander.jpg deleted file mode 100644 index e856dd2..0000000 Binary files a/repo_images/spacecommander.jpg and /dev/null differ diff --git a/repo_images/spoon.jpg b/repo_images/spoon.jpg deleted file mode 100644 index 0a6f659..0000000 Binary files a/repo_images/spoon.jpg and /dev/null differ diff --git a/repo_images/squash.jpg b/repo_images/squash.jpg deleted file mode 100644 index 6c588e7..0000000 Binary files a/repo_images/squash.jpg and /dev/null differ diff --git a/repo_images/subzero.jpg b/repo_images/subzero.jpg deleted file mode 100644 index d2e2b0d..0000000 Binary files a/repo_images/subzero.jpg and /dev/null differ diff --git a/repo_images/wire.jpg b/repo_images/wire.jpg deleted file mode 100644 index 55126f8..0000000 Binary files a/repo_images/wire.jpg and /dev/null differ diff --git a/repos.json b/repos.json deleted file mode 100644 index 4c5ba77..0000000 --- a/repos.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "repos": { - "Aardvark": ["iOS"], - "Ackbar": ["iOS"], - "android-times-square": ["Android"], - "assertj-android": ["Android"], - "beancounter": ["Go"], - "border_patrol": ["Ruby"], - "cane": ["Ruby"], - "certigo": ["Go"], - "certstrap": ["Go"], - "Cleanse": ["iOS"], - "crossfilter": ["JavaScript"], - "cube": ["JavaScript"], - "cubism": ["JavaScript"], - "ETL": ["Ruby"], - "fdoc": ["Ruby"], - "field-kit": ["JavaScript"], - "ghostunnel": ["Go"], - "go-jose": ["Go"], - "gssh": ["Go"], - "JavaPoet": ["Java"], - "jetpack": ["Ruby"], - "jirafy": ["Other"], - "js-jose": ["JavaScript"], - "Keywhiz": ["Java"], - "KotlinPoet": ["Kotlin"], - "leakcanary": ["Android", "Kotlin"], - "LGTM": ["JavaScript"], - "metrics": ["Go"], - "moshi": ["Android", "Java"], - "okhttp": ["Android", "Java", "Kotlin"], - "okio": ["Android", "Java", "Kotlin"], - "p2": ["Other"], - "picasso": ["Android"], - "pollexor": ["Android", "Java"], - "PonyDebugger": ["iOS"], - "rack-servlet": ["Java"], - "rails-auth": ["Ruby"], - "retrofit": ["Android", "Java", "Kotlin"], - "seismic": ["Android"], - "shift": ["Other"], - "shuttle": ["Other"], - "spacecommander": ["iOS"], - "spoon": ["Android"], - "sqldelight": ["Android", "iOS", "Kotlin"], - "squalor": ["Go"], - "subzero": ["C", "Java", "Go"], - "SuperDelegate": ["iOS"], - "tape": ["Android"], - "toggle": null, - "Valet": ["iOS"], - "wire": ["Android", "Java", "Kotlin"], - "workflow": ["Android", "iOS", "Kotlin"] - }, - "custom": [ - { - "name": "es6-module-transpiler", - "homepage": "http://esnext.github.io/es6-module-transpiler/", - "html_url": "https://github.com/esnext/es6-module-transpiler", - "description": "Tomorrow’s JavaScript module syntax today", - "categories": ["JavaScript"] - } - ] -} diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index c8fc0a0..0000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -pygithub3==0.5.1 -pystache==0.5.4 -requests==2.20.0 diff --git a/scripts/generate.js b/scripts/generate.js new file mode 100644 index 0000000..21e220e --- /dev/null +++ b/scripts/generate.js @@ -0,0 +1,267 @@ +#!/usr/bin/env node + +import fs from "node:fs"; + +const ORG = "ubc-library-rc"; // replace if needed +const TOKEN = process.env.GITHUB_TOKEN; + +const TOPIC_LABELS = { + data: "Data analysis and visualization", + "digital-scholarship": "Digital scholarship", + geospatial: "Geographic information systems (GIS) and mapping", +// "research-data-management": "Research data management", --exclude RDM, which is added manually through 'non_repo_workshops.html' +}; + +// ----------------------------- +// Helpers +// ----------------------------- + +async function fetchAllRepos(headers) { + let allRepos = []; + let page = 1; + let fetched; + do { + const res = await fetch( + `https://api.github.com/orgs/${ORG}/repos?per_page=100&page=${page}`, + { headers } + ); + if (!res.ok) throw new Error(`HTTP ${res.status}: repos page ${page}`); + fetched = await res.json(); + allRepos = allRepos.concat(fetched); + page++; + } while (fetched.length === 100); + return allRepos; +} + +async function fetchRepoTopics(repo, headers) { + const res = await fetch(`https://api.github.com/repos/${ORG}/${repo}/topics`, { + headers: { ...headers, Accept: "application/vnd.github+json" }, + }); + if (!res.ok) return { names: [] }; + return res.json(); +} + +async function fetchRepoReadme(repo, headers) { + const res = await fetch(`https://api.github.com/repos/${ORG}/${repo}/readme`, { + headers, + }); + if (!res.ok) return ""; + const data = await res.json(); + if (!data.content) return ""; + return Buffer.from(data.content, "base64").toString("utf-8"); +} + +function extractTitleAndBlurb(readme) { + let title = null; + let blurb = null; + if (!readme) return { title, blurb }; + + const lines = readme.split(/\r?\n/); + for (const line of lines) { + if (!title && line.startsWith("#")) { + title = line.replace(/^#+\s*/, "").trim(); + } + if (!blurb && line.startsWith("Description:")) { + blurb = line.replace("Description:", "").trim(); + } + if (title && blurb) break; + } + return { title, blurb }; +} + +// ----------------------------- +// Main +// ----------------------------- + +async function main() { + const headers = { + "User-Agent": "gh-actions", + Accept: "application/vnd.github+json", + ...(TOKEN ? { Authorization: `token ${TOKEN}` } : {}), + }; + + const repos = await fetchAllRepos(headers); + + const enriched = []; + const featured = []; + + for (const repo of repos) { + if (!repo.description) continue; + + try { + const topics = await fetchRepoTopics(repo.name, headers); + const readme = await fetchRepoReadme(repo.name, headers); + const { title, blurb } = extractTitleAndBlurb(readme); + + const finalTitle = title || repo.description || repo.name; + + const enrichedRepo = { + name: repo.name, + title: finalTitle, + blurb, + url: `https://${ORG}.github.io/${repo.name}/`, + archived: repo.archived, + topics: topics.names || [], + }; + + if (topics.names && topics.names.includes("workshop")) { + enriched.push(enrichedRepo); + } + if (topics.names && topics.names.includes("featured")) { + featured.push(enrichedRepo); + } + } catch (e) { + console.warn(`⚠️ Skipping ${repo.name}: ${e.message}`); + } + } + + // ----------------------------- + // Group by predefined topics + // ----------------------------- + function groupRepos(repos) { + const grouped = {}; + for (const topic of Object.keys(TOPIC_LABELS)) { + grouped[topic] = repos + .filter((r) => r.topics.includes(topic)) + .sort((a, b) => a.title.localeCompare(b.title)); + } + return grouped; + } + + const groupedAll = groupRepos(enriched); + const groupedFeatured = groupRepos(featured); + + // ----------------------------- + // Non-repo workshops + // ----------------------------- + let nonRepoWorkshops = ""; + try { + nonRepoWorkshops = fs.readFileSync("non_repo_workshops.html", "utf8"); + } catch (err) { + console.warn("⚠️ Could not load non_repo_workshops.html:", err.message); + } + + // ----------------------------- + // Non-repo featured workshops + // ----------------------------- + let nonRepoFeaturedWorkshops = ""; + try { + nonRepoFeaturedWorkshops = fs.readFileSync("non_repo_featured_workshops.html", "utf8"); + } catch (err) { + console.warn("⚠️ Could not load non_repo_featured_workshops.html:", err.message); + } + + // ----------------------------- + // Generate all_test.html + // ----------------------------- + const sectionsAll = Object.entries(groupedAll) + .map(([topic, repos]) => { + if (!repos.length) return ""; + const items = repos + .map((repo) => { + const text = repo.title + (repo.archived ? " (archived)" : ""); + const cls = repo.archived ? 'class="archived"' : ""; + return `
  • ${text}
  • `; + }) + .join("\n"); + return `
    +

    ${TOPIC_LABELS[topic]}

    +
      ${items}
    +
    `; + }) + .join("\n\n"); + + const htmlAll = ` + + + + Codestin Search App + + + +
    +
    +
    + UBC Research Commons logo +
    +
    + UBC Library Research Commons +
    + +
    +
    +

    Past and present workshops offered by the Research Commons

    +

    For currently scheduled workshops visit https://researchcommons.library.ubc.ca/events/

    + ${sectionsAll} + ${nonRepoWorkshops} + +`; + + fs.writeFileSync("all_test.html", htmlAll); + + // ----------------------------- + // Generate featured_workshops.html + // ----------------------------- + const sectionsFeatured = Object.entries(groupedFeatured) + .map(([topic, repos]) => { + if (!repos.length) return ""; + const items = repos + .map((repo) => { + const text = repo.title + (repo.archived ? " (archived)" : ""); + const cls = repo.archived ? 'class="archived"' : ""; + const blurbText = repo.blurb + ? `

    ${repo.blurb}

    ` + : ""; + return `
    + ${text} + ${blurbText} +
    `; + }) + .join("\n"); + return `
    +

    ${TOPIC_LABELS[topic]}

    +
    + ${items} +
    +
    `; + }) + .join("\n\n"); + + const htmlFeatured = ` + + + + Codestin Search App + + + +
    +
    +
    + UBC Research Commons logo +
    +
    + UBC Library Research Commons +
    + +
    +
    +

    Featured Workshops

    + ${sectionsFeatured} + ${nonRepoFeaturedWorkshops} + +`; + + fs.writeFileSync("featured_workshops.html", htmlFeatured); + + console.log("✅ Pages generated: all_test.html, featured_workshops.html"); +} + +main().catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/style.css b/style.css new file mode 100644 index 0000000..1d6d9e1 --- /dev/null +++ b/style.css @@ -0,0 +1,105 @@ +body { + font-family: Arial, sans-serif; + padding: 2rem; + max-width: 850px; + margin: auto; + color: #2d3c48; + font-size: 14px; +} + +h1 { + font-size: 1.6rem; + font-weight: 300; + margin-bottom: 0.3rem; + margin-top: 3rem; +} + +h2 { + margin-top: 2rem; + font-size: 1.4rem; + font-weight: 300; + margin-bottom: 0.3rem +} + +ul { + list-style: none; + padding-left: 0; +} + +li { margin-bottom: 0.2rem;} + +a { + color: #3e8cb7; + text-decoration: none; +} + +a:hover { text-decoration: underline;} + +.archived { font-style: italic; } + +.large { font-size: 1.4em; font-weight: 300; } + +section {border-bottom: 1px solid rgba(0,0,0,0.1)} + +.header-flex { + display: flex; + align-items: center; + justify-content: space-between; + flex-wrap: wrap; + gap: 1rem; + margin-bottom: 1rem; +} + +#header-img { + flex: 0 0 auto; + width: 80px; + height: 80px; +} + +#header-img img { + max-width: 100%; + height: auto; +} + +#header-text { + font-size: 1.9rem; + font-weight: 300; + flex: 1 1 auto; + min-width: 200px; +} + +#header-link { + flex: 0 0 auto; + text-align: right; + min-width: 200px; +} + +.workshop-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); /* always 3 columns on wide screens */ + gap: 1.5rem; /* spacing between items */ + margin-top: 1rem; +} + +.workshop-card { + padding: 0; /* no card styling, just spacing */ +} + +.workshop-card a { + font-weight: bold; + display: block; + margin-bottom: 0.3rem; /* small spacing between title and blurb */ +} + +.workshop-card .blurb { + font-size: 0.9em; + color: #555; + margin: 0; +} + +/* Responsive: stack on smaller screens */ +@media (max-width: 800px) { + .workshop-grid { + grid-template-columns: 1fr; /* single column */ + } +}