Compare commits

...

48 Commits

Author SHA1 Message Date
2ac951771c Merge branch 'main' into dependabot/npm_and_yarn/unocss-preset-primitives-0.0.2-beta.2 2026-01-15 05:02:04 -06:00
doprz
518a3286fa feat(release): v2.3.0 2026-01-07 13:11:01 -06:00
Diego Perez
2d18553f98 feat: LHD birthday (#717)
* chore: add tsparticles/react

* fix: imports and lint issues

* fix: imports and format

* feat: refactor settings and add LHD birthday celebration

* chore: lint and format
2026-01-07 10:36:45 -06:00
doprz
68e3fe45fa chore(nix): update lock file 2026-01-06 12:47:27 -06:00
Diego Perez
38bb29b20b feat(nix): build UTRP (#714)
* feat(nix): build UTRP

* feat(nix): set fixed rev and sha256 + update lock file

* chore(nix): remove systems input

* chore: format

* chore(nix): add meta attribute

* feat(nix): add doprz as a maintainer
2026-01-06 12:39:34 -06:00
Diego Perez
8ccf7fb37e feat(nix): add prettier-version-match check (#713) 2025-12-26 13:24:22 -06:00
doprz
b406d4dd24 fix: .editorconfig syntax for nix files 2025-12-17 13:50:47 -06:00
doprz
d12c8bd7b7 chore: add treefmt/prettier note 2025-12-13 22:56:38 -06:00
doprz
ea5d1e2b16 chore: format 2025-12-13 22:49:09 -06:00
doprz
c2b43dc949 refactor(nix): use flake-parts (#642)
refactor(nix): split into flake parts module and add shell.nix

chore: add prettier to treefmt and pin version

chore(nix): add prettier exclude

chore(nix): bump pnpm to v10.18.2

feat(nix): add overlay for nodejs

feat(nix): add overlay for nodejs

chore: consolidate .editorconfig
2025-12-13 22:48:23 -06:00
8d2fdfa63c chore: feature request made better for the common student (#702)
I made these a less painful experience for the average non cs major who just wants to make an issue request

Co-authored-by: doprz <52579214+doprz@users.noreply.github.com>
2025-11-22 18:11:20 -06:00
c1ffd89dbe Refine bug report template for clarity and conciseness (#703)
Updated the bug report template to streamline the checklist and clarify sections.

Co-authored-by: doprz <52579214+doprz@users.noreply.github.com>
2025-11-22 18:10:40 -06:00
Aaron Park
dd8187d6da style: UTRP-14: Add a bigger "hitbox" to calendar sidebar buttons (#563)
* fix(sidebar): increase sidebar button hitbox

* chore(ui): change hitbox area for plus button

* chore(ui): update size of hitbox area

* fix: fix pnpm version conflict

* fix: pnpm version conflict

* chore(ui): update size of hitbox area for the social links

* feat: calendar footer story

---------

Co-authored-by: doprz <52579214+doprz@users.noreply.github.com>
Co-authored-by: Samuel Gunter <29130894+Samathingamajig@users.noreply.github.com>
Co-authored-by: Derek <derex1987@gmail.com>
2025-11-20 13:40:17 -06:00
5028d07f0b style: overflow no longer has the scroll because it is meant to be truncated (#704)
oh finally - DerexXD
2025-11-20 12:22:18 -06:00
4f5d8c6d20 fix: toSorted outdated chrome bug (#694)
* fix: polyfill

* fix: polyfill implemented

* chore: lint

* chore: replace polyfill with a single function replacement

* Delete src/polyfills.ts
2025-11-18 22:56:09 -06:00
Vincent Situ
6a67a32e4f feat: allow bypassing the 10-schedule limit (#675)
* feat: allow bypassing the 10-schedule limit

* feat: option to bypass 10 schedules- code done, not tested

* feat(ui): option to bypass 10 schedules

* feat(ui): button to lead to settings after reaching max limit

* Delete manifest.json

* Remove cross-env from build:watch script

* Remove cross-env and update caniuse-lite version

Removed cross-env dependency and updated caniuse-lite version.

* chore: lint

---------

Co-authored-by: Derek <derex1987@gmail.com>
2025-11-10 13:39:36 -06:00
Uthman
549c52a39f feat: add drag-and-drop import for schedules (#661)
* testing

* feat: add drag-and-drop support to FileUpload (#446)

* chore: remove testing comment

* chore: fix lint issues

* chore: format FileUpload.tsx with prettier

---------

Co-authored-by: Uthman Ogungbo <uthmanogungbo@Uthmans-MacBook-Pro.local>
Co-authored-by: Uthman Ogungbo <uthmanogungbo@wireless-10-148-166-229.public.utexas.edu>
Co-authored-by: Derek <derex1987@gmail.com>
2025-11-06 23:03:55 -06:00
doprz
36007b9d1a docs: add CODE_OF_CONDUCT.md (#651)
Added a Code of Conduct document to outline community guidelines and expectations.

Co-authored-by: Derek <derex1987@gmail.com>
2025-11-05 16:58:16 -06:00
cee5f0284f feat: condense resourceLinks course schedule (#676)
* chore: remove summer 2025 schedule list item

* feat: compress course schedules into one link

* Revise ResourceLinks with Spring '26 schedule

Updated course schedule links for Spring '26.
2025-11-05 16:38:00 -06:00
dependabot[bot]
96eb6cfefe chore(deps-dev): bump unocss-preset-primitives
Bumps [unocss-preset-primitives](https://github.com/zirbest/unocss-preset-primitives) from 0.0.2-beta.1 to 0.0.2-beta.2.
- [Release notes](https://github.com/zirbest/unocss-preset-primitives/releases)
- [Commits](https://github.com/zirbest/unocss-preset-primitives/compare/v0.0.2-beta.1...v0.0.2-beta.2)

---
updated-dependencies:
- dependency-name: unocss-preset-primitives
  dependency-version: 0.0.2-beta.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 16:02:18 +00:00
dependabot[bot]
e8a8b8e1ae chore(deps): bump the npm_and_yarn group across 1 directory with 4 updates (#639)
Bumps the npm_and_yarn group with 4 updates in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite), [@babel/helpers](https://github.com/babel/babel/tree/HEAD/packages/babel-helpers), [brace-expansion](https://github.com/juliangruber/brace-expansion) and [undici](https://github.com/nodejs/undici).


Updates `vite` from 5.4.14 to 5.4.20
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v5.4.20/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v5.4.20/packages/vite)

Updates `@babel/helpers` from 7.26.9 to 7.28.4
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.28.4/packages/babel-helpers)

Updates `brace-expansion` from 1.1.11 to 1.1.12
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/1.1.11...v1.1.12)

Updates `undici` from 6.21.1 to 6.22.0
- [Release notes](https://github.com/nodejs/undici/releases)
- [Commits](https://github.com/nodejs/undici/compare/v6.21.1...v6.22.0)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 5.4.20
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: "@babel/helpers"
  dependency-version: 7.28.4
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: brace-expansion
  dependency-version: 1.1.12
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: undici
  dependency-version: 6.22.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-13 11:36:53 -05:00
doprz
c21cbd77f0 feat(release): v2.2.2 2025-10-13 11:20:01 -05:00
99a035e29d chore: remove summer 2025 schedule list item (#637) 2025-10-13 02:25:27 -05:00
doprz
64baa6d290 refactor(nix): dev shells (#634) 2025-10-12 22:47:47 -05:00
Samuel Gunter
46fe591fa7 fix: whitespace wrapping in semester warning (#629) 2025-10-07 18:28:41 -05:00
doprz
8f7e1bc0af feat(env): add SENTRY env vars 2025-10-07 16:11:14 -05:00
doprz
9fc1098ef7 chore(env): add .env.example 2025-10-07 16:00:40 -05:00
Warith Rahman
ae094416fc chore(ui): added spring 2026 course schedule (#628) 2025-10-07 15:26:15 -05:00
ishita778
2e7dac1e3e feat: show warning for courses of different semesters (#570)
* chore: removed extra space at calendar footer

* chore: fixed eslint issues

* chore: changed return type to react node

* chore: displaycourses true fixes and checks fixed

* chore: prettier fix

* feat: not working same semester course issue

* feat: modifying components to use the new hook

* feat: small fixes

* fix: remove comments and spaces

* fix: dialog error solved

* fix: add to new schedule

* fix: prettier

* fix: delete unnecessary custom hook and p[rettier

* fix: checks all passing

* fix: added requested changes

* fix: added new conditions

* fix: description fixed

* style: fix Roboto Flex not being used as font in dialog

* fix: made requested changes

---------

Co-authored-by: doprz <52579214+doprz@users.noreply.github.com>
Co-authored-by: Razboy20 <razboy20@gmail.com>
Co-authored-by: Samuel Gunter <29130894+Samathingamajig@users.noreply.github.com>
2025-08-27 13:41:36 -05:00
doprz
7bea23a655 refactor: nix flake (#625)
* chore(nix): update flake

* chore(nix): remove just and update comment

* chore(nix): update node version + volta config

* refactor: nix flake
2025-08-25 11:33:44 -07:00
Samuel Gunter
3d28869e92 chore: spring 2025 grades (#624) 2025-08-18 00:29:59 -05:00
doprz
f0f1f0b365 chore: bump node and pnpm version (#620)
* chore(nix): update flake

* chore(nix): remove just and update comment

* chore(nix): update node version + volta config
2025-08-12 14:00:45 -05:00
be861b823c feat: search result shading (#617)
* feat: site support kws

* feat: function

* feat: stuff before bedtime

* feat: shading function

* feat: shading

* feat: shading the table children

* chore: fix lint issues

* feat: dependency array

* feat: remove

* feat: remove temp console log
2025-08-07 13:28:56 -05:00
Samuel Gunter
95de8df372 fix: fix or ignore various eslint warning (#609) 2025-07-16 07:54:40 -07:00
5994ded8be feat: export schedule button add to calendar (#594)
* feat: export schedule button add to calendar add to util too

* docs: hypen bruh

* chore: lowercase

* style: filecode icon

* chore: unused import

* refactor: use export json deleted old function

* chore: linting

* chore: remove useless import

---------

Co-authored-by: Samuel Gunter <29130894+Samathingamajig@users.noreply.github.com>
2025-06-17 11:57:48 -07:00
doprz
7b401add15 feat: add nix flake (#593)
Co-authored-by: Samuel Gunter <29130894+Samathingamajig@users.noreply.github.com>
2025-06-08 23:16:43 -05:00
Samuel Gunter
2d92dd47f0 feat: support summer grades, fix summer course parser (#596)
* feat: support summer grades, fix summer course parser

* chore: lint

* docs: mention summer terms in Course::number description

* feat: Course::getNumberWithoutTerm, strip summer term indicator when displaying grades

---------

Co-authored-by: doprz <52579214+doprz@users.noreply.github.com>
2025-06-08 21:10:05 -07:00
Aiyaz Mostofa
eb8141ee8c fix: limit height of schedule list dropdown in the extension popup (#543)
* fix: limit height of schedule list dropdown in the extension popup

* fix: limit the entire dropdown to 200px, not just the schedule list

* fix: use flexbox for dropdown and wedge scrollbar inside margin

* fix: use DisclosurePanel in schedule dropdown, do Uno class sorting

---------

Co-authored-by: Ethan Lanting <ethanlanting@gmail.com>
Co-authored-by: Samuel Gunter <29130894+Samathingamajig@users.noreply.github.com>
Co-authored-by: doprz <52579214+doprz@users.noreply.github.com>
2025-06-08 20:54:36 -07:00
sjalkote
2a50f5580d feat: automatically select new or duplicated schedules (#583) (#589)
Co-authored-by: doprz <52579214+doprz@users.noreply.github.com>
Co-authored-by: Samuel Gunter <29130894+Samathingamajig@users.noreply.github.com>
2025-06-08 20:39:46 -07:00
doprz
65bfb1d129 docs: add pnpm and update versions (#597) 2025-06-08 15:57:12 -05:00
doprz
234f3d627d feat(release): v2.2.1 2025-06-03 19:46:36 -05:00
Ethan Lanting
be1dccfcb9 feat: add dining app promo (#598)
* feat: add DiningAppPromo component and integrate it into Calendar

* feat: update WhatsNewPopup with new features and app download link

* fix: remove outdated links

* chore: run lint

* chore: run prettier

* feat: enhance DiningAppPromo with close button and integrate user preference for promo visibility

* chore: run lint

* chore: run check types

* fix: correct promo visibility logic in Calendar component

* feat: centralize app store URLs in appUrls.ts

* chore: run lint

* feat: integrate UT Dining promo image

* chore: run lint

* fix: update logo in WhatsNew popup to use LD icon

* fix: convert URLs to URL objects for consistency

* fix: update LD icon in WhatsNew popup to new version

* fix: update description for Coffee Shops feature to clarify operating times

* fix: rename promo state and storage key to showUTDiningPromo for clarity

---------

Co-authored-by: doprz <52579214+doprz@users.noreply.github.com>
2025-05-28 20:13:45 -05:00
Razboy20
454e5e807a fix: hide sentry instrumentation on debug builds (#604)
* fix: hide sentry instrumentation on debug builds

* fix: amend documentation to reference zip:to-public rather than zip
2025-05-27 23:35:11 -05:00
Razboy20
29d20d5c5a chore: setup dependabot configuration (#603)
* chore: setup dependabot configuration
2025-05-27 22:55:11 -05:00
doprz
e29546c727 chore: update issue templates 2025-05-27 21:55:36 -05:00
doprz
5a89be6238 chore: update issue templates 2025-05-27 21:53:42 -05:00
Samuel Gunter
cfb5faa09b fix: course columns on calendar (#587)
* fix: course columns on calendar

* test: new tests for course cell columns, extract calls to help function

* fix: gracefully handle async courses

* refactor: split course cell column logic into multiple functions, add comments, and derive fields

* chore: comments, for-index to for-of

* chore: fix typo

* fix: don't use sentry in storybook contexts

* fix: silence, brand

* refactor: don't rely on calculating columns, find as you go

---------

Co-authored-by: doprz <52579214+doprz@users.noreply.github.com>
2025-05-06 16:07:27 -05:00
37471efb74 feat: inside jokes005 (#590)
* feat: moved some of my lines together removed one of mine and added jack black

* feat: just ctrl x ctrl v a few lines

* Update insideJokes.tsx
2025-04-13 21:33:52 -05:00
87 changed files with 3799 additions and 1799 deletions

View File

@@ -7,3 +7,6 @@ insert_final_newline = true
trim_trailing_whitespace = true trim_trailing_whitespace = true
indent_size = 4 indent_size = 4
indent_style = space indent_style = space
[*.{nix,yaml,yml}]
indent_size = 2

3
.env.example Normal file
View File

@@ -0,0 +1,3 @@
SENTRY_ORG=longhorn-developers
SENTRY_PROJECT=ut-registration-plus
SENTRY_AUTH_TOKEN=

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

View File

@@ -2,7 +2,7 @@
name: Bug report name: Bug report
about: Create a report to help us improve about: Create a report to help us improve
title: '[BUG] ' title: '[BUG] '
labels: 'bug' labels: ''
assignees: '' assignees: ''
--- ---
@@ -10,11 +10,11 @@ assignees: ''
<!-- Please check all applicable boxes before submitting your issue --> <!-- Please check all applicable boxes before submitting your issue -->
- [ ] I have searched existing issues to make sure this is not a duplicate - [ ] I have searched existing issues to make sure this is not a duplicate
- [ ] I have cleared my browser cache and confirmed the issue persists - [ ] I have cleared my browser cache and confirmed the issue persists
- [ ] I have checked this issue affects the latest version of the extension - [ ] I have checked this issue affects the latest version of the extension
- [ ] I have disabled other extensions to ensure this isn't a conflict issue - [ ] I have disabled other extensions to ensure this isn't a conflict issue
- [ ] I have included all the information requested below - [ ] I have included all the information requested below
**Bug Description** **Bug Description**
@@ -29,11 +29,11 @@ assignees: ''
**Expected Behavior** **Expected Behavior**
<!-- A clear and concise description of what you expected to happen --> <!-- What you expected to happen -->
**Current Behavior** **Current Behavior**
<!-- A clear and concise description of what actually happened --> <!-- What actually happened -->
**Screenshots** **Screenshots**
@@ -41,9 +41,9 @@ assignees: ''
**Debug Information** **Debug Information**
- UTRP Extension Version: [e.g. 1.2.0] - UTRP Extension Version: [e.g. 1.2.0]
- Browser Info: [e.g. Chrome 120.0.0] - Browser Info: [e.g. Chrome 120.0.0]
- OS: [e.g. Windows 11, macOS Sonoma] - OS: [e.g. Windows 11, macOS Sonoma]
**Console Logs** **Console Logs**

View File

@@ -2,7 +2,7 @@
name: Feature Request name: Feature Request
about: Suggest an idea for this project about: Suggest an idea for this project
title: '[FEATURE] ' title: '[FEATURE] '
labels: 'feature' labels: feature
assignees: '' assignees: ''
--- ---
@@ -10,24 +10,20 @@ assignees: ''
<!-- Please check all applicable boxes before submitting your feature request --> <!-- Please check all applicable boxes before submitting your feature request -->
- [ ] I have searched existing issues to ensure this feature hasn't been requested - [ ] I have searched existing issues to ensure this feature hasn't been requested
- [ ] I have searched closed issues to check if this was previously rejected/implemented - [ ] I have searched closed issues to check if this was previously rejected/implemented
- [ ] I have checked the project roadmap (if available) for planned similar features - [ ] I have checked the project roadmap (if available) for planned similar features
- [ ] I have reviewed the documentation to confirm this feature doesn't exist - [ ] I have reviewed the documentation to confirm this feature doesn't exist
- [ ] I have completed all sections below with detailed information - [ ] I have completed all sections below with detailed information
**Feature Description** **Your Idea**
<!-- A clear and concise description of the feature you'd like to see --> <!-- A clear and concise description of the feature you'd like to see, and how it would work -->
**Proposed Solution**
<!-- A clear and concise description of what you want to happen -->
**UI/UX Considerations** **UI/UX Considerations**
<!-- If this feature involves UI changes, please describe the visual aspects --> <!-- If this feature involves UI changes (aka how it looks), please describe the visual aspects -->
**Technical Implementation Details** **Other**
<!-- If you have specific technical suggestions, list them here --> <!-- Any other comments you have can go here! -->

View File

@@ -0,0 +1,11 @@
---
name: Updating Build Dependencies
about: Updating Build Dependencies
title: ''
labels: build, dependencies
assignees: doprz, Razboy20
---
- [ ] Updated Nix Flake
- [ ] Update Dockerfile
- [ ] Update Docs

20
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
version: 2
updates:
- package-ecosystem: 'npm'
directory: '/'
schedule:
interval: 'weekly'
day: 'monday'
time: '09:00'
timezone: 'America/Chicago'
groups:
minor-and-patch-updates:
update-types:
- 'minor'
- 'patch'
major-updates:
update-types:
- 'major'
ignore:
- dependency-name: '@crxjs/vite-plugin'
- dependency-name: '@unocss/vite'

View File

@@ -1,43 +1,33 @@
name: Best Practices name: Best Practices
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
lint: lint:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps:
steps: - name: Checkout code
- name: Checkout code uses: actions/checkout@v4
uses: actions/checkout@v4 with:
with: fetch-depth: 0
fetch-depth: 0 - name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Setup pnpm with:
uses: pnpm/action-setup@v4 version: 10
with: - name: Install dependencies
version: 10 run: pnpm install
- name: Run ESLint
- name: Install dependencies run: pnpm run lint
run: pnpm install format:
runs-on: ubuntu-latest
- name: Run ESLint steps:
run: pnpm run lint - name: Checkout code
format: uses: actions/checkout@v4
runs-on: ubuntu-latest with:
fetch-depth: 0
steps: - name: Setup pnpm
- name: Checkout code uses: pnpm/action-setup@v4
uses: actions/checkout@v4 with:
with: version: 10
fetch-depth: 0 - name: Install dependencies
run: pnpm install
- name: Setup pnpm - name: Run Prettier
uses: pnpm/action-setup@v4 run: pnpm run prettier
with:
version: 10
- name: Install dependencies
run: pnpm install
- name: Run Prettier
run: pnpm run prettier

View File

@@ -1,24 +1,18 @@
name: Type Check name: Type Check
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
type-check: type-check:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps:
steps: - name: Checkout code
- name: Checkout code uses: actions/checkout@v4
uses: actions/checkout@v4 with:
with: fetch-depth: 0
fetch-depth: 0 - name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Setup pnpm with:
uses: pnpm/action-setup@v4 version: 10
with: - name: Install dependencies
version: 10 run: pnpm install
- name: Run tests
- name: Install dependencies run: pnpm run check-types
run: pnpm install
- name: Run tests
run: pnpm run check-types

View File

@@ -1,26 +1,22 @@
name: 'Chromatic' name: 'Chromatic'
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
chromatic: chromatic:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Setup pnpm - name: Setup pnpm
uses: pnpm/action-setup@v4 uses: pnpm/action-setup@v4
with: with:
version: 10 version: 10
- name: Install dependencies
- name: Install dependencies run: pnpm install
run: pnpm install - name: Publish to Chromatic
uses: chromaui/action@latest
- name: Publish to Chromatic with:
uses: chromaui/action@latest projectToken: chpt_e8bd07b0b27d8eb
with: exitZeroOnChanges: true
projectToken: chpt_e8bd07b0b27d8eb autoAcceptChanges: 'main'
exitZeroOnChanges: true
autoAcceptChanges: 'main'

View File

@@ -1,25 +1,24 @@
name: Create Release name: Create Release
on: on:
push: push:
branches: branches:
- production - production
- preview - preview
jobs: jobs:
build: build:
name: build extension & create release name: build extension & create release
runs-on: ubuntu-latest runs-on: ubuntu-latest
concurrency: concurrency:
group: ${{ github.ref }} group: ${{ github.ref }}
cancel-in-progress: true cancel-in-progress: true
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
- name: Get file permission - name: Get file permission
run: chmod -R 777 . run: chmod -R 777 .
- name: Install dependencies
- name: Install dependencies run: npm ci
run: npm ci - name: Release with semantic-release
- name: Release with semantic-release id: semantic-release
id: semantic-release run: npx --no-install semantic-release
run: npx --no-install semantic-release env:
env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -1,24 +1,18 @@
name: Tests name: Tests
on: [push, pull_request] on: [push, pull_request]
jobs: jobs:
test: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps:
steps: - name: Checkout code
- name: Checkout code uses: actions/checkout@v4
uses: actions/checkout@v4 with:
with: fetch-depth: 0
fetch-depth: 0 - name: Setup pnpm
uses: pnpm/action-setup@v4
- name: Setup pnpm with:
uses: pnpm/action-setup@v4 version: 10
with: - name: Install dependencies
version: 10 run: pnpm install
- name: Run tests
- name: Install dependencies run: pnpm test
run: pnpm install
- name: Run tests
run: pnpm test

View File

@@ -1,43 +1,40 @@
name: Validate PR Title name: Validate PR Title
# thank you ben limmer for this workflow: # thank you ben limmer for this workflow:
# https://github.com/blimmer/semantic-release-demo-2/blob/main/.github/workflows/lint-pr.yml # https://github.com/blimmer/semantic-release-demo-2/blob/main/.github/workflows/lint-pr.yml
on: on:
pull_request_target: pull_request_target:
types: types:
- opened - opened
- reopened - reopened
- edited - edited
- synchronize - synchronize
jobs: jobs:
main: main:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: amannn/action-semantic-pull-request@v3.2.6 - uses: amannn/action-semantic-pull-request@v3.2.6
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Post Conventional Commit Comment (on failure) - name: Post Conventional Commit Comment (on failure)
uses: jungwinter/comment@v1 uses: jungwinter/comment@v1
id: conventional-commit-help id: conventional-commit-help
with: with:
type: create type: create
issue_number: ${{ github.event.pull_request.number }} issue_number: ${{ github.event.pull_request.number }}
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
body: | body: |
Your pull request title did not conform to [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) standards. Our upcoming automated release pipeline will automatically determine Your pull request title did not conform to [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) standards. Our upcoming automated release pipeline will automatically determine
the proper release version based on your pull request title. the proper release version based on your pull request title.
**Cheat Sheet** **Cheat Sheet**
- feat: A new feature - feat: A new feature
- fix: A bug fix - fix: A bug fix
- docs: Documentation only changes - docs: Documentation only changes
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) - style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- refactor: A code change that neither fixes a bug nor adds a feature - refactor: A code change that neither fixes a bug nor adds a feature
- perf: A code change that improves performance - perf: A code change that improves performance
- test: Adding missing tests or correcting existing tests - test: Adding missing tests or correcting existing tests
- build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) - build: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
- ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs) - ci: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
- chore: Other changes that don't modify src or test files - chore: Other changes that don't modify src or test files
- revert: Reverts a previous commit - revert: Reverts a previous commit
if: ${{ failure() }} if: ${{ failure() }}

7
.gitignore vendored
View File

@@ -211,3 +211,10 @@ sketch
package-lock.json package-lock.json
storybook-static/ storybook-static/
package/ package/
# Nix
result
result-*
# direnv
.direnv

8
.vscode/launch.json vendored
View File

@@ -6,13 +6,9 @@
"request": "launch", "request": "launch",
"name": "Run current script", "name": "Run current script",
"runtimeExecutable": "npx", "runtimeExecutable": "npx",
"runtimeArgs": [ "runtimeArgs": ["tsx"],
"tsx"
],
"program": "${file}", "program": "${file}",
"skipFiles": [ "skipFiles": ["<node_internals>/**"]
"<node_internals>/**"
],
} }
] ]
} }

View File

@@ -26,7 +26,7 @@
"navigation": "Routes", "navigation": "Routes",
"logging": "log", "logging": "log",
"popup": "Layout", "popup": "Layout",
"storage": "Database", "storage": "Database"
}, },
"material-icon-theme.files.associations": { "material-icon-theme.files.associations": {
"tsconfig.extension.json": "tsconfig", "tsconfig.extension.json": "tsconfig",
@@ -36,5 +36,5 @@
"[html]": { "[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "esbenp.prettier-vscode"
}, },
"typescript.tsdk": "node_modules/typescript/lib", "typescript.tsdk": "node_modules/typescript/lib"
} }

View File

@@ -1,365 +1,406 @@
## [2.3.0](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.2.2...v2.3.0) (2026-01-07)
### Features
* add drag-and-drop import for schedules ([#661](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/661)) ([549c52a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/549c52a39fee718f2bb07cfce33a294835a2246b)), closes [#446](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/446)
* allow bypassing the 10-schedule limit ([#675](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/675)) ([6a67a32](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6a67a32e4f50a5bdd20aa43789f199b822483e2d))
* condense resourceLinks course schedule ([#676](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/676)) ([cee5f02](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cee5f0284f09f39ca5ae64559d0b697646c77e74))
* LHD birthday ([#717](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/717)) ([2d18553](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2d18553f98c5146fa18699ae20462e7dcbc9d35c))
* **nix:** add prettier-version-match check ([#713](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/713)) ([8ccf7fb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8ccf7fb37e769ba445f39c140ca9c1c4245cc1c1))
* **nix:** build UTRP ([#714](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/714)) ([38bb29b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/38bb29b20b97ed3cf8fd6511df16553fed1d58bb))
### Bug Fixes
* .editorconfig syntax for nix files ([b406d4d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b406d4dd244a25688c2b9621cf5d441228bd8913))
* toSorted outdated chrome bug ([#694](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/694)) ([4f5d8c6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4f5d8c6d20e3cfeb7b62520ba1819e297d2cc60f))
## [2.2.2](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.2.1...v2.2.2) (2025-10-13)
### Features
* add nix flake ([#593](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/593)) ([7b401ad](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7b401add1565ff401bad99745ff9e53b9a7f899f))
* automatically select new or duplicated schedules ([#583](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/583)) ([#589](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/589)) ([2a50f55](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2a50f5580d3dbeb0d66546c23cf29bbb37d80da2))
* **env:** add SENTRY env vars ([8f7e1bc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8f7e1bc0af6336549068e02b80df21d4e8f4ef9c))
* export schedule button add to calendar ([#594](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/594)) ([5994ded](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5994ded8be876cb55174d27d3fdb0832b21a0ff9))
* **release:** v2.2.2 ([c21cbd7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c21cbd77f0764c03a711589ff4f957cb8c936eec))
* search result shading ([#617](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/617)) ([be861b8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/be861b823cb2cb7f6f4a1f266351eec3fc1c2f99))
* show warning for courses of different semesters ([#570](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/570)) ([2e7dac1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2e7dac1e3eba757231ac07ac966231c08c703a16))
* support summer grades, fix summer course parser ([#596](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/596)) ([2d92dd4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2d92dd47f00a44b7d48e92a8ffba94480e4e73f9))
### Bug Fixes
* fix or ignore various eslint warning ([#609](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/609)) ([95de8df](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/95de8df37243b6d59625df515a60442f11b7a9d3))
* limit height of schedule list dropdown in the extension popup ([#543](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/543)) ([eb8141e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/eb8141ee8c3d32bce901457178d50781b78f86dd))
* whitespace wrapping in semester warning ([#629](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/629)) ([46fe591](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/46fe591fa72ef017eea7cfb8aa37d12d8f223926))
## [2.2.1](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.2.0...v2.2.1) (2025-06-04)
### Features
* add dining app promo ([#598](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/598)) ([be1dccf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/be1dccfcb9d052c6b291b50cc53418d6bb645beb))
* inside jokes005 ([#590](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/590)) ([37471ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/37471efb740c7a5828cf3b54bac70954694359d7))
* **release:** v2.2.1 ([234f3d6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/234f3d627d603adf8555b4d0e93106d198918169))
### Bug Fixes
* course columns on calendar ([#587](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/587)) ([cfb5faa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cfb5faa09bb0788e270d100f1f36536a53bcff75))
* hide sentry instrumentation on debug builds ([#604](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/604)) ([454e5e8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/454e5e807af29ae0384cc3a3b8b691df5edc69d1))
## [2.2.0](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.1.1...v2.2.0) (2025-04-06) ## [2.2.0](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.1.1...v2.2.0) (2025-04-06)
### Features ### Features
- auto create empty schedule when deleted all schedules ([#552](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/552)) ([7c2beef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7c2beef1930fbc887e8ec1aea789016b3150cd21)) * auto create empty schedule when deleted all schedules ([#552](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/552)) ([7c2beef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7c2beef1930fbc887e8ec1aea789016b3150cd21))
- ensure unique splash text on schedule change ([#554](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/554)) ([9448072](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/94480721124e052426c1f3236e8605c7088df79c)) * ensure unique splash text on schedule change ([#554](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/554)) ([9448072](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/94480721124e052426c1f3236e8605c7088df79c))
- implement a What's New prompt ([#539](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/539)) ([f036d40](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f036d409e60a39fd1d3cb2f0db53a6056615f336)) * implement a What's New prompt ([#539](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/539)) ([f036d40](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f036d409e60a39fd1d3cb2f0db53a6056615f336))
- persist sidebar toggle state ([#569](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/569)) ([6957431](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/695743104c57951ba1957258c60c843f8fae793f)) * persist sidebar toggle state ([#569](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/569)) ([6957431](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/695743104c57951ba1957258c60c843f8fae793f))
- recruitment banner for designer ([#578](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/578)) ([70d4fec](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/70d4fecad61ec3cd3ba839de302fd851e075d073)) * recruitment banner for designer ([#578](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/578)) ([70d4fec](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/70d4fecad61ec3cd3ba839de302fd851e075d073))
- rework start time to checkboxes ([#553](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/553)) ([ca734dc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ca734dcd39a433cfd2e930ea04adeba959b32c36)) * **release:** v2.2.0 ([7a4f40a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7a4f40a765d704bf32a3b515d695916ed84f9397))
- sticky calendar header and days ([#568](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/568)) ([fa9f78b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fa9f78b46e3a2270a44d4cc0691195a7c695cb93)) * rework start time to checkboxes ([#553](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/553)) ([ca734dc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ca734dcd39a433cfd2e930ea04adeba959b32c36))
* sticky calendar header and days ([#568](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/568)) ([fa9f78b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fa9f78b46e3a2270a44d4cc0691195a7c695cb93))
### Bug Fixes ### Bug Fixes
- ics calendar export dates ([#535](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/535)) ([4a5f67f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4a5f67f0fda9f0ef57f821e4b7a55d63f099f579)) * ics calendar export dates ([#535](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/535)) ([4a5f67f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4a5f67f0fda9f0ef57f821e4b7a55d63f099f579))
- include logo in screenshot, fix screenshots on small/zoomed windows ([#579](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/579)) ([76b6aa7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/76b6aa7c150299dfcfa4b3dc00ce2de32f90f75c)) * include logo in screenshot, fix screenshots on small/zoomed windows ([#579](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/579)) ([76b6aa7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/76b6aa7c150299dfcfa4b3dc00ce2de32f90f75c))
- merge course labels across pages ([#541](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/541)) ([6c3139b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6c3139bf0f324c9a7be826b6c24e8bf142fc53b1)) * merge course labels across pages ([#541](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/541)) ([6c3139b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6c3139bf0f324c9a7be826b6c24e8bf142fc53b1))
- **schedule:** truncate long schedule names in popup ([#564](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/564)) ([3bed9cc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3bed9cc27febfe795af0766a913c4845e74cc2da)) * **schedule:** truncate long schedule names in popup ([#564](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/564)) ([3bed9cc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3bed9cc27febfe795af0766a913c4845e74cc2da))
## [2.1.1](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.1.0...v2.1.1) (2025-03-03) ## [2.1.1](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.1.0...v2.1.1) (2025-03-03)
### Features ### Features
- add isDeveloper ([c6452c4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c6452c4f2b174487e6f51ad546ca1c3f8b4dbc1f)) * add isDeveloper ([c6452c4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c6452c4f2b174487e6f51ad546ca1c3f8b4dbc1f))
- map page ([#390](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/390)) ([2184774](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/218477404fdeacda7b39cd233e4e1e65995935d4)) * map page ([#390](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/390)) ([2184774](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/218477404fdeacda7b39cd233e4e1e65995935d4))
### Bug Fixes ### Bug Fixes
- import schedule file upload button ([#515](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/515)) ([766c0bc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/766c0bc1b4a75f8146a922cb2eca8871032c1dc9)) * import schedule file upload button ([#515](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/515)) ([766c0bc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/766c0bc1b4a75f8146a922cb2eca8871032c1dc9))
## [2.1.0](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.0.2...v2.1.0) (2025-02-20) ## [2.1.0](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.0.2...v2.1.0) (2025-02-20)
### Features ### Features
- add 'new search' link to the course catalog page ([#456](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/456)) ([ca5e4c1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ca5e4c13d31aeb603660972536712ea161c6f870)) * add 'new search' link to the course catalog page ([#456](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/456)) ([ca5e4c1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ca5e4c13d31aeb603660972536712ea161c6f870))
- add 404 page ([#426](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/426)) ([46c76b1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/46c76b1703ea2344c3330c4cfa82560663be1c4c)) * add 404 page ([#426](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/426)) ([46c76b1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/46c76b1703ea2344c3330c4cfa82560663be1c4c))
- add CacheStore for GitHub stats and use names instead of usernames ([#405](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/405)) ([b732a80](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b732a80eaa6f6cbf5b627ffc31ab321de3a8e8f4)) * add CacheStore for GitHub stats and use names instead of usernames ([#405](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/405)) ([b732a80](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b732a80eaa6f6cbf5b627ffc31ab321de3a8e8f4))
- add eslint-plugin-tsdoc ([#430](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/430)) ([e987fbb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e987fbbe8e733de6767d62811c2d4d6eaccf2d24)) * add eslint-plugin-tsdoc ([#430](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/430)) ([e987fbb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e987fbbe8e733de6767d62811c2d4d6eaccf2d24))
- add explanation to grade distribution ([#325](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/325)) ([9ad3239](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9ad32390d13e1d413ca01b1bc45d02c695bc23dd)) * add explanation to grade distribution ([#325](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/325)) ([9ad3239](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9ad32390d13e1d413ca01b1bc45d02c695bc23dd))
- add open calendar button ([#457](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/457)) ([93733e3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/93733e37214f00543479e77209ca03864776a1a6)) * add open calendar button ([#457](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/457)) ([93733e3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/93733e37214f00543479e77209ca03864776a1a6))
- add spacing system ([#474](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/474)) ([e61ab56](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e61ab565c35a197609d205adcaac9c7ffe0fc6da)) * add spacing system ([#474](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/474)) ([e61ab56](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e61ab565c35a197609d205adcaac9c7ffe0fc6da))
- **build:** add Docker support ([#322](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/322)) ([a5e921f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a5e921fd75109a50f17d05c9682e73ba246f3dd1)) * **build:** add Docker support ([#322](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/322)) ([a5e921f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a5e921fd75109a50f17d05c9682e73ba246f3dd1))
- **build:** add vite-build-logger ([#507](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/507)) ([1aa4e8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1aa4e8c5fb2d1aea308e4cccea3e2818a9c946ec)) * **build:** add vite-build-logger ([#507](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/507)) ([1aa4e8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1aa4e8c5fb2d1aea308e4cccea3e2818a9c946ec))
- **build:** refactor gulpfile to use gulp-execa ([#323](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/323)) ([db04bbb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/db04bbb52e4ab19730dd66f417e68ab013ce2f79)) * **build:** refactor gulpfile to use gulp-execa ([#323](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/323)) ([db04bbb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/db04bbb52e4ab19730dd66f417e68ab013ce2f79))
- export/import functionality (backup/restore/share with friends) + a new input component ([#433](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/433)) ([7dbffc6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7dbffc6eef346747042f1596da627ad0a2fcae1a)) * export/import functionality (backup/restore/share with friends) + a new input component ([#433](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/433)) ([7dbffc6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7dbffc6eef346747042f1596da627ad0a2fcae1a))
- injected button - add all courses from MyUT AND passing URL to handler ([#291](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/291)) ([c41467c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c41467c6176d31f70cd3ecdcf56eeb73696c6c23)) * injected button - add all courses from MyUT AND passing URL to handler ([#291](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/291)) ([c41467c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c41467c6176d31f70cd3ecdcf56eeb73696c6c23))
- modify Course Block text style and time and location text ([#409](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/409)) ([0d51cae](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0d51cae4c8b27201b09c0898f4d7a6e7abb3c100)) * modify Course Block text style and time and location text ([#409](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/409)) ([0d51cae](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0d51cae4c8b27201b09c0898f4d7a6e7abb3c100))
- **settings:** add option to always open calendar in new tab ([#488](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/488)) ([009de62](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/009de628285ce9c6571e492f8e3f52cdeeed4459)) * **settings:** add option to always open calendar in new tab ([#488](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/488)) ([009de62](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/009de628285ce9c6571e492f8e3f52cdeeed4459))
- **settings:** allow disabling of auto-loading courses ([#489](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/489)) ([b74c698](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b74c698866c1074ce2236ede549c94555667e6a5)) * **settings:** allow disabling of auto-loading courses ([#489](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/489)) ([b74c698](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b74c698866c1074ce2236ede549c94555667e6a5))
- **ui:** add schedule list icons ([#500](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/500)) ([f0b257a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f0b257aa124a8fff0bb31e3396715aecb09948d5)) * **ui:** add schedule list icons ([#500](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/500)) ([f0b257a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f0b257aa124a8fff0bb31e3396715aecb09948d5))
- **ui:** added shadows to popup buttons and course blocks ([#378](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/378)) ([a20332e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a20332e53da9bda873fabb8395afe6ff6303799c)) * **ui:** added shadows to popup buttons and course blocks ([#378](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/378)) ([a20332e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a20332e53da9bda873fabb8395afe6ff6303799c))
- **ui:** calendar header redesign ([#479](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/479)) ([9c766c2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9c766c26959673389e372c3a440c1a73d5887b1d)) * **ui:** calendar header redesign ([#479](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/479)) ([9c766c2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9c766c26959673389e372c3a440c1a73d5887b1d))
- **ui:** calendar sidebar redesign ([#464](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/464)) ([843cb5b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/843cb5b4430885527592feee33656dfae50c95c2)) * **ui:** calendar sidebar redesign ([#464](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/464)) ([843cb5b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/843cb5b4430885527592feee33656dfae50c95c2))
- **ui:** change icons to phosphor-icons [#467](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/467) ([#469](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/469)) ([37bd7e7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/37bd7e79d9202d55c7d0f566518526b0aed53c68)) * **ui:** change icons to phosphor-icons [#467](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/467) ([#469](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/469)) ([37bd7e7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/37bd7e79d9202d55c7d0f566518526b0aed53c68))
- **ui:** change red text when instructor not found ([#483](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/483)) ([52347fd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/52347fd56dff95190915d9f375dbebe1383e76c8)) * **ui:** change red text when instructor not found ([#483](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/483)) ([52347fd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/52347fd56dff95190915d9f375dbebe1383e76c8))
- **ui:** color picker final touches ([#491](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/491)) ([c2328e4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c2328e461ea0a846f399a22bc525540da2796dcd)) * **ui:** color picker final touches ([#491](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/491)) ([c2328e4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c2328e461ea0a846f399a22bc525540da2796dcd))
- **ui:** course color picker ([#382](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/382)) ([1f635d2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1f635d2515fc403ad7f08fc3a244a17d262e3f7b)) * **ui:** course color picker ([#382](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/382)) ([1f635d2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1f635d2515fc403ad7f08fc3a244a17d262e3f7b))
- **ui:** course unique number copy button ([#490](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/490)) ([501f506](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/501f50667725aa1515391869b133908b8383d868)) * **ui:** course unique number copy button ([#490](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/490)) ([501f506](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/501f50667725aa1515391869b133908b8383d868))
- **ui:** Modify Calendar Footer design and Unscheduled courses ([#503](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/503)) ([b171f01](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b171f01d01f47c75e7df5e5c8e4e7b15b7397c52)) * **ui:** Modify Calendar Footer design and Unscheduled courses ([#503](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/503)) ([b171f01](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b171f01d01f47c75e7df5e5c8e4e7b15b7397c52))
- **ui:** redesign grade distribution tooltip ([#485](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/485)) ([a61bddf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a61bddf0e8a76c89d4963d9e580fb063309bee92)) * **ui:** redesign grade distribution tooltip ([#485](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/485)) ([a61bddf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a61bddf0e8a76c89d4963d9e580fb063309bee92))
- **ui:** update button variants following figma ([#482](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/482)) ([0aa469a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0aa469af81e7912a6b26ee1b80c5920f677b5fbd)) * **ui:** update button variants following figma ([#482](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/482)) ([0aa469a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0aa469af81e7912a6b26ee1b80c5920f677b5fbd))
- **ui:** update popup and course blocks ([#506](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/506)) ([ee4c6ce](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ee4c6ce6999ad35821b9be5d657790f2dee017b3)) * **ui:** update popup and course blocks ([#506](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/506)) ([ee4c6ce](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ee4c6ce6999ad35821b9be5d657790f2dee017b3))
- **ui:** update theme colors [#466](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/466) ([#473](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/473)) ([0d73b13](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0d73b13b288bf8b18444f26455da24c2f4acedf6)) * **ui:** update theme colors [#466](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/466) ([#473](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/473)) ([0d73b13](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0d73b13b288bf8b18444f26455da24c2f4acedf6))
- update SWE list ([aa29bcf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aa29bcf9fe4bad7812336d55d7575a6032aea91c)) * update SWE list ([aa29bcf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aa29bcf9fe4bad7812336d55d7575a6032aea91c))
- update text styles ([#468](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/468)) ([918f4e4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/918f4e419cf5fa71bda1112597e9a373daca69ea)), closes [#465](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/465) * update text styles ([#468](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/468)) ([918f4e4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/918f4e419cf5fa71bda1112597e9a373daca69ea)), closes [#465](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/465)
- validate login passed to background and implemented into add all injected button ([#443](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/443)) ([cd05e5e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cd05e5e7fcaa02dab30f230c178f189d8052a7c9)) * validate login passed to background and implemented into add all injected button ([#443](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/443)) ([cd05e5e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cd05e5e7fcaa02dab30f230c178f189d8052a7c9))
### Bug Fixes ### Bug Fixes
- 4th attempt for: now able to delete schedule even if active ([#435](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/435)) ([2425679](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/24256798ba7b877dd170d77ce4970b13b8a69a68)) * 4th attempt for: now able to delete schedule even if active ([#435](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/435)) ([2425679](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/24256798ba7b877dd170d77ce4970b13b8a69a68))
- instructor formatting errors ([#425](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/425)) ([8b92208](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8b922082a79ebdbf50a09f37ecb9dfea1be6e1f3)) * instructor formatting errors ([#425](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/425)) ([8b92208](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8b922082a79ebdbf50a09f37ecb9dfea1be6e1f3))
- place hours and courses under schedule name ([#388](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/388)) ([7dd9369](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7dd93690d6dbd206cb50442f42ec85d6bbfc1da8)) * place hours and courses under schedule name ([#388](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/388)) ([7dd9369](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7dd93690d6dbd206cb50442f42ec85d6bbfc1da8))
- transition added ([#381](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/381)) ([598bafe](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/598bafe67f47ad57b3801a425e61f86093ba2be8)) * transition added ([#381](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/381)) ([598bafe](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/598bafe67f47ad57b3801a425e61f86093ba2be8))
- **ui:** fix longstanding drag-and-drop duplication issue ([#502](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/502)) ([4752f58](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4752f5860a96e08a1177c0ddf57a0fa269d89072)) * **ui:** fix longstanding drag-and-drop duplication issue ([#502](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/502)) ([4752f58](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4752f5860a96e08a1177c0ddf57a0fa269d89072))
- **ui:** reduce left side grade distribution margin/padding ([#427](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/427)) ([91fa78e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/91fa78e2d0532a73e24ecc013d2ba6c0f62c1fcd)) * **ui:** reduce left side grade distribution margin/padding ([#427](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/427)) ([91fa78e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/91fa78e2d0532a73e24ecc013d2ba6c0f62c1fcd))
- **ui:** stop import button dropdown from squishing ([#504](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/504)) ([846070e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/846070ebb5e13e0fc0df94666dbce75194100049)) * **ui:** stop import button dropdown from squishing ([#504](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/504)) ([846070e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/846070ebb5e13e0fc0df94666dbce75194100049))
- updated text when time/location not provided ([#289](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/289)) ([ebcc0aa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ebcc0aa76a89f0d1a9e90cfc50d70f017c9bed42)) * updated text when time/location not provided ([#289](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/289)) ([ebcc0aa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ebcc0aa76a89f0d1a9e90cfc50d70f017c9bed42))
## [2.0.2](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.0.1...v2.0.2) (2024-11-05) ## [2.0.2](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.0.1...v2.0.2) (2024-11-05)
### Features ### Features
- add core curriculum chips to injected popup ([#372](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/372)) ([6f1afc5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6f1afc5b25441c6a1fbfdf57b3c8b5b74e36f5a0)) * add core curriculum chips to injected popup ([#372](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/372)) ([6f1afc5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6f1afc5b25441c6a1fbfdf57b3c8b5b74e36f5a0))
- Add linkedin social to calendar ([#368](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/368)) ([b6eccac](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b6eccaca6a2cdba9b57d2f49f064ae8504bbd5cb)) * Add linkedin social to calendar ([#368](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/368)) ([b6eccac](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b6eccaca6a2cdba9b57d2f49f064ae8504bbd5cb))
- add more relevant links to the From the Team section ([#380](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/380)) ([643ea13](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/643ea1320798aabb7783d267f5e6fd7c00fc2e3f)) * add more relevant links to the From the Team section ([#380](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/380)) ([643ea13](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/643ea1320798aabb7783d267f5e6fd7c00fc2e3f))
- bold course number in grade distribution chart, change text to ut-black ([#406](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/406)) ([638ee88](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/638ee88c96510a779c157b524903caaeffc9ef19)) * bold course number in grade distribution chart, change text to ut-black ([#406](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/406)) ([638ee88](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/638ee88c96510a779c157b524903caaeffc9ef19))
- disable/some actions when no instructor ([#319](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/319)) ([839f9c6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/839f9c6d6afd4a1eae1a0bdf8893ab2e19b9fdff)) * disable/some actions when no instructor ([#319](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/319)) ([839f9c6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/839f9c6d6afd4a1eae1a0bdf8893ab2e19b9fdff))
- **ui:** changed popup close icon to ut-black ([#394](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/394)) ([0077ae7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0077ae70d22f24549c4c3b243188d19adbfbac14)), closes [#333F48](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/333F48) * **ui:** changed popup close icon to ut-black ([#394](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/394)) ([0077ae7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0077ae70d22f24549c4c3b243188d19adbfbac14)), closes [#333F48](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/333F48)
- update senior swe admins ([#326](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/326)) ([b967240](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b967240f8fbb7a790a78f4aa256f0a77a491abb8)) * update senior swe admins ([#326](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/326)) ([b967240](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b967240f8fbb7a790a78f4aa256f0a77a491abb8))
- update useful links ([#367](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/367)) ([cef99c2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cef99c2d72d3a2800f8a918d01cb116f8795d0c8)) * update useful links ([#367](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/367)) ([cef99c2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cef99c2d72d3a2800f8a918d01cb116f8795d0c8))
- use "copy of" for duplicated schedules and place them under the original schedule [#358](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/358) ([#397](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/397)) ([94744e0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/94744e01b94819fb4f5d64616ea56857b906c2dd)) * use "copy of" for duplicated schedules and place them under the original schedule [#358](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/358) ([#397](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/397)) ([94744e0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/94744e01b94819fb4f5d64616ea56857b906c2dd))
### Bug Fixes ### Bug Fixes
- added descending sort for commits on contributor section in settings page ([#365](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/365)) ([a715bbd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a715bbd933a87742e7bce3a44e8ba1bd419ad5eb)), closes [#363](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/363) [#363](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/363) [#363](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/363) * added descending sort for commits on contributor section in settings page ([#365](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/365)) ([a715bbd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a715bbd933a87742e7bce3a44e8ba1bd419ad5eb)), closes [#363](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/363) [#363](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/363) [#363](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/363)
- change schedule total courses text color to UTRP black ([#369](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/369)) ([b00bf6c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b00bf6c180f1c6c3a61c5ef855e160ddf4af3ea4)) * change schedule total courses text color to UTRP black ([#369](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/369)) ([b00bf6c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b00bf6c180f1c6c3a61c5ef855e160ddf4af3ea4))
- changed the font-weight of h1-course ([#370](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/370)) ([4f609ae](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4f609aeec797c1f99f0a57e5aeef7b82756ea4bc)), closes [#347](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/347) * changed the font-weight of h1-course ([#370](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/370)) ([4f609ae](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4f609aeec797c1f99f0a57e5aeef7b82756ea4bc)), closes [#347](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/347)
- ensure input elements take full width of parent ([#364](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/364)) ([c2007ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c2007ef090aab3bbfcb8bca1ebc476255d09cb90)) * ensure input elements take full width of parent ([#364](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/364)) ([c2007ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c2007ef090aab3bbfcb8bca1ebc476255d09cb90))
- remove screenshot padding class for png download for [#344](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/344) ([#376](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/376)) ([768ac77](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/768ac776ed4d5ca2113a032a93c2dc7432915aa1)), closes [#334](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/334) * remove screenshot padding class for png download for [#344](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/344) ([#376](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/376)) ([768ac77](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/768ac776ed4d5ca2113a032a93c2dc7432915aa1)), closes [#334](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/334)
- sentry issues ([#389](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/389)) ([2d0804f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2d0804f90e5d7a9ff83f7fd5c5acfdc7c1b1cc84)) * sentry issues ([#389](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/389)) ([2d0804f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2d0804f90e5d7a9ff83f7fd5c5acfdc7c1b1cc84))
- typo in settings page ([#386](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/386)) ([d357735](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d3577358d0d1fb60f2c776ae4b01e255fcf9109e)) * typo in settings page ([#386](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/386)) ([d357735](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d3577358d0d1fb60f2c776ae4b01e255fcf9109e))
- **ui:** add space before/after forward slash in "ASYNC/OTHER" text ([#366](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/366)) ([86792eb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/86792eb56f04b615f7d52b2f417b88f4cb9a82ec)) * **ui:** add space before/after forward slash in "ASYNC/OTHER" text ([#366](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/366)) ([86792eb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/86792eb56f04b615f7d52b2f417b88f4cb9a82ec))
- **ui:** duplicate schedule warning ([#295](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/295)) ([7346720](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/73467208947e0116ce8538052ee75dea1d8038f9)) * **ui:** duplicate schedule warning ([#295](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/295)) ([7346720](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/73467208947e0116ce8538052ee75dea1d8038f9))
- **ui:** main popup now shows 0 for empty schedule ([#395](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/395)) ([8de88d6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8de88d6ad7d4c2b5c3aa08e1efc59f7226b40c6b)) * **ui:** main popup now shows 0 for empty schedule ([#395](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/395)) ([8de88d6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8de88d6ad7d4c2b5c3aa08e1efc59f7226b40c6b))
- **ui:** multiple instructors are formatted properly, displays last name only, and are capitalized in all course blocks ([#342](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/342)) ([#403](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/403)) ([50e88fa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/50e88fa015e0290fbe0dab8a19f8fcdbc4dd02b0)) * **ui:** multiple instructors are formatted properly, displays last name only, and are capitalized in all course blocks ([#342](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/342)) ([#403](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/403)) ([50e88fa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/50e88fa015e0290fbe0dab8a19f8fcdbc4dd02b0))
- **ui:** placeholder text for no instructor course [#400](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/400) ([#402](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/402)) ([b3ae91d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b3ae91d8f3cebb89e5e5cea7f1200d28326afb4d)) * **ui:** placeholder text for no instructor course [#400](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/400) ([#402](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/402)) ([b3ae91d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b3ae91d8f3cebb89e5e5cea7f1200d28326afb4d))
## [2.0.1](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.0.0...v2.0.1) (2024-10-17) ## [2.0.1](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/v2.0.0...v2.0.1) (2024-10-17)
### Features ### Features
- spring 2024 instructors db ([#317](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/317)) ([79dd29c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/79dd29cfc9e849b09e7d91bd0eed51c1c93b3352)) * spring 2024 instructors db ([#317](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/317)) ([79dd29c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/79dd29cfc9e849b09e7d91bd0eed51c1c93b3352))
### Bug Fixes ### Bug Fixes
- add a little error checking to settings ([#315](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/315)) ([e261641](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e261641e5985d8bd5047d8a0be5d1caae844e40f)) * add a little error checking to settings ([#315](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/315)) ([e261641](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e261641e5985d8bd5047d8a0be5d1caae844e40f))
- gulp zip ([#314](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/314)) ([05f00b2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/05f00b23d26b90f564710db4364426e90c8d6831)) * gulp zip ([#314](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/314)) ([05f00b2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/05f00b23d26b90f564710db4364426e90c8d6831))
- migration loop ([aeff5e0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aeff5e09a238503293c3882d97d40270da1e4883)) * migration loop ([aeff5e0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aeff5e09a238503293c3882d97d40270da1e4883))
- show calendar in active window ([#312](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/312)) ([ceba38b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ceba38b1ac74ec9e6630222183bd466a8d12c27d)) * show calendar in active window ([#312](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/312)) ([ceba38b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ceba38b1ac74ec9e6630222183bd466a8d12c27d))
## [2.0.0](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/b4e8c7589e53f1064d70703459cc6d66fae1b04c...v2.0.0) (2024-10-15) ## [2.0.0](https://github.com/Longhorn-Developers/UT-Registration-Plus/compare/b4e8c7589e53f1064d70703459cc6d66fae1b04c...v2.0.0) (2024-10-15)
### Features ### Features
- abhinavchadaga/course-catalog-popup ([#128](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/128)) ([745f9dd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/745f9dd6fb96ccc0eace7189b87abf9a38f03828)) * abhinavchadaga/course-catalog-popup ([#128](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/128)) ([745f9dd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/745f9dd6fb96ccc0eace7189b87abf9a38f03828))
- abhinavchadaga/reusable-popup-prompt ([#148](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/148)) ([44af9e1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/44af9e16e4bf3b92c9a4fa0e779197f4f9ecb237)) * abhinavchadaga/reusable-popup-prompt ([#148](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/148)) ([44af9e1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/44af9e16e4bf3b92c9a4fa0e779197f4f9ecb237))
- actually sum for duplicate semesters (different uniques) ([#202](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/202)) ([d3f64ec](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d3f64ec79eb64ebe72ae28991127dbe521823842)) * actually sum for duplicate semesters (different uniques) ([#202](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/202)) ([d3f64ec](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d3f64ec79eb64ebe72ae28991127dbe521823842))
- add button to the rows, use new ConflictsWithWarning component ([bec2649](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bec2649fc1244bffb5cb03809db62cc0ea477260)) * add button to the rows, use new ConflictsWithWarning component ([bec2649](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bec2649fc1244bffb5cb03809db62cc0ea477260))
- add buttons with icons in tailwind ([93b65ac](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/93b65ac2edef3fc728305cc51d1a32ecf5073274)) * add buttons with icons in tailwind ([93b65ac](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/93b65ac2edef3fc728305cc51d1a32ecf5073274))
- add cal save buttons (no functionality) ([53e7c7f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/53e7c7fedaf1f268d2d7d06ff1a5df9e2af2306d)) * add cal save buttons (no functionality) ([53e7c7f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/53e7c7fedaf1f268d2d7d06ff1a5df9e2af2306d))
- add Calendar Component ([e0212d5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e0212d510928e5e95d3ba75e391c34714f1bb035)) * add Calendar Component ([e0212d5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e0212d510928e5e95d3ba75e391c34714f1bb035))
- add Calendar schedules component (clicking on storybook not working) ([d1a336e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d1a336e903f09b04b89f11ba7ede2f7d26e0ac3c)) * add Calendar schedules component (clicking on storybook not working) ([d1a336e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d1a336e903f09b04b89f11ba7ede2f7d26e0ac3c))
- add CalendarHeader and its Storybook, need to resize ([23276e5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/23276e5c7c907261b1d02e9006d8021d99b43984)) * add CalendarHeader and its Storybook, need to resize ([23276e5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/23276e5c7c907261b1d02e9006d8021d99b43984))
- add check-path-alias custom ESLint rule ([#123](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/123)) ([208103d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/208103d7081abcf5b31bf36335320aaf7d213464)) * add check-path-alias custom ESLint rule ([#123](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/123)) ([208103d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/208103d7081abcf5b31bf36335320aaf7d213464))
- add chrome.storage api mocks for storybook use ([#141](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/141)) ([3839bff](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3839bff29ef6f0ecfad1e975e685df9a64d96c92)) * add chrome.storage api mocks for storybook use ([#141](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/141)) ([3839bff](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3839bff29ef6f0ecfad1e975e685df9a64d96c92))
- add CSS for calendarCell div ([6cdcf49](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6cdcf4930d9868c0ed45820f66102d89a644cfb6)) * add CSS for calendarCell div ([6cdcf49](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6cdcf4930d9868c0ed45820f66102d89a644cfb6))
- add CSS for hourLine div ([0ba6153](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0ba61534cbfc83408cb64eb1145ecacef1ee8f04)) * add CSS for hourLine div ([0ba6153](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0ba61534cbfc83408cb64eb1145ecacef1ee8f04))
- add CSS for timeLabelContainer div ([56f6456](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/56f6456ce85f77edb9d6fa64ecb82a8388feec41)) * add CSS for timeLabelContainer div ([56f6456](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/56f6456ce85f77edb9d6fa64ecb82a8388feec41))
- add custom ESLint rule restrict-import-depth ([#110](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/110)) ([8c069b7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8c069b7ad339ed8db97bb5e3e6e88ab8d332489b)) * add custom ESLint rule restrict-import-depth ([#110](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/110)) ([8c069b7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8c069b7ad339ed8db97bb5e3e6e88ab8d332489b))
- add downloadBlob util ([2af351e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2af351efa85264da5abeee27fbd091d4ce637041)) * add downloadBlob util ([2af351e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2af351efa85264da5abeee27fbd091d4ce637041))
- add empty settings component - waiting on design ([9d0f210](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9d0f2105481cc3d5affdb4bd69d428379ea92de3)) * add empty settings component - waiting on design ([9d0f210](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9d0f2105481cc3d5affdb4bd69d428379ea92de3))
- add ImportantLinks Component ([5dbee6f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5dbee6f0c39e620c3b65a5e0156fd59ec8217ca7)) * add ImportantLinks Component ([5dbee6f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5dbee6f0c39e620c3b65a5e0156fd59ec8217ca7))
- add List component ([e6b4049](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e6b40494031ca88894b2f918bb18448b70124481)) * add List component ([e6b4049](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e6b40494031ca88894b2f918bb18448b70124481))
- add MIMEType ([0c76052](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c760524781556cf089f1885dc4ff3fd567bfc2b)) * add MIMEType ([0c76052](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c760524781556cf089f1885dc4ff3fd567bfc2b))
- add new db powered by UT_Grade_Parser ([#163](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/163)) ([60d1f48](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/60d1f48bd95132f0517258f017a7644d8aff5101)) * add new db powered by UT_Grade_Parser ([#163](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/163)) ([60d1f48](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/60d1f48bd95132f0517258f017a7644d8aff5101))
- add react-loading-skeleton package ([#244](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/244)) ([b4dd91a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b4dd91ad2595d9583a60530c2c2ff6d829d2d5e5)) * add react-loading-skeleton package ([#244](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/244)) ([b4dd91a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b4dd91ad2595d9583a60530c2c2ff6d829d2d5e5))
- add skeleton loader for course description + distribution ([#267](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/267)) ([c2cab40](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c2cab407f3a07c1d3073e936c9d23cb1cecc9cb9)) * add skeleton loader for course description + distribution ([#267](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/267)) ([c2cab40](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c2cab407f3a07c1d3073e936c9d23cb1cecc9cb9))
- add story for CalendarGridCell ([fd91c3b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fd91c3b12ef5670563e689d190be75ef1f695d1c)) * add story for CalendarGridCell ([fd91c3b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fd91c3b12ef5670563e689d190be75ef1f695d1c))
- add Storybook story ([cb3cb5d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cb3cb5d5fc18a68ca5a825f97b808b535aa1fe29)) * add Storybook story ([cb3cb5d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cb3cb5d5fc18a68ca5a825f97b808b535aa1fe29))
- add tailwind version of Button component ([28d93b3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/28d93b3c25e1cbca3baea992a299d626ca823570)) * add tailwind version of Button component ([28d93b3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/28d93b3c25e1cbca3baea992a299d626ca823570))
- add tickmarks to day div ([8b9cb06](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8b9cb065c28b5dd38b7e1681839a81f55691a3c6)) * add tickmarks to day div ([8b9cb06](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8b9cb065c28b5dd38b7e1681839a81f55691a3c6))
- add time column to Calendar Component ([9d68211](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9d6821127e7ff9bf63cef659932ee7408de4c969)) * add time column to Calendar Component ([9d68211](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9d6821127e7ff9bf63cef659932ee7408de4c969))
- add timeAndGrid div ([95e0544](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/95e0544b7301d382439b74038fb1b3e25dfe6d30)) * add timeAndGrid div ([95e0544](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/95e0544b7301d382439b74038fb1b3e25dfe6d30))
- added flag ;-; ([#195](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/195)) ([9b4d61c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9b4d61c2b0d8806b5d4a10296c1cc1266ac4229f)) * added flag ;-; ([#195](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/195)) ([9b4d61c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9b4d61c2b0d8806b5d4a10296c1cc1266ac4229f))
- added scrapedAt property ([#149](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/149)) ([8e181b3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8e181b3010dfe25ea1e4b4ba181cbe9944d6e92e)) * added scrapedAt property ([#149](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/149)) ([8e181b3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8e181b3010dfe25ea1e4b4ba181cbe9944d6e92e))
- additional changes to [#201](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/201) ([#224](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/224)) ([bc354f3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bc354f3798a02e6ebc3c66a8b5eee553c25a19d4)) * additional changes to [#201](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/201) ([#224](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/224)) ([bc354f3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bc354f3798a02e6ebc3c66a8b5eee553c25a19d4))
- aesthetically pleasing squishier course blocks when compressed ([#232](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/232)) ([438c82b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/438c82bfb5db0f570b261d15368a05447939b0fb)) * aesthetically pleasing squishier course blocks when compressed ([#232](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/232)) ([438c82b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/438c82bfb5db0f570b261d15368a05447939b0fb))
- align day labels and add to grid ([1bb6191](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1bb6191244f40220a9af66cced4fe8f0c1e546a0)) * align day labels and add to grid ([1bb6191](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1bb6191244f40220a9af66cced4fe8f0c1e546a0))
- alignment on calendar and header ([#109](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/109)) ([07ec5ab](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/07ec5abc3e1b40b801b7c977d21399b31222a4d3)) * alignment on calendar and header ([#109](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/109)) ([07ec5ab](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/07ec5abc3e1b40b801b7c977d21399b31222a4d3))
- async course adding and async/other course block adjustments ([#273](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/273)) ([668c8d0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/668c8d00756a5e3e3daaade46380967c74eec1ae)) * async course adding and async/other course block adjustments ([#273](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/273)) ([668c8d0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/668c8d00756a5e3e3daaade46380967c74eec1ae))
- async text hiding on Calendar's Bottom Bar when there are no async courses ([#152](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/152)) ([0dff122](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0dff12232c29415fa7bc5ac3771393a406ab738d)) * async text hiding on Calendar's Bottom Bar when there are no async courses ([#152](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/152)) ([0dff122](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0dff12232c29415fa7bc5ac3771393a406ab738d))
- basic CalendarCourseMeeting component laid out - missing Text and Right Icon ([da9e7aa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/da9e7aac4135afa5184e4949c36a288ef6ab62a7)) * basic CalendarCourseMeeting component laid out - missing Text and Right Icon ([da9e7aa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/da9e7aac4135afa5184e4949c36a288ef6ab62a7))
- Best Practices ([#102](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/102)) ([5eb7be2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5eb7be246cd2a1db27c7ca777d81074ae7bb3b82)) * Best Practices ([#102](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/102)) ([5eb7be2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5eb7be246cd2a1db27c7ca777d81074ae7bb3b82))
- beta builds ([#187](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/187)) ([8a5e12e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8a5e12ec63539ae7199f0f1561f642cb9cf19302)) * beta builds ([#187](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/187)) ([8a5e12e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8a5e12ec63539ae7199f0f1561f642cb9cf19302))
- better discord icon ([#205](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/205)) ([a3f5e0f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a3f5e0f27ffdfcb4e3ddd47140979aca379f9f42)) * better discord icon ([#205](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/205)) ([a3f5e0f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a3f5e0f27ffdfcb4e3ddd47140979aca379f9f42))
- bold red refresh error ([#220](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/220)) ([229a8a2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/229a8a29e8d04dfbe15de200ceffc53b4f758413)) * bold red refresh error ([#220](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/220)) ([229a8a2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/229a8a29e8d04dfbe15de200ceffc53b4f758413))
- bottom bar for the calendar page ([#91](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/91)) ([0f730d6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0f730d6c50462c9f7d0428ebb379742305212ef6)) * bottom bar for the calendar page ([#91](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/91)) ([0f730d6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0f730d6c50462c9f7d0428ebb379742305212ef6))
- build without errors ([babc925](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/babc925967b01f1064b8d8e067e7bc792dd57b0a)) * build without errors ([babc925](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/babc925967b01f1064b8d8e067e7bc792dd57b0a))
- calendar components 3rd attempt at merging ([#60](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/60)) ([4faca8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4faca8c43befe19c9b05ff4f3afba420e016bb59)) * calendar components 3rd attempt at merging ([#60](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/60)) ([4faca8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4faca8c43befe19c9b05ff4f3afba420e016bb59))
- Calendar Components 3rd Attempt at Merging ([#60](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/60)) ([ab2cd68](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ab2cd688fae616742b39c0637291a65e508e23bd)) * Calendar Components 3rd Attempt at Merging ([#60](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/60)) ([ab2cd68](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ab2cd688fae616742b39c0637291a65e508e23bd))
- calendar course block component ([#75](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/75)) ([00e0019](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/00e00197efb807d420196f2b030fc4dc71e9cd42)) * calendar course block component ([#75](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/75)) ([00e0019](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/00e00197efb807d420196f2b030fc4dc71e9cd42))
- calendar course block component ([#75](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/75)) ([a41cb3e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a41cb3ed8711eff9a2fbbe435e867c073904f452)) * calendar course block component ([#75](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/75)) ([a41cb3e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a41cb3ed8711eff9a2fbbe435e867c073904f452))
- calendar grid and grid cells ([#81](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/81)) ([bfeb239](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bfeb2398aacf9a1fba892737b6ef0286acbc326f)) * calendar grid and grid cells ([#81](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/81)) ([bfeb239](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bfeb2398aacf9a1fba892737b6ef0286acbc326f))
- Calendar Grid and Grid Cells ([#81](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/81)) ([dd2f696](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dd2f696f8de2c0b291e917ef4d4cb2171b76712c)) * Calendar Grid and Grid Cells ([#81](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/81)) ([dd2f696](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dd2f696f8de2c0b291e917ef4d4cb2171b76712c))
- calendar header formatting and data displaying ([#160](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/160)) ([5cce1c7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5cce1c79fc2b50843426ed290a1b53849375e4eb)) * calendar header formatting and data displaying ([#160](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/160)) ([5cce1c7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5cce1c79fc2b50843426ed290a1b53849375e4eb))
- calendar matchings ([#173](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/173)) ([791a42b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/791a42bcd49478024b6f1a237a2d2a9f6211749e)) * calendar matchings ([#173](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/173)) ([791a42b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/791a42bcd49478024b6f1a237a2d2a9f6211749e))
- Calendar Schedule component finished, fix: list didn't allow updates when adding a new schedule ([#115](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/115)) ([a99a557](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a99a55788a0b9791ff048c8bbbaad5bada47c41f)) * Calendar Schedule component finished, fix: list didn't allow updates when adding a new schedule ([#115](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/115)) ([a99a557](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a99a55788a0b9791ff048c8bbbaad5bada47c41f))
- calendar-course-cell-color-picker ([#157](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/157)) ([df18491](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/df1849180de2c793c10e3a49d2c862d236456ec2)) * calendar-course-cell-color-picker ([#157](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/157)) ([df18491](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/df1849180de2c793c10e3a49d2c862d236456ec2))
- can open tabs, updated injected popup heading. basically done ([35fab34](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/35fab3444582b436f63c7b16a26ebd5989c4bf3e)) * can open tabs, updated injected popup heading. basically done ([35fab34](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/35fab3444582b436f63c7b16a26ebd5989c4bf3e))
- change Chip to tailwind css. Fixed eslint for ConflictsWithWarning ([3568b8e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3568b8eb5ee9ce3fe17f77f5641c0583bacc17a4)) * change Chip to tailwind css. Fixed eslint for ConflictsWithWarning ([3568b8e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3568b8eb5ee9ce3fe17f77f5641c0583bacc17a4))
- check-path-alias autofix ([#124](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/124)) ([265652c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/265652c4200a56b1ae62e6e94e0609fb4604c188)) * check-path-alias autofix ([#124](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/124)) ([265652c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/265652c4200a56b1ae62e6e94e0609fb4604c188))
- chrome extension works ([35f3c72](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/35f3c7225049d760c6061ed827aa796514291e62)) * chrome extension works ([35f3c72](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/35f3c7225049d760c6061ed827aa796514291e62))
- color palette for calendar ([#118](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/118)) ([471e55d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/471e55dcea1ae439658d00ed41570e2f218f0c3d)) * color palette for calendar ([#118](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/118)) ([471e55d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/471e55dcea1ae439658d00ed41570e2f218f0c3d))
- Conventional Commits ([#103](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/103)) ([fe599df](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fe599dfe7514ead880596d3b75c8370bde796e09)) * Conventional Commits ([#103](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/103)) ([fe599df](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fe599dfe7514ead880596d3b75c8370bde796e09))
- convert all LabelsAndDetails Components to Tailwind ([9e0f9df](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9e0f9df9de1a5c99657ddcef3b2eb101dd825b84)) * convert all LabelsAndDetails Components to Tailwind ([9e0f9df](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9e0f9df9de1a5c99657ddcef3b2eb101dd825b84))
- course color generation ([#179](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/179)) ([5ed81e4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5ed81e4be99a8b7f3c68a3ba70358e4cbe5cc613)) * course color generation ([#179](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/179)) ([5ed81e4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5ed81e4be99a8b7f3c68a3ba70358e4cbe5cc613))
- course colors ([#175](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/175)) ([dc77cc2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dc77cc27da7ab521e290a8c9ba810573e677b6b8)) * course colors ([#175](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/175)) ([dc77cc2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dc77cc27da7ab521e290a8c9ba810573e677b6b8))
- Course Flag Tooltips ([#178](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/178)) ([ba2bc60](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ba2bc60add2b87ccd4e9894c454d7a8d8382f0dd)) * Course Flag Tooltips ([#178](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/178)) ([ba2bc60](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ba2bc60add2b87ccd4e9894c454d7a8d8382f0dd))
- course-catalog-injected-popup ([#98](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/98)) ([89d03f4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/89d03f4244d324915cadadaf75a827221525d43f)) * course-catalog-injected-popup ([#98](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/98)) ([89d03f4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/89d03f4244d324915cadadaf75a827221525d43f))
- CourseStatus Component implemented ([#83](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/83)) ([58d7df4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/58d7df499ca9a8dfd4dc3aa47bc9d76837f21bf7)) * CourseStatus Component implemented ([#83](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/83)) ([58d7df4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/58d7df499ca9a8dfd4dc3aa47bc9d76837f21bf7))
- CourseStatus Component implemented ([#83](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/83)) ([fa1d737](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fa1d7374bcafbe19673dc31f33b3f8075e45f37a)) * CourseStatus Component implemented ([#83](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/83)) ([fa1d737](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/fa1d7374bcafbe19673dc31f33b3f8075e45f37a))
- create empty Popup story ([ad83ba4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ad83ba4cdc67f86096d0cbc2cb6659aa9be98a0b)) * create empty Popup story ([ad83ba4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ad83ba4cdc67f86096d0cbc2cb6659aa9be98a0b))
- Create icon helper ([#77](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/77)) ([ccea0f4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ccea0f4bd1e8d66dc0717d92c9e970040d9fbe9e)) * Create icon helper ([#77](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/77)) ([ccea0f4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ccea0f4bd1e8d66dc0717d92c9e970040d9fbe9e))
- Create icon helper ([#77](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/77)) ([1b51d65](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1b51d65c89a4b544f4f2a9c60106e14300f9a3b0)) * Create icon helper ([#77](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/77)) ([1b51d65](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1b51d65c89a4b544f4f2a9c60106e14300f9a3b0))
- Derek vinson/calendar header ([#94](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/94)) ([12d09b5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/12d09b54cbf840993d17323b96cf274ec24c67ce)) * Derek vinson/calendar header ([#94](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/94)) ([12d09b5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/12d09b54cbf840993d17323b96cf274ec24c67ce))
- Derek/disable updating ([#239](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/239)) ([0ab83ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0ab83efd47d75fb6c278994c7dc8a6d22b4b6b83)) * Derek/disable updating ([#239](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/239)) ([0ab83ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0ab83efd47d75fb6c278994c7dc8a6d22b4b6b83))
- Derek/export png ([#95](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/95)) ([58c2b46](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/58c2b4634a9d065ca156d27c4af69a504b7c2d2d)) * Derek/export png ([#95](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/95)) ([58c2b46](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/58c2b4634a9d065ca156d27c4af69a504b7c2d2d))
- DialogProvider component ([#198](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/198)) ([d1b921a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d1b921a5b000693d7f3dabaf84d8b9580c361941)) * DialogProvider component ([#198](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/198)) ([d1b921a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d1b921a5b000693d7f3dabaf84d8b9580c361941))
- dividers in calendar bottom bar ([#120](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/120)) ([eba5d9f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/eba5d9f508576d2648bd2501e5d5aaff32592566)) * dividers in calendar bottom bar ([#120](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/120)) ([eba5d9f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/eba5d9f508576d2648bd2501e5d5aaff32592566))
- **docs:** add extra acknowledgements ([e2cbfa3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e2cbfa3f48cb0b10a43134cf9784a44b13aa542d)) * **docs:** add extra acknowledgements ([e2cbfa3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e2cbfa3f48cb0b10a43134cf9784a44b13aa542d))
- drag only on vertical axis ([34a6449](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/34a644952995d4aedd18d11d327bd8589f5b2610)) * drag only on vertical axis ([34a6449](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/34a644952995d4aedd18d11d327bd8589f5b2610))
- early iteration of non-virtual list ([677aa62](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/677aa624d7fb2bbb922aaf8806abe979c3399e4e)) * early iteration of non-virtual list ([677aa62](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/677aa624d7fb2bbb922aaf8806abe979c3399e4e))
- enable TS strict mode ([#168](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/168)) ([efed1c0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/efed1c0edbf93987c551952a03c9c4b3c461d819)) * enable TS strict mode ([#168](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/168)) ([efed1c0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/efed1c0edbf93987c551952a03c9c4b3c461d819))
- experimental toggle for icons, left off for now ([#237](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/237)) ([f34dd95](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f34dd95d7765322b6cecb2e817a46e0549d929a5)) * experimental toggle for icons, left off for now ([#237](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/237)) ([f34dd95](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f34dd95d7765322b6cecb2e817a46e0549d929a5))
- fall 2023 grades ([#226](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/226)) ([863d980](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/863d980b2d1c706b1fc648f1a0de2a31515e339e)) * fall 2023 grades ([#226](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/226)) ([863d980](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/863d980b2d1c706b1fc648f1a0de2a31515e339e))
- finally fix grid JSX.Element generation ([e49fc29](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e49fc295ba40a37f9bf59686adbd8b4f523cd9c6)) * finally fix grid JSX.Element generation ([e49fc29](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e49fc295ba40a37f9bf59686adbd8b4f523cd9c6))
- finish ScheduleTotalHoursAndCourses ([12f680d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/12f680d7e9aef826281c8f769825408dc6f9f9de)) * finish ScheduleTotalHoursAndCourses ([12f680d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/12f680d7e9aef826281c8f769825408dc6f9f9de))
- fix icons on PopupMain and convert to tailwind ([#108](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/108)) ([87799d8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/87799d8f02aa5986025982f768639afdb1b0267a)) * fix icons on PopupMain and convert to tailwind ([#108](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/108)) ([87799d8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/87799d8f02aa5986025982f768639afdb1b0267a))
- fix save as button dividers ([#153](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/153)) ([7986549](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7986549fdd40834a85bedbfd0862cdb21c9ae657)) * fix save as button dividers ([#153](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/153)) ([7986549](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7986549fdd40834a85bedbfd0862cdb21c9ae657))
- grades by professor ([#225](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/225)) ([78d749a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/78d749a8a96f63c32663b464e5b663f932c28ed0)) * grades by professor ([#225](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/225)) ([78d749a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/78d749a8a96f63c32663b464e5b663f932c28ed0))
- html2canvas -> htmlToImage and fix derick's bugs ([bda0282](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bda02826b14b96fd65a6f24218950e510c5aa3d8)) * html2canvas -> htmlToImage and fix derick's bugs ([bda0282](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bda02826b14b96fd65a6f24218950e510c5aa3d8))
- icon added successfully ([3b588c2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3b588c20394523ddf90456e1ca58546e5b820c74)) * icon added successfully ([3b588c2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3b588c20394523ddf90456e1ca58546e5b820c74))
- implement Chip component ([23e881f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/23e881f14cc80100d8f8deef6a25daaa72d83f07)) * implement Chip component ([23e881f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/23e881f14cc80100d8f8deef6a25daaa72d83f07))
- implement flatten course schedule helper function ([e54f488](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e54f488b170d5a9af646c1ac82e8b33579fef61d)) * implement flatten course schedule helper function ([e54f488](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e54f488b170d5a9af646c1ac82e8b33579fef61d))
- implemented ConflictsWithWarning ([93f3a30](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/93f3a307b4acce6cc55fc411f1ea2d7576006b00)) * implemented ConflictsWithWarning ([93f3a30](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/93f3a307b4acce6cc55fc411f1ea2d7576006b00))
- implemented InfoCard ([21b6430](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/21b643000d884442e025534802be6bb1f6ba68e2)) * implemented InfoCard ([21b6430](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/21b643000d884442e025534802be6bb1f6ba68e2))
- Initial Splash Text Commit ([#208](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/208)) ([0534f60](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0534f607a51f1dd0905f6f45f08519cba65ea05a)) * Initial Splash Text Commit ([#208](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/208)) ([0534f60](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0534f607a51f1dd0905f6f45f08519cba65ea05a))
- limit schedules to 10 ([#272](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/272)) ([290b841](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/290b8415170bca631e5d71b08d88db80b02163f0)) * limit schedules to 10 ([#272](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/272)) ([290b841](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/290b8415170bca631e5d71b08d88db80b02163f0))
- link to your registered courses ([#228](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/228)) ([f83e012](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f83e012d62e268d95dce19a30e54e34f3779142b)) * link to your registered courses ([#228](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/228)) ([f83e012](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f83e012d62e268d95dce19a30e54e34f3779142b))
- list reordering ([#154](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/154)) ([038ebaa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/038ebaa2689c14bc9906afb542ef62c21cb13177)) * list reordering ([#154](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/154)) ([038ebaa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/038ebaa2689c14bc9906afb542ef62c21cb13177))
- listed versioning for beta builds ([#192](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/192)) ([0c42979](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c429794230a91c4fd949715b7eea210ac18fee3)) * listed versioning for beta builds ([#192](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/192)) ([0c42979](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c429794230a91c4fd949715b7eea210ac18fee3))
- lowercase instructor! ([#268](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/268)) ([9ec05ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9ec05ef764b2451c05e2d084d92074fb1e984268)) * lowercase instructor! ([#268](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/268)) ([9ec05ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9ec05ef764b2451c05e2d084d92074fb1e984268))
- made List more extensible ([cd34601](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cd34601379d5cd2b53d967afbc954178834823b9)) * made List more extensible ([cd34601](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cd34601379d5cd2b53d967afbc954178834823b9))
- match calendar designs & add functionality ([#176](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/176)) ([8027c3d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8027c3d1bf228053acbad3e232b030c9ddbaca6a)) * match calendar designs & add functionality ([#176](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/176)) ([8027c3d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8027c3d1bf228053acbad3e232b030c9ddbaca6a))
- migrate styles to TailwindCSS ([7e2f5ea](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7e2f5eaed7d782bc886545f7241e0891d55cfae0)) * migrate styles to TailwindCSS ([7e2f5ea](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7e2f5eaed7d782bc886545f7241e0891d55cfae0))
- migration update showing ([#293](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/293)) ([aede681](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aede681d4bb5b01723eb9d68527f4e64991adfab)) * migration update showing ([#293](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/293)) ([aede681](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aede681d4bb5b01723eb9d68527f4e64991adfab))
- missed one chip toggle there ([#245](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/245)) ([5ca24da](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5ca24dab82509d34cf43af4359940476159d052f)) * missed one chip toggle there ([#245](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/245)) ([5ca24da](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5ca24dab82509d34cf43af4359940476159d052f))
- newer grades and parameterized queries ([#238](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/238)) ([75ad416](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/75ad4167b6639bbcf58e2dc6dafc80ed4656a899)) * newer grades and parameterized queries ([#238](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/238)) ([75ad416](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/75ad4167b6639bbcf58e2dc6dafc80ed4656a899))
- one single exclamation mark did all that ([#235](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/235)) ([be87e41](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/be87e4181430e0df41683be5c9d0a1ce992b2c61)) * one single exclamation mark did all that ([#235](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/235)) ([be87e41](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/be87e4181430e0df41683be5c9d0a1ce992b2c61))
- open an injected course page on course block click in popup main ([#146](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/146)) ([2709484](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/27094846f70feb8d83c8d464ab0fa8dcd99b3e71)) * open an injected course page on course block click in popup main ([#146](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/146)) ([2709484](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/27094846f70feb8d83c8d464ab0fa8dcd99b3e71))
- pad unique ids to 5 digits ([#170](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/170)) ([b4ad687](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b4ad6870bfc88f68bdd7f87fe1d94c23d0a02b95)) * pad unique ids to 5 digits ([#170](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/170)) ([b4ad687](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b4ad6870bfc88f68bdd7f87fe1d94c23d0a02b95))
- parallelize initializeDB.ts promises ([9f1dcc6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9f1dcc667df9857e3d0469fe7112a9f985aad490)) * parallelize initializeDB.ts promises ([9f1dcc6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9f1dcc667df9857e3d0469fe7112a9f985aad490))
- popout icon for ccip in calendar ([#221](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/221)) ([6812d68](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6812d685d08902f7b3d9d2e5293350c8170c6f06)) * popout icon for ccip in calendar ([#221](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/221)) ([6812d68](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6812d685d08902f7b3d9d2e5293350c8170c6f06))
- popup schedule select ([#126](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/126)) ([7f2a589](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7f2a5893d4dd82a0f077dca6dfd28e79f929766f)) * popup schedule select ([#126](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/126)) ([7f2a589](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7f2a5893d4dd82a0f077dca6dfd28e79f929766f))
- PopupCourseBlock Component ([#79](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/79)) ([9accd17](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9accd17bd418f8c9334e80b0f7e38673092ba208)) * PopupCourseBlock Component ([#79](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/79)) ([9accd17](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9accd17bd418f8c9334e80b0f7e38673092ba208))
- PopupCourseBlock Component ([#79](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/79)) ([f045b40](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f045b400a56569f7353eb00ecd0d081b68660fc5)) * PopupCourseBlock Component ([#79](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/79)) ([f045b40](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f045b400a56569f7353eb00ecd0d081b68660fc5))
- proper injected styles ([#164](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/164)) ([e919e96](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e919e96c53bc9bec7db3d09693d1ff0684b56e87)) * proper injected styles ([#164](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/164)) ([e919e96](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e919e96c53bc9bec7db3d09693d1ff0684b56e87))
- readme animation ([#281](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/281)) ([da6d86c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/da6d86c785f92f70f52ef0b4cab3dc14e0bd9790)) * readme animation ([#281](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/281)) ([da6d86c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/da6d86c785f92f70f52ef0b4cab3dc14e0bd9790))
- refactor all components in common ([e544312](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e5443122b422266a126de497b475020e298b2f1c)) * refactor all components in common ([e544312](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e5443122b422266a126de497b475020e298b2f1c))
- refactor all components in injected ([0c44849](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c44849e15333c3a5cbdf8972eb31ada0e830b0a)) * refactor all components in injected ([0c44849](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c44849e15333c3a5cbdf8972eb31ada0e830b0a))
- refactor calendar ([28f1924](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/28f192472b7f244253b6a0b5339491b9740880f7)) * refactor calendar ([28f1924](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/28f192472b7f244253b6a0b5339491b9740880f7))
- Refactor database initialization code ([5e98f45](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5e98f45210346f0e7bb69af5cf25e336c76416ca)) * Refactor database initialization code ([5e98f45](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5e98f45210346f0e7bb69af5cf25e336c76416ca))
- release notes ([#283](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/283)) ([bd17e33](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bd17e3353792df70ca2e33c8b7a32b5fb9acc7d2)) * release notes ([#283](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/283)) ([bd17e33](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bd17e3353792df70ca2e33c8b7a32b5fb9acc7d2))
- report issue popup ([#261](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/261)) ([65ff6bf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/65ff6bfbbfc6b696621628e448865155d0405f7f)) * report issue popup ([#261](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/261)) ([65ff6bf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/65ff6bfbbfc6b696621628e448865155d0405f7f))
- rerouted directory to syllabus when click on professor name ([#211](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/211)) ([8959e0d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8959e0d9f7fdd82125f391f1ec51aa390ba9450d)) * rerouted directory to syllabus when click on professor name ([#211](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/211)) ([8959e0d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8959e0d9f7fdd82125f391f1ec51aa390ba9450d))
- sam's jokes ([#278](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/278)) ([895cd31](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/895cd31d8eb40e7e99fc0969b543e95bd070f6b7)) * sam's jokes ([#278](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/278)) ([895cd31](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/895cd31d8eb40e7e99fc0969b543e95bd070f6b7))
- save as PNG functionality ([ad18fbd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ad18fbd16235be0c75121b527867fac708670300)) * save as PNG functionality ([ad18fbd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ad18fbd16235be0c75121b527867fac708670300))
- schedule list item action menu ([#230](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/230)) ([15fc369](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/15fc3699cfda3ad56e5a262bd37dca166e2685dd)) * schedule list item action menu ([#230](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/230)) ([15fc369](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/15fc3699cfda3ad56e5a262bd37dca166e2685dd))
- screenshot whole page, hide certain elements, screenshot fixed size ([#180](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/180)) ([7d4c5d7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7d4c5d7be8b266b5f3caf2135c4f3fecb96d75be)) * screenshot whole page, hide certain elements, screenshot fixed size ([#180](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/180)) ([7d4c5d7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7d4c5d7be8b266b5f3caf2135c4f3fecb96d75be))
- settings page ([#260](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/260)) ([7a5c3a2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7a5c3a2e62c3a726735f9fe921f9e08d4092d0f9)) * settings page ([#260](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/260)) ([7a5c3a2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7a5c3a2e62c3a726735f9fe921f9e08d4092d0f9))
- show async courses in the bottom bar ([#204](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/204)) ([227de53](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/227de53e8453804f0791f269dae64ec388136390)) * show async courses in the bottom bar ([#204](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/204)) ([227de53](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/227de53e8453804f0791f269dae64ec388136390))
- some small changes for colors and font ([#201](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/201)) ([bae1da4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bae1da43d3373e12d593682e9fb69e19557b5749)) * some small changes for colors and font ([#201](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/201)) ([bae1da4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bae1da43d3373e12d593682e9fb69e19557b5749))
- splash text additions before v2 release ([#296](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/296)) ([e774f31](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e774f316e3f92c03e79274a55f1f729178c9a14a)) * splash text additions before v2 release ([#296](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/296)) ([e774f31](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e774f316e3f92c03e79274a55f1f729178c9a14a))
- splash text has arrived! ([#246](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/246)) ([9971435](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9971435716dec11e954dc26c14bf7d1505563d0d)) * splash text has arrived! ([#246](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/246)) ([9971435](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9971435716dec11e954dc26c14bf7d1505563d0d))
- Storybook for Vite ([#52](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/52)) ([9cc299c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9cc299ced6132644a5c2375b95a8a16a3482601b)) * Storybook for Vite ([#52](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/52)) ([9cc299c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9cc299ced6132644a5c2375b95a8a16a3482601b))
- swe title updates ([#310](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/310)) ([4629626](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4629626a31934c491758ddca874e5018d9c22e57)) * swe title updates ([#310](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/310)) ([4629626](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4629626a31934c491758ddca874e5018d9c22e57))
- switch button ([#229](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/229)) ([abae7a5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/abae7a5c22ab944262d66ae897298b008a03c5f1)) * switch button ([#229](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/229)) ([abae7a5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/abae7a5c22ab944262d66ae897298b008a03c5f1))
- temporary removal of waitlist etc ([#236](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/236)) ([d424ccc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d424ccce49ba05305b24cb61aeb4ffeada5bab33)) * temporary removal of waitlist etc ([#236](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/236)) ([d424ccc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d424ccce49ba05305b24cb61aeb4ffeada5bab33))
- UnoCSS (TailwindCSS) (Storybook only) ([#61](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/61)) ([85c7f78](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/85c7f7817c58f13f6a4e8bec13a45f6412ad87db)) * UnoCSS (TailwindCSS) (Storybook only) ([#61](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/61)) ([85c7f78](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/85c7f7817c58f13f6a4e8bec13a45f6412ad87db))
- UnoCSS (TailwindCSS) (Storybook only) ([#61](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/61)) ([6521a4b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6521a4b2a90af06e182c779f2fc7cb1a3b1e55c1)) * UnoCSS (TailwindCSS) (Storybook only) ([#61](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/61)) ([6521a4b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6521a4b2a90af06e182c779f2fc7cb1a3b1e55c1))
- unplugin-icons ([#62](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/62)) ([2d67b12](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2d67b1218ff852c59901b77909615c5f54794a67)) * unplugin-icons ([#62](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/62)) ([2d67b12](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2d67b1218ff852c59901b77909615c5f54794a67))
- unplugin-icons ([#62](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/62)) ([945e09b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/945e09b49e4ffa9bd4b02442f6567bb99831923e)) * unplugin-icons ([#62](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/62)) ([945e09b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/945e09b49e4ffa9bd4b02442f6567bb99831923e))
- update admin titles ([4cf8c3f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4cf8c3f9645cd8fda07244413cdc406105b12fec)) * update admin titles ([4cf8c3f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4cf8c3f9645cd8fda07244413cdc406105b12fec))
- update badge count when schedule changes ([#150](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/150)) ([a5e9e3c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a5e9e3c2145d61d8cc5788eb50fa19718e6d13bf)) * update badge count when schedule changes ([#150](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/150)) ([a5e9e3c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a5e9e3c2145d61d8cc5788eb50fa19718e6d13bf))
- update Button to v2 design ([863521f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/863521fb3bb268131bd3f369064ae10a442b4fbc)) * update Button to v2 design ([863521f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/863521fb3bb268131bd3f369064ae10a442b4fbc))
- update dialog component to headlessui ([#159](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/159)) ([442be8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/442be8cbee06ec403467b100d8d5300dd4a7ea72)) * update dialog component to headlessui ([#159](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/159)) ([442be8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/442be8cbee06ec403467b100d8d5300dd4a7ea72))
- update with TailwindCSS ([f3a8a7d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f3a8a7db560a6b28f96a2e976c8ed33af97fe77a)) * update with TailwindCSS ([f3a8a7d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f3a8a7db560a6b28f96a2e976c8ed33af97fe77a))
- updated calendar page and recruitment banner links ([#219](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/219)) ([a2303ee](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a2303ee35f10aba5fa7ff5e307d0092a39f18830)) * updated calendar page and recruitment banner links ([#219](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/219)) ([a2303ee](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a2303ee35f10aba5fa7ff5e307d0092a39f18830))
- updated divider component ([#99](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/99)) ([8ab60c9](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8ab60c9f018143df594e7bfd0d321666289cc28c)) * updated divider component ([#99](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/99)) ([8ab60c9](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8ab60c9f018143df594e7bfd0d321666289cc28c))
- updated Text component to latest design specification ([#70](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/70)) ([8b8433d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8b8433deaf8fe66f917fd66fb56cb0a748bc6e6e)) * updated Text component to latest design specification ([#70](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/70)) ([8b8433d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8b8433deaf8fe66f917fd66fb56cb0a748bc6e6e))
- updated Text component to latest design specification ([#70](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/70)) ([bb727f7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bb727f70bea5a4c2ff5dba7e9b4428c0c84de7b2)) * updated Text component to latest design specification ([#70](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/70)) ([bb727f7](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bb727f70bea5a4c2ff5dba7e9b4428c0c84de7b2))
- updating joke styling and updating jokes array ([#277](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/277)) ([0da27e2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0da27e2c46e9fc32efb80808715053c1f9f5165a)) * updating joke styling and updating jokes array ([#277](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/277)) ([0da27e2](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0da27e2c46e9fc32efb80808715053c1f9f5165a))
- use display: grid for calendarGrid ([b535a6e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b535a6eb32ac1091c8b5309ca3cfb6bab0b62526)) * use display: grid for calendarGrid ([b535a6e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b535a6eb32ac1091c8b5309ca3cfb6bab0b62526))
- use downloadBlob util ([#186](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/186)) ([2dfb10e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2dfb10e57b51a08fcde2dc6638a81b5ec9bbc7ab)) * use downloadBlob util ([#186](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/186)) ([2dfb10e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2dfb10e57b51a08fcde2dc6638a81b5ec9bbc7ab))
- use filter() instead of pop() ([063349d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/063349d96d0ad008fa0dc1f0a8c7a27cf3f108ce)) * use filter() instead of pop() ([063349d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/063349d96d0ad008fa0dc1f0a8c7a27cf3f108ce))
- use React-icons ([8df9ea5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8df9ea55a9f0bcb04c90314cb311bba9d1ebf2e3)) * use React-icons ([8df9ea5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8df9ea55a9f0bcb04c90314cb311bba9d1ebf2e3))
- UTRP v2 migration ([#292](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/292)) ([d22237d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d22237d561ddf6a2f8ed699ca4c11088a8b408e8)) * UTRP v2 migration ([#292](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/292)) ([d22237d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d22237d561ddf6a2f8ed699ca4c11088a8b408e8))
- working PNG and CAL downloads ([#119](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/119)) ([d9ee23c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d9ee23c5bbe27240a0e2849aae2eae81d7960bb5)) * working PNG and CAL downloads ([#119](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/119)) ([d9ee23c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d9ee23c5bbe27240a0e2849aae2eae81d7960bb5))
### Bug Fixes ### Bug Fixes
- add margin-top: -10px to p ([18406b0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/18406b0c94604b1b524de03bf97e78cffe7a5bbf)) * add margin-top: -10px to p ([18406b0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/18406b0c94604b1b524de03bf97e78cffe7a5bbf))
- added room number to course popup ([#231](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/231)) ([9eaff24](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9eaff24cbb6d78d7f28521a07c32630a90a96f82)) * added room number to course popup ([#231](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/231)) ([9eaff24](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9eaff24cbb6d78d7f28521a07c32630a90a96f82))
- align timeBlock div ([4dc8957](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4dc8957c459d0ee57e40c67fa61194ace832327e)) * align timeBlock div ([4dc8957](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4dc8957c459d0ee57e40c67fa61194ace832327e))
- async course display size ([#181](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/181)) ([949bbb0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/949bbb0835bfb55a81f0800850aa084b4ed1bfc4)) * async course display size ([#181](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/181)) ([949bbb0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/949bbb0835bfb55a81f0800850aa084b4ed1bfc4))
- broken close bracket ([b34aacb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b34aacb06772af6f83d1f7bafe828ba43a10db85)) * broken close bracket ([b34aacb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b34aacb06772af6f83d1f7bafe828ba43a10db85))
- broken file ([92462cf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/92462cf0dffa222d75965885ee0e63181bce9890)) * broken file ([92462cf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/92462cf0dffa222d75965885ee0e63181bce9890))
- bugs ([2a01506](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2a0150600f26af5b7394f878e13c4d19611f3f64)) * bugs ([2a01506](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2a0150600f26af5b7394f878e13c4d19611f3f64))
- build ([60ab140](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/60ab140c556ec56eca78b1f4e280dfb6e9dbb538)) * build ([60ab140](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/60ab140c556ec56eca78b1f4e280dfb6e9dbb538))
- build errors and merge in Casey's branch (driodiwb) ([39947b3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/39947b3694f42f9d5ad2f21d044585aa3d12c407)) * build errors and merge in Casey's branch (driodiwb) ([39947b3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/39947b3694f42f9d5ad2f21d044585aa3d12c407))
- build errors and restructure Calendar page ([c6a48dd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c6a48dd3f6025fe531c18e12b8730683d63f67ed)) * build errors and restructure Calendar page ([c6a48dd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c6a48dd3f6025fe531c18e12b8730683d63f67ed))
- calendar course cell colors ([74be880](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/74be880f9d2dc340ba48416429711fb28915baa2)) * calendar course cell colors ([74be880](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/74be880f9d2dc340ba48416429711fb28915baa2))
- calendar storybook issue ([#125](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/125)) ([0c5bec8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c5bec8002022cb4702f3879f43fcd32b9fa6b5a)) * calendar storybook issue ([#125](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/125)) ([0c5bec8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0c5bec8002022cb4702f3879f43fcd32b9fa6b5a))
- Calendar View/Scaling Issues ([#144](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/144)) ([4c61ebd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4c61ebd3fc93240903f1224f9dd3057a23d30046)) * Calendar View/Scaling Issues ([#144](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/144)) ([4c61ebd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4c61ebd3fc93240903f1224f9dd3057a23d30046))
- CalendarCourseCell spacing ([13c69ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/13c69ef862f0214dfa6c9368fc3463519aa8f2f0)) * CalendarCourseCell spacing ([13c69ef](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/13c69ef862f0214dfa6c9368fc3463519aa8f2f0))
- change Chromatic action to build current branch, not base branch ([#100](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/100)) ([e73c9fe](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e73c9fe417169e73c395cde1aeb841eee8add579)) * change Chromatic action to build current branch, not base branch ([#100](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/100)) ([e73c9fe](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e73c9fe417169e73c395cde1aeb841eee8add579))
- change material icons to material symbols ([#71](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/71)) ([52e34cb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/52e34cb830ff1f12659703776bd3d9a24815ee00)) * change material icons to material symbols ([#71](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/71)) ([52e34cb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/52e34cb830ff1f12659703776bd3d9a24815ee00))
- chromatic build ([11303da](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/11303daebcc1e4de340463e6266082dc0920582d)) * chromatic build ([11303da](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/11303daebcc1e4de340463e6266082dc0920582d))
- chromatic builds on PRs ([#140](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/140)) ([78a6939](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/78a69399292767a1f8eac66e4c86cbcb8aad019d)) * chromatic builds on PRs ([#140](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/140)) ([78a6939](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/78a69399292767a1f8eac66e4c86cbcb8aad019d))
- chromatic storybook - CourseCatalogInjectedPopup ([#106](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/106)) ([ced2997](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ced29975b20a2a5beac51ea875627a2b1042e5c2)) * chromatic storybook - CourseCatalogInjectedPopup ([#106](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/106)) ([ced2997](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ced29975b20a2a5beac51ea875627a2b1042e5c2))
- clean up [#173](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/173) ([#174](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/174)) ([afa634f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/afa634f0853dc16cf313c129434d49bf132388d0)) * clean up [#173](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/173) ([#174](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/174)) ([afa634f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/afa634f0853dc16cf313c129434d49bf132388d0))
- cleanup imports ([#112](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/112)) ([b17c3fa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b17c3fae6d9a8fdb2f6de84dc28d00bc31e7bcc8)) * cleanup imports ([#112](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/112)) ([b17c3fa](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b17c3fae6d9a8fdb2f6de84dc28d00bc31e7bcc8))
- conflict row bug ([#130](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/130)) ([a8ea3bc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a8ea3bc683f88fc33191a8cacf649be83f6758f8)) * conflict row bug ([#130](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/130)) ([a8ea3bc](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a8ea3bc683f88fc33191a8cacf649be83f6758f8))
- ConflictsWithWarning ([1599e48](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1599e48d75d4877b3515c943120d83b59d084a55)) * ConflictsWithWarning ([1599e48](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1599e48d75d4877b3515c943120d83b59d084a55))
- correct parsing of noon ([#155](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/155)) ([91f62e1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/91f62e1943633eaef7dc8d437e6a7397456a9123)) * correct parsing of noon ([#155](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/155)) ([91f62e1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/91f62e1943633eaef7dc8d437e6a7397456a9123))
- db with proper insertion order ([8e79d6a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8e79d6a6a87210e0a30584c0c9ceb60bd3a33665)) * db with proper insertion order ([8e79d6a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8e79d6a6a87210e0a30584c0c9ceb60bd3a33665))
- delete storybook timestamp file ([f93a98e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f93a98e46ae76e9b1474c8143bfc3f5076e8b91f)) * delete storybook timestamp file ([f93a98e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f93a98e46ae76e9b1474c8143bfc3f5076e8b91f))
- dialog movement ([#227](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/227)) ([bc5d68c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bc5d68ce18f818c285ef7f5eda03f499365ee2e8)) * dialog movement ([#227](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/227)) ([bc5d68c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bc5d68ce18f818c285ef7f5eda03f499365ee2e8))
- disabled [object Object] hover message on dialog popups ([#284](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/284)) ([dcc1d81](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dcc1d81a74922ba27ad2a6859f978f3f20136178)) * disabled [object Object] hover message on dialog popups ([#284](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/284)) ([dcc1d81](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dcc1d81a74922ba27ad2a6859f978f3f20136178))
- divider usage in HeaderAndActions ([#113](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/113)) ([84e8320](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/84e8320e8fce5961877a5745e89419a722055ed5)) * divider usage in HeaderAndActions ([#113](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/113)) ([84e8320](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/84e8320e8fce5961877a5745e89419a722055ed5))
- doesn't autoload on pages that don't have pages to load ([#270](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/270)) ([88eeb62](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/88eeb620aec52d6e4172cc908843339412ade90b)) * doesn't autoload on pages that don't have pages to load ([#270](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/270)) ([88eeb62](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/88eeb620aec52d6e4172cc908843339412ade90b))
- don't crash on cultural diversity flag ([#196](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/196)) ([5b1e451](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5b1e4513e29203a54ed9f4913c227d6c45d2e67a)) * don't crash on cultural diversity flag ([#196](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/196)) ([5b1e451](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5b1e4513e29203a54ed9f4913c227d6c45d2e67a))
- eslint and remove React-beautiful-dnd ([6af805b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6af805ba3a7b04b7e5705d3d597b5ace686d61e0)) * eslint and remove React-beautiful-dnd ([6af805b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6af805ba3a7b04b7e5705d3d597b5ace686d61e0))
- extra space ([0f43796](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0f43796cd864acd012fc1242cbdf34844df62406)) * extra space ([0f43796](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0f43796cd864acd012fc1242cbdf34844df62406))
- Fix popup drag hitbox ([#216](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/216)) ([7a40008](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7a40008c1e3846f09ac4eeadc4a50f810ffc0d90)) * Fix popup drag hitbox ([#216](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/216)) ([7a40008](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7a40008c1e3846f09ac4eeadc4a50f810ffc0d90))
- fixed bug where activeSchedule doesn't update correctly ([#158](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/158)) ([a409090](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a409090b904686b76a5db52af980e81108b97082)) * fixed bug where activeSchedule doesn't update correctly ([#158](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/158)) ([a409090](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a409090b904686b76a5db52af980e81108b97082))
- fixed bug with course cells after 12 PM extending past midnight ([#122](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/122)) ([f22a3cd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f22a3cd7c0df138ca6ecd4b4a4efaa7ce845c3dd)) * fixed bug with course cells after 12 PM extending past midnight ([#122](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/122)) ([f22a3cd](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/f22a3cd7c0df138ca6ecd4b4a4efaa7ce845c3dd))
- fixed issues involving course meeting objects not being recognized as course meeting objects ([#132](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/132)) ([3406e9a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3406e9a0e2644218fc06cbd0b05046df5339264c)) * fixed issues involving course meeting objects not being recognized as course meeting objects ([#132](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/132)) ([3406e9a](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3406e9a0e2644218fc06cbd0b05046df5339264c))
- Fixed typescript error ([#161](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/161)) ([df7a7c6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/df7a7c65d695cb5c5a825ac9f5ecc48438735b65)) * Fixed typescript error ([#161](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/161)) ([df7a7c6](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/df7a7c65d695cb5c5a825ac9f5ecc48438735b65))
- grade dist when no instructor ([#269](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/269)) ([6a363ae](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6a363aeb5ccb1c11e15db317b34c4f04a3c9aafc)) * grade dist when no instructor ([#269](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/269)) ([6a363ae](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6a363aeb5ccb1c11e15db317b34c4f04a3c9aafc))
- grid JSX.Element generation ([b691bf3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b691bf3231d5002a631687f26c7409e311237662)) * grid JSX.Element generation ([b691bf3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b691bf3231d5002a631687f26c7409e311237662))
- icon library resolution ([#74](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/74)) ([bb3b313](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bb3b313fd272bba12f99270c912e046df5358fed)) * icon library resolution ([#74](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/74)) ([bb3b313](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bb3b313fd272bba12f99270c912e046df5358fed))
- idk why that comment was there ([#177](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/177)) ([c5fc621](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c5fc6219e1540e1fb889d8bedc7296190103a56b)) * idk why that comment was there ([#177](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/177)) ([c5fc621](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c5fc6219e1540e1fb889d8bedc7296190103a56b))
- import error ([152bc45](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/152bc4577685605ae95f39d9e670b5449e32e0e9)) * import error ([152bc45](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/152bc4577685605ae95f39d9e670b5449e32e0e9))
- improper list data propagation ([#240](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/240)) ([149fda3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/149fda3b721dcc3d8ffa6c2398c28e39dcb62aaa)) * improper list data propagation ([#240](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/240)) ([149fda3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/149fda3b721dcc3d8ffa6c2398c28e39dcb62aaa))
- improve dialog handling and error management in list items ([#257](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/257)) ([1942508](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1942508d8d11f51b62806894ae13162b6404753b)) * improve dialog handling and error management in list items ([#257](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/257)) ([1942508](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/1942508d8d11f51b62806894ae13162b6404753b))
- injection not working from som/elie commit ([#145](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/145)) ([591687e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/591687eee8731b3649a5f8c1357a416eb2992a93)) * injection not working from som/elie commit ([#145](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/145)) ([591687e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/591687eee8731b3649a5f8c1357a416eb2992a93))
- list component fixed ([#162](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/162)) ([5714ed1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5714ed16d72c5442f58366ac51f40cc32ea406ab)) * list component fixed ([#162](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/162)) ([5714ed1](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5714ed16d72c5442f58366ac51f40cc32ea406ab))
- made list draggable only by handle ([cbb190b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cbb190bf4b3ad694c87b650489e1fca5aa6b7826)) * made list draggable only by handle ([cbb190b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cbb190bf4b3ad694c87b650489e1fca5aa6b7826))
- margins on list component ([cc71389](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cc7138949cf77d1bcf1520633d669e939540575e)) * margins on list component ([cc71389](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/cc7138949cf77d1bcf1520633d669e939540575e))
- non-determinstic options page generation ([#137](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/137)) ([d700110](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d70011016a45f5de62b06839a31c634637024f4a)) * non-determinstic options page generation ([#137](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/137)) ([d700110](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d70011016a45f5de62b06839a31c634637024f4a))
- non-virtual dnd ([837fddf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/837fddf8048350b0b25a58bbd16c1957fbad6edb)) * non-virtual dnd ([837fddf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/837fddf8048350b0b25a58bbd16c1957fbad6edb))
- old icon removed in .tsx ([4d387e8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4d387e8063314c7c6d7452b746728e2cf85a1787)) * old icon removed in .tsx ([4d387e8](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4d387e8063314c7c6d7452b746728e2cf85a1787))
- only show button hover effects when not disabled ([8e3aa7e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8e3aa7ef3380836fd36a12698b1f6982e110c0f7)) * only show button hover effects when not disabled ([8e3aa7e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/8e3aa7ef3380836fd36a12698b1f6982e110c0f7))
- openTabFromContentScript TS issue ([3a48859](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3a48859dddc0e85649ff6a949e9afd22c962825d)) * openTabFromContentScript TS issue ([3a48859](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3a48859dddc0e85649ff6a949e9afd22c962825d))
- options page ([#131](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/131)) ([dc100b5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dc100b5d3ac1db5f1dc011ea2536c286f56fa55b)) * options page ([#131](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/131)) ([dc100b5](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/dc100b5d3ac1db5f1dc011ea2536c286f56fa55b))
- reactivity ([#188](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/188)) ([4f4f34e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4f4f34e281e8aabcdbf8b06652d05bca3554b11f)) * reactivity ([#188](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/188)) ([4f4f34e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/4f4f34e281e8aabcdbf8b06652d05bca3554b11f))
- README.md ([a30fecf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a30fecf8ec76ecae03be9bb4d813803b9ffdb490)) * README.md ([a30fecf](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/a30fecf8ec76ecae03be9bb4d813803b9ffdb490))
- README.md ([b27b21b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b27b21bbfcc8fbdc130c3fa85776479451745b7b)) * README.md ([b27b21b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b27b21bbfcc8fbdc130c3fa85776479451745b7b))
- refactor AST parsing for custom ESLint rule ([62f0851](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/62f0851406bf82d3d0481fed40462bdd30ffcf1b)) * refactor AST parsing for custom ESLint rule ([62f0851](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/62f0851406bf82d3d0481fed40462bdd30ffcf1b))
- remote react-window fully (from List component) ([#114](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/114)) ([5f1c023](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5f1c0231e483bc571ef944bbc0b950ab20d31028)) * remote react-window fully (from List component) ([#114](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/114)) ([5f1c023](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/5f1c0231e483bc571ef944bbc0b950ab20d31028))
- remove course name from the syllabi lookup ([#200](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/200)) ([bcb5a8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bcb5a8c469c4b5c1909880ab6789d67d04487ed2)) * remove course name from the syllabi lookup ([#200](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/200)) ([bcb5a8c](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/bcb5a8c469c4b5c1909880ab6789d67d04487ed2))
- remove extra spacing ([#121](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/121)) ([6ba8b68](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6ba8b68654dc182bd2a084f93b0f4f7d5c132862)) * remove extra spacing ([#121](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/121)) ([6ba8b68](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/6ba8b68654dc182bd2a084f93b0f4f7d5c132862))
- remove white space after duplicate schedule regex matching ([#286](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/286)) ([d73615e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d73615e28129ee7d78604c6b295ec572b11be46e)) * remove white space after duplicate schedule regex matching ([#286](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/286)) ([d73615e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/d73615e28129ee7d78604c6b295ec572b11be46e))
- rename to course block and fix line height for styling ([b602b0b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b602b0b895416a26214e934f9650a8ec0a10711e)) * rename to course block and fix line height for styling ([b602b0b](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b602b0b895416a26214e934f9650a8ec0a10711e))
- revert "chore: add default story" ([aef8c3d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aef8c3d9873c6df79f6a54ab4c669ee1849b5ea5)) * revert "chore: add default story" ([aef8c3d](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/aef8c3d9873c6df79f6a54ab4c669ee1849b5ea5))
- revert "rename to course block and fix line height for styling" ([0273a23](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0273a239139c0f3c0ad773ed8ab1cd4ad8d22fa3)) * revert "rename to course block and fix line height for styling" ([0273a23](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/0273a239139c0f3c0ad773ed8ab1cd4ad8d22fa3))
- revert CalendarGrid and CalendarGridCell back to SCSS from Tailwind ([56306ab](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/56306ab9440baf5ca1158f95d788de7ba42d73d8)) * revert CalendarGrid and CalendarGridCell back to SCSS from Tailwind ([56306ab](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/56306ab9440baf5ca1158f95d788de7ba42d73d8))
- revert last commit ([27d945f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/27d945f57c76a1c2f31fee9f98c324fab6183bb6)) * revert last commit ([27d945f](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/27d945f57c76a1c2f31fee9f98c324fab6183bb6))
- Schedule Switching Bugs ([#138](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/138)) ([c51e688](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c51e6881d186e8bef056e483e2bca95585d5eac6)) * Schedule Switching Bugs ([#138](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/138)) ([c51e688](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/c51e6881d186e8bef056e483e2bca95585d5eac6))
- support classes with no location ([#242](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/242)) ([3ff06e0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3ff06e043b112bc232c9c173e72b2ea99609cf7a)) * support classes with no location ([#242](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/242)) ([3ff06e0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/3ff06e043b112bc232c9c173e72b2ea99609cf7a))
- theme colors ([2f537b4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2f537b4f3e3946241f2e287d9ae075e5a2aa7087)) * theme colors ([2f537b4](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/2f537b4f3e3946241f2e287d9ae075e5a2aa7087))
- type issues by using correct import ([#111](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/111)) ([19fe070](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/19fe070491be9e2d40f12918561f6f6ac5921237)) * type issues by using correct import ([#111](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/111)) ([19fe070](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/19fe070491be9e2d40f12918561f6f6ac5921237))
- **ui:** unhid settings button ([#288](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/288)) ([db1eac3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/db1eac33a2786a3db87f0e6b3679233a85ab923f)) * **ui:** unhid settings button ([#288](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/288)) ([db1eac3](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/db1eac33a2786a3db87f0e6b3679233a85ab923f))
- undefined color case ([9aa78a0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9aa78a02a5d4f68daa062e4892875cf5f568306c)) * undefined color case ([9aa78a0](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/9aa78a02a5d4f68daa062e4892875cf5f568306c))
- unocss theme color namings ([79d7832](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/79d7832d0987b8a7c9650b984f72ffd702682423)) * unocss theme color namings ([79d7832](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/79d7832d0987b8a7c9650b984f72ffd702682423))
- update alignment ([7eb3113](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7eb3113adaa0917c0275576c3366c387bfe77440)) * update alignment ([7eb3113](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/7eb3113adaa0917c0275576c3366c387bfe77440))
- update daysOfWeek with new DAY_MAP keys ([ecdaadb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ecdaadb83eb21b144d07d573613fd8971f0a5ce2)) * update daysOfWeek with new DAY_MAP keys ([ecdaadb](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ecdaadb83eb21b144d07d573613fd8971f0a5ce2))
- visual overflow bug when editing schedule name ([#251](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/251)) ([e8d2c2e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e8d2c2e1429072fcc1173ee770f06b07e9ddda20)) * visual overflow bug when editing schedule name ([#251](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/251)) ([e8d2c2e](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/e8d2c2e1429072fcc1173ee770f06b07e9ddda20))
- vitest path alias bug ([ee37897](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ee37897df4f65cd2d285e2ad628be43aebb21ea1)) * vitest path alias bug ([ee37897](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/ee37897df4f65cd2d285e2ad628be43aebb21ea1))
### Reverts ### Reverts
- Revert "individual bug fix" ([b4e8c75](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b4e8c7589e53f1064d70703459cc6d66fae1b04c)) * Revert "individual bug fix" ([b4e8c75](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/b4e8c7589e53f1064d70703459cc6d66fae1b04c))
- color palette for calendar ([#118](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/118)) ([51bbd65](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/51bbd6590bf284ce54644b014466c8b2c73b8925)) * color palette for calendar ([#118](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues/118)) ([51bbd65](https://github.com/Longhorn-Developers/UT-Registration-Plus/commit/51bbd6590bf284ce54644b014466c8b2c73b8925))

32
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,32 @@
# UT Registration Plus Code of Conduct
Like the technical community as a whole, the UT Registration Plus team and community is made up of a mixture of professionals and volunteers from all over the world, working on every aspect of the mission - including mentorship, teaching, and connecting people.
Diversity is one of our huge strengths, but it can also lead to communication issues and unhappiness. To that end, we have a few ground rules that we ask people to adhere to. This code applies equally to founders, mentors and those seeking help and guidance.
This isnt an exhaustive list of things that you cant do. Rather, take it in the spirit in which its intended - a guide to make it easier to enrich all of us and the technical communities in which we participate.
This code of conduct applies to all spaces managed by the UT Registration Plus project or Longhorn Developers. This includes IRC, the mailing lists, the issue tracker, DSF events, and any other forums created by the project team which the community uses for communication. In addition, violations of this code outside these spaces may affect a person's ability to participate within them.
If you believe someone is violating the code of conduct, we ask that you report it by emailing [contact@longhorns.dev](mailto:contact@longhorns.dev). For more details please see our
- **Be friendly and patient.**
- **Be welcoming.** We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.
- **Be considerate.** Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone else's primary language.
- **Be respectful.** Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. Its important to remember that a community where people feel uncomfortable or threatened is not a productive one. Members of the UT Registration Plus community should be respectful when dealing with other members as well as with people outside the UT Registration Plus community.
- **Be careful in the words that you choose.** We are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior aren't acceptable. This includes, but is not limited to:
- Violent threats or language directed against another person.
- Discriminatory jokes and language.
- Posting sexually explicit or violent material.
- Posting (or threatening to post) other people's personally identifying information ("doxing").
- Personal insults, especially those using racist or sexist terms.
- Unwelcome sexual attention.
- Advocating for, or encouraging, any of the above behavior.
- Repeated harassment of others. In general, if someone asks you to stop, then stop.
- **When we disagree, try to understand why.** Disagreements, both social and technical, happen all the time and UT Registration Plus is no exception. It is important that we resolve disagreements and differing views constructively. Remember that were different. The strength of UT Registration Plus comes from its varied community, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesnt mean that theyre wrong. Dont forget that it is human to err and blaming each other doesnt get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes.
Original text courtesy of the [Speak Up! project](http://web.archive.org/web/20141109123859/http://speakup.io/coc.html).
## Questions?
If you have questions, please see . If that doesn't answer your questions, feel free to [contact us](mailto:contact@longhorns.dev).

View File

@@ -2,8 +2,8 @@
## Prerequisites ## Prerequisites
- Docker installed on your machine - Docker installed on your machine
- Git (to clone the repository) - Git (to clone the repository)
## Getting Started ## Getting Started
@@ -70,9 +70,9 @@ docker run -it --rm -v $(pwd)/dist:/extension/dist -p 5173:5173 -e BUILD_MODE=de
## Accessing the Built Extension ## Accessing the Built Extension
- For build mode, the extension files will be in the `dist` directory on your host machine. - For build mode, the extension files will be in the `dist` directory on your host machine.
- For zip mode, the zipped extension will be in the `package` directory on your host machine. - For zip mode, the zipped extension will be in the `package` directory on your host machine.
- For dev mode, the extension will be continuously built in the `dist` directory, and you can load it as an unpacked extension in Chrome. - For dev mode, the extension will be continuously built in the `dist` directory, and you can load it as an unpacked extension in Chrome.
## Docker Development Workflow ## Docker Development Workflow
@@ -85,5 +85,5 @@ When working on the extension:
## Troubleshooting ## Troubleshooting
- If you encounter permission issues with the output directories, ensure that the directories exist on your host machine and have the correct permissions. - If you encounter permission issues with the output directories, ensure that the directories exist on your host machine and have the correct permissions.
- For any other issues, please check the Docker logs or open an issue in the GitHub repository. - For any other issues, please check the Docker logs or open an issue in the GitHub repository.

116
README.md
View File

@@ -14,36 +14,37 @@
## Features ## Features
- **Quick Access to Class Info**: For each class in the UT Course Schedule, UTRP provides a "breakdown" popup with direct links to RateMyProfessor, Course Evaluation Surveys (CES), and past syllabi. - **Quick Access to Class Info**: For each class in the UT Course Schedule, UTRP provides a "breakdown" popup with direct links to RateMyProfessor, Course Evaluation Surveys (CES), and past syllabi.
- **Prerequisite & Restriction Highlights**: Displays course descriptions with highlighted details on prerequisites, restrictions, and other important info. - **Prerequisite & Restriction Highlights**: Displays course descriptions with highlighted details on prerequisites, restrictions, and other important info.
- **Grade Distribution Graphs**: View an aggregate and semester-specific graph of grade distributions for each course. - **Grade Distribution Graphs**: View an aggregate and semester-specific graph of grade distributions for each course.
- **Saved Courses List**: Easily add courses to a list and view them in the extension popup. Copy unique numbers with a single click. - **Saved Courses List**: Easily add courses to a list and view them in the extension popup. Copy unique numbers with a single click.
- **Conflict Detection**: Automatically highlights and strikes out courses that conflict with your saved courses in the UT Course Catalog. - **Conflict Detection**: Automatically highlights and strikes out courses that conflict with your saved courses in the UT Course Catalog.
- **Weekly Schedule View**: Displays your saved courses in a weekly schedule format for easier planning. - **Weekly Schedule View**: Displays your saved courses in a weekly schedule format for easier planning.
- **Multiple Schedule Support**: Create multiple schedules to plan for different registration scenarios. - **Multiple Schedule Support**: Create multiple schedules to plan for different registration scenarios.
- **And much more!** - **And much more!**
## Toolchain ## Toolchain
- React v20.9.0 (LTS) - React v20.9.0 (LTS)
- TypeScript - TypeScript v5.x
- Vite 5 - Vite v5.x
- UnoCSS - pnpm v10.x
- ESLint - UnoCSS
- Prettier - ESLint
- Storybook - Prettier
- Figma - Storybook
- Semantic-Release - Figma
- Custom Messaging & Storage Wrappers - Semantic-Release
- Custom Messaging & Storage Wrappers
## VSCode Extensions ## VSCode Extensions
We recommend using the following VSCode extensions to improve your development experience: We recommend using the following VSCode extensions to improve your development experience:
- **[ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)**: For identifying and fixing linting issues. - **[ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint)**: For identifying and fixing linting issues.
- **[Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)**: For automatic code formatting. - **[Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode)**: For automatic code formatting.
- **[Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**: For Tailwind CSS class autocomplete and IntelliSense. - **[Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss)**: For Tailwind CSS class autocomplete and IntelliSense.
- **[UnoCSS](https://marketplace.visualstudio.com/items?itemName=antfu.unocss)**: For better support with UnoCSS utilities. - **[UnoCSS](https://marketplace.visualstudio.com/items?itemName=antfu.unocss)**: For better support with UnoCSS utilities.
## Contributing ## Contributing
@@ -78,7 +79,7 @@ Once set up, the extension can be built to the `dist/` directory using the follo
### Development Builds ### Development Builds
- Run the development server: - Run the development server:
```bash ```bash
pnpm dev pnpm dev
``` ```
@@ -91,7 +92,7 @@ Once set up, the extension can be built to the `dist/` directory using the follo
### Production Builds ### Production Builds
- To generate production builds: - To generate production builds:
```bash ```bash
pnpm build pnpm build
``` ```
@@ -120,10 +121,10 @@ To load the extension manually in Chrome:
If you encounter bugs or issues, please report them in the [Issues](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues) section, including: If you encounter bugs or issues, please report them in the [Issues](https://github.com/Longhorn-Developers/UT-Registration-Plus/issues) section, including:
- A clear, descriptive title - A clear, descriptive title
- Steps to reproduce the issue - Steps to reproduce the issue
- Expected behavior - Expected behavior
- Screenshots or logs (if applicable) - Screenshots or logs (if applicable)
We aim to address issues promptly. We aim to address issues promptly.
@@ -141,14 +142,14 @@ Follow this structure for commit messages:
Where: Where:
- **type**: One of the following: - **type**: One of the following:
- `feat`: A new feature - `feat`: A new feature
- `fix`: A bug fix - `fix`: A bug fix
- `docs`: Documentation updates - `docs`: Documentation updates
- `style`: Code formatting changes (whitespace, semicolons, etc.) - `style`: Code formatting changes (whitespace, semicolons, etc.)
- `refactor`: Code restructuring (without adding features or fixing bugs) - `refactor`: Code restructuring (without adding features or fixing bugs)
- `test`: Adding or modifying tests - `test`: Adding or modifying tests
- `chore`: Maintenance tasks or build process changes - `chore`: Maintenance tasks or build process changes
Example: Example:
@@ -167,9 +168,9 @@ Branch names should follow the format:
Examples: Examples:
- `feat/user-login` - `feat/user-login`
- `fix/navbar-layout` - `fix/navbar-layout`
- `docs/update-readme` - `docs/update-readme`
## License ## License
@@ -183,27 +184,28 @@ We maintain a strict code of conduct. By contributing, you agree to adhere to th
Special thanks to the developers and contributors behind these amazing tools and libraries: Special thanks to the developers and contributors behind these amazing tools and libraries:
- React v20.9.0 (LTS) - React v20.9.0 (LTS)
- TypeScript - TypeScript v5.x
- Vite 5 - Vite v5.x
- UnoCSS - pnpm v10.x
- ESLint - UnoCSS
- Prettier - ESLint
- Storybook - Prettier
- Figma - Storybook
- Semantic-Release - Figma
- [chrome-extension-toolkit](https://github.com/sghsri/chrome-extension-toolkit) - Semantic-Release
- [UT_Grade_Parser](https://github.com/doprz/UT_Grade_Parser) - [chrome-extension-toolkit](https://github.com/sghsri/chrome-extension-toolkit)
- [eslint-plugin-import-essentials](https://github.com/doprz/eslint-plugin-import-essentials) - [UT_Grade_Parser](https://github.com/doprz/UT_Grade_Parser)
- [UT Registration Plus v1.2.2.7](https://github.com/Longhorn-Developers/UT-Registration-Plus/tree/legacy) by @sghsri - [eslint-plugin-import-essentials](https://github.com/doprz/eslint-plugin-import-essentials)
- [UT Registration Planner](https://github.com/doprz/UT-Registration-Planner) by @doprz - [UT Registration Plus v1.2.2.7](https://github.com/Longhorn-Developers/UT-Registration-Plus/tree/legacy) by @sghsri
- [Figma Designs](https://www.figma.com/design/8tsCay2FRqctrdcZ3r9Ahw/UTRP) by @IsaDavRod - [UT Registration Planner](https://github.com/doprz/UT-Registration-Planner) by @doprz
- [Longhorn Developers](https://github.com/Longhorn-Developers) - established in 2024 - [Figma Designs](https://www.figma.com/design/8tsCay2FRqctrdcZ3r9Ahw/UTRP) by @IsaDavRod
- The UTRP devs, beta testers, and all supporters of the project! - [Longhorn Developers](https://github.com/Longhorn-Developers) - established in 2024
- The UTRP devs, beta testers, and all supporters of the project!
## Activity ## Activity
![UT-Registration-Plus Activity](https://repobeats.axiom.co/api/embed/47930fa3916ac1b475cd63a05948c449eb5ad502.svg "UT-Registration-Plus Repobeats analytics image") ![UT-Registration-Plus Activity](https://repobeats.axiom.co/api/embed/47930fa3916ac1b475cd63a05948c449eb5ad502.svg 'UT-Registration-Plus Repobeats analytics image')
## Star History ## Star History

View File

@@ -1,5 +1,5 @@
{ {
"onlyChanged": true, "onlyChanged": true,
"projectId": "Project:65c5172964f36dcf207985bf", "projectId": "Project:65c5172964f36dcf207985bf",
"zip": true "zip": true
} }

10
default.nix Normal file
View File

@@ -0,0 +1,10 @@
(import (
let
rev = "v1.1.0";
sha256 = "sha256:19d2z6xsvpxm184m41qrpi1bplilwipgnzv9jy17fgw421785q1m";
in
fetchTarball {
inherit sha256;
url = "https://github.com/NixOS/flake-compat/archive/${rev}.tar.gz";
}
) { src = ./.; }).defaultNix

View File

@@ -24,7 +24,7 @@ else
fi fi
# Validate the mode # Validate the mode
if [[ ! " ${SUPPORTED_MODES[*]} " =~ " ${mode} " ]]; then if [[ ! " ${SUPPORTED_MODES[*]} " =~ ${mode} ]]; then
echo "Error: Invalid mode '${mode}'" >&2 echo "Error: Invalid mode '${mode}'" >&2
usage usage
fi fi

96
flake.lock generated Normal file
View File

@@ -0,0 +1,96 @@
{
"nodes": {
"flake-parts": {
"inputs": {
"nixpkgs-lib": "nixpkgs-lib"
},
"locked": {
"lastModified": 1767609335,
"narHash": "sha256-feveD98mQpptwrAEggBQKJTYbvwwglSbOv53uCfH9PY=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "250481aafeb741edfe23d29195671c19b36b6dca",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1767640445,
"narHash": "sha256-UWYqmD7JFBEDBHWYcqE6s6c77pWdcU/i+bwD6XxMb8A=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "9f0c42f8bc7151b8e7e5840fb3bd454ad850d8c5",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs-lib": {
"locked": {
"lastModified": 1765674936,
"narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=",
"owner": "nix-community",
"repo": "nixpkgs.lib",
"rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nixpkgs.lib",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1761236834,
"narHash": "sha256-+pthv6hrL5VLW2UqPdISGuLiUZ6SnAXdd2DdUE+fV2Q=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "d5faa84122bc0a1fd5d378492efce4e289f8eac1",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-parts": "flake-parts",
"nixpkgs": "nixpkgs",
"treefmt-nix": "treefmt-nix"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": "nixpkgs_2"
},
"locked": {
"lastModified": 1767468822,
"narHash": "sha256-MpffQxHxmjVKMiQd0Tg2IM/bSjjdQAM+NDcX6yxj7rE=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "d56486eb9493ad9c4777c65932618e9c2d0468fc",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

33
flake.nix Normal file
View File

@@ -0,0 +1,33 @@
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-parts.url = "github:hercules-ci/flake-parts";
treefmt-nix.url = "github:numtide/treefmt-nix";
};
outputs =
inputs@{ flake-parts, ... }:
flake-parts.lib.mkFlake { inherit inputs; } {
systems = inputs.nixpkgs.lib.systems.flakeExposed;
imports = [
./nix/packages.nix
./nix/devShells.nix
./nix/treefmt.nix
];
perSystem =
{ system, ... }:
{
_module.args.pkgs = import inputs.nixpkgs {
inherit system;
overlays = [
(final: prev: {
nodejs = prev.nodejs_20; # v20.19.5
})
];
config = { };
};
};
};
}

View File

@@ -35,9 +35,13 @@ function removeExtraDatabaseDir(cb) {
// Instrument with Sentry // Instrument with Sentry
// Make sure sentry is configured https://docs.sentry.io/platforms/javascript/sourcemaps/uploading/typescript/#2-configure-sentry-cli // Make sure sentry is configured https://docs.sentry.io/platforms/javascript/sourcemaps/uploading/typescript/#2-configure-sentry-cli
async function instrumentWithSentry(cb) { async function instrumentWithSentry(cb) {
await exec(`sentry-cli sourcemaps inject ${DIST_DIR}`); if (process.env.SENTRY_ENV && process.env.SENTRY_ENV !== 'development') {
await exec(`sentry-cli sourcemaps upload ${DIST_DIR}`); await exec(`sentry-cli sourcemaps inject ${DIST_DIR}`);
log('Sentry instrumentation completed.'); await exec(`sentry-cli sourcemaps upload ${DIST_DIR}`);
log('Sentry instrumentation completed.');
} else {
logWarn('Skipping uploading/creating Sentry source maps. (development build)');
}
cb(); cb();
} }

30
nix/devShells.nix Normal file
View File

@@ -0,0 +1,30 @@
{
perSystem =
{
pkgs,
...
}:
let
commonPackages = with pkgs; [
nodejs # Defined in overlay
pnpm_10 # v10.18.2
];
additionalPackages = with pkgs; [
bun
nodePackages.conventional-changelog-cli
sentry-cli
];
in
{
devShells.default = pkgs.mkShell {
name = "utrp-dev";
packages = commonPackages;
};
devShells.full = pkgs.mkShell {
name = "utrp-dev-full";
packages = commonPackages ++ additionalPackages;
};
};
}

51
nix/package.nix Normal file
View File

@@ -0,0 +1,51 @@
{
stdenv,
lib,
nodejs,
pnpm_10,
git,
version ? "dev",
gitRev ? "unknown",
gitBranch ? "unknown",
buildScript ? "build",
}:
stdenv.mkDerivation (finalAttrs: {
inherit version;
pname = "ut-registration-plus";
src = ../.;
nativeBuildInputs = [
nodejs
pnpm_10.configHook
git
];
pnpmDeps = pnpm_10.fetchDeps {
inherit (finalAttrs) pname version src;
fetcherVersion = 2;
hash = "sha256-UqHymJWvlTV4glra/6DkxuCxbG5dpPkFcnvq3vuxsJ8=";
};
# Pass git info to the build
VITE_GIT_COMMIT = gitRev;
VITE_GIT_BRANCH = gitBranch;
buildPhase = ''
pnpm run ${buildScript}
'';
installPhase = ''
mkdir -p $out
cp -r dist/* $out/
'';
meta = {
description = "UT Registration Plus";
homepage = "https://github.com/Longhorn-Developers/UT-Registration-Plus";
license = lib.licenses.mit;
maintainers = lib.maintainers.doprz;
platforms = lib.platforms.unix;
};
})

40
nix/packages.nix Normal file
View File

@@ -0,0 +1,40 @@
{ inputs, ... }:
{
perSystem =
{ pkgs, ... }:
let
packageJson = builtins.fromJSON (builtins.readFile ../package.json);
gitRev = inputs.self.shortRev or inputs.self.dirtyShortRev or "dev";
gitBranch = if inputs.self ? ref then inputs.self.ref else "unknown";
baseVersion = packageJson.version;
commonArgs = {
inherit gitRev gitBranch;
};
# Prod variant
ut-registration-plus = pkgs.callPackage ./package.nix (
commonArgs
// {
version = "${baseVersion}+git.${gitRev}";
buildScript = "build";
}
);
# Dev variant
ut-registration-plus-dev = pkgs.callPackage ./package.nix (
commonArgs
// {
version = "${baseVersion}-dev+git.${gitRev}";
buildScript = "build:dev";
}
);
in
{
packages = {
inherit ut-registration-plus ut-registration-plus-dev;
default = ut-registration-plus;
dev = ut-registration-plus-dev;
};
};
}

63
nix/treefmt.nix Normal file
View File

@@ -0,0 +1,63 @@
{ inputs, ... }:
{
imports = [
inputs.treefmt-nix.flakeModule
];
perSystem =
{ pkgs, ... }:
{
treefmt = {
projectRootFile = "flake.nix";
programs.nixfmt.enable = pkgs.lib.meta.availableOn pkgs.stdenv.buildPlatform pkgs.nixfmt-rfc-style.compiler;
programs.nixfmt.package = pkgs.nixfmt-rfc-style;
# NOTE: Make sure the prettier version in package.json and the one used by treefmt are the same for consistent results
programs.prettier.enable = true;
programs.shellcheck.enable = true;
programs.yamlfmt.enable = true;
programs.dockerfmt.enable = true;
settings.formatter.prettier.excludes = [ "pnpm-lock.yaml" ];
settings.formatter.shellcheck.excludes = [ ".envrc" ];
settings.formatter.yamlfmt.excludes = [ "pnpm-lock.yaml" ];
};
checks = {
prettier-version-match =
pkgs.runCommand "check-prettier-version"
{
buildInputs = [ pkgs.jq ];
}
''
# Extract prettier version from package.json
packageJsonVersion=$(jq -r '.devDependencies.prettier // empty' ${../package.json})
if [ -z "$packageJsonVersion" ]; then
echo "Error: prettier not found in package.json devDependencies"
exit 1
fi
# Remove any semver prefix characters (^, ~, etc...)
packageJsonVersion=$(echo "$packageJsonVersion" | sed 's/^[\^~>=<]*//')
# Get prettier version from nixpkgs
nixVersion="${pkgs.nodePackages.prettier.version}"
if [ "$packageJsonVersion" != "$nixVersion" ]; then
echo ""
echo "ERROR: Prettier version mismatch!"
echo " package.json: $packageJsonVersion"
echo " nixpkgs: $nixVersion"
echo ""
echo "Please update one of the following:"
echo " - Update prettier in package.json to match nixpkgs: $nixVersion"
echo " - Override prettier in your flake to match package.json"
exit 1
fi
touch $out
'';
};
};
}

View File

@@ -1,7 +1,7 @@
{ {
"name": "ut-registration-plus", "name": "ut-registration-plus",
"displayName": "UT Registration Plus", "displayName": "UT Registration Plus",
"version": "2.2.0", "version": "2.3.0",
"description": "UT Registration Plus is a Chrome extension that allows students to easily register for classes.", "description": "UT Registration Plus is a Chrome extension that allows students to easily register for classes.",
"private": true, "private": true,
"homepage": "https://github.com/Longhorn-Developers/UT-Registration-Plus", "homepage": "https://github.com/Longhorn-Developers/UT-Registration-Plus",
@@ -9,8 +9,10 @@
"scripts": { "scripts": {
"dev": "vite", "dev": "vite",
"build": "tsc && vite build", "build": "tsc && vite build",
"build:dev": "tsc && NODE_ENV='development' vite build --mode development",
"build:watch": "NODE_ENV='development' vite build --mode development -w", "build:watch": "NODE_ENV='development' vite build --mode development -w",
"zip": "PROD=true pnpm build && pnpm gulp zipProdBuild", "zip": "pnpm build && pnpm gulp zipProdBuild",
"zip:to-publish": "SENTRY_ENV='production' pnpm zip",
"prettier": "prettier src --check", "prettier": "prettier src --check",
"prettier:fix": "prettier src --write", "prettier:fix": "prettier src --write",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives", "lint": "eslint src --ext ts,tsx --report-unused-disable-directives",
@@ -37,6 +39,9 @@
"@phosphor-icons/react": "^2.1.7", "@phosphor-icons/react": "^2.1.7",
"@sentry/react": "^8.55.0", "@sentry/react": "^8.55.0",
"@tanstack/react-query": "^5.69.0", "@tanstack/react-query": "^5.69.0",
"@tsparticles/engine": "^3.9.1",
"@tsparticles/react": "^3.0.0",
"@tsparticles/slim": "^3.9.1",
"@unocss/vite": "^0.63.6", "@unocss/vite": "^0.63.6",
"@vitejs/plugin-react": "^4.3.4", "@vitejs/plugin-react": "^4.3.4",
"chrome-extension-toolkit": "^0.0.54", "chrome-extension-toolkit": "^0.0.54",
@@ -134,15 +139,15 @@
"gulp-zip": "^6.1.0", "gulp-zip": "^6.1.0",
"path": "^0.12.7", "path": "^0.12.7",
"postcss": "^8.5.3", "postcss": "^8.5.3",
"prettier": "^3.5.2", "prettier": "3.6.2",
"react-dev-utils": "^12.0.1", "react-dev-utils": "^12.0.1",
"semantic-release": "^24.2.3", "semantic-release": "^24.2.3",
"storybook": "^8.6.0", "storybook": "^8.6.0",
"typescript": "^5.7.3", "typescript": "^5.7.3",
"unocss": "^0.63.6", "unocss": "^0.63.6",
"unocss-preset-primitives": "0.0.2-beta.1", "unocss-preset-primitives": "0.0.2-beta.2",
"unplugin-icons": "^0.19.3", "unplugin-icons": "^0.19.3",
"vite": "^5.4.14", "vite": "^5.4.20",
"vite-plugin-inspect": "^0.8.9", "vite-plugin-inspect": "^0.8.9",
"vitest": "^2.1.9" "vitest": "^2.1.9"
}, },
@@ -157,10 +162,13 @@
}, },
"overrides": { "overrides": {
"es-module-lexer": "^1.5.4" "es-module-lexer": "^1.5.4"
} },
"onlyBuiltDependencies": [
"@tsparticles/engine"
]
}, },
"volta": { "volta": {
"node": "20.9.0", "node": "20.19.4",
"pnpm": "10.6.5" "pnpm": "10.14.0"
} }
} }

1442
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

10
shell.nix Normal file
View File

@@ -0,0 +1,10 @@
(import (
let
rev = "v1.1.0";
sha256 = "sha256:19d2z6xsvpxm184m41qrpi1bplilwipgnzv9jy17fgw421785q1m";
in
fetchTarball {
inherit sha256;
url = "https://github.com/NixOS/flake-compat/archive/${rev}.tar.gz";
}
) { src = ./.; }).shellNix

BIN
src/assets/LD-icon-new.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

View File

@@ -8,15 +8,27 @@ const splashText: string[] = [
'The squirrels, they have mastered begging for food better than students. Impressive... but worrying.', 'The squirrels, they have mastered begging for food better than students. Impressive... but worrying.',
"Do you study often? Ha! What am I saying? Of course you don't.", "Do you study often? Ha! What am I saying? Of course you don't.",
"Hey, you, you're finally awake. You were trying to skip class right?", "Hey, you, you're finally awake. You were trying to skip class right?",
'Mmm... Brutalist architecture...',
'The course syllabus: more than meets the eye',
'Pain is temporary, GPA is forever.',
"You've Yee'd Your Last Haw.",
'lol everything is already waitlisted.',
'Could be worse. Could be A&M.',
"Should you major in Compsci? well, here's a better question. do you wanna have a bad time?",
'A pen and paper is old fashioned, but sometimes old ways are best',
'A heart is like bedrock, destroyable only by cheating',
'You may not rest now, there are Canvas assignments nearby',
'You are filled with DETERMINATION',
'60k+ users!',
'Almost Turing complete',
'#BF5700',
'The waitlist is a lie!',
'BEVO JOCKEY 🗣️🗣️🗣️',
'RIP Domino, you beloved campus feline.', 'RIP Domino, you beloved campus feline.',
"The year is 2055 and Welch still isn't finished.", "The year is 2055 and Welch still isn't finished.",
'Motivation dropping faster than ur GPA', 'Motivation dropping faster than ur GPA',
'No Work Happens On PCL 5th Floor.', 'No Work Happens On PCL 5th Floor.',
'I may be a sophomore in name, but my credit count screams freshman!', 'I may be a sophomore in name, but my credit count screams freshman!',
'Pain is temporary, GPA is forever.',
"You've Yee'd Your Last Haw.",
'lol everything is already waitlisted.',
'Could be worse. Could be A&M.',
// 'TeXAs iS BaCK GuYZ', // 'TeXAs iS BaCK GuYZ',
'mAke iT yOuR tExAS', 'mAke iT yOuR tExAS',
'change yOur slogan', 'change yOur slogan',
@@ -24,7 +36,7 @@ const splashText: string[] = [
'Does McCombs teach Parseltongue?', 'Does McCombs teach Parseltongue?',
'No Cruce Enfrente Del Bus.', 'No Cruce Enfrente Del Bus.',
'Omae Wa Mou Shindeiru...', 'Omae Wa Mou Shindeiru...',
'Every day another brick disappears from Speedway', "They say each day, another brick disappears from Speedway. No one's sure where to.",
'The GDC will annex the EER one day', 'The GDC will annex the EER one day',
'To hike to Kins or not to hike to Kins...', 'To hike to Kins or not to hike to Kins...',
"C'mon you Longhorns! You want to study forever?", "C'mon you Longhorns! You want to study forever?",
@@ -39,8 +51,6 @@ const splashText: string[] = [
'Roll for Initiative!', 'Roll for Initiative!',
'The line at the on-campus Starbucks is longer than your course waitlist.', 'The line at the on-campus Starbucks is longer than your course waitlist.',
'The weather changes more often than your class schedule.', 'The weather changes more often than your class schedule.',
'Mmm... Brutalist architecture...',
'The course syllabus: more than meets the eye',
"'studying' often means refreshing Canvas every five minutes to see if the professor posted lecture slides.", "'studying' often means refreshing Canvas every five minutes to see if the professor posted lecture slides.",
"It's over Bevo! I have the high ground!", "It's over Bevo! I have the high ground!",
"I'll just skip this lecture and watch the recording later. What's the worst that could happen?", "I'll just skip this lecture and watch the recording later. What's the worst that could happen?",
@@ -59,14 +69,6 @@ const splashText: string[] = [
'Planner is now acquired by Plus', 'Planner is now acquired by Plus',
'Longhorn Developers is the best UT Student Org', 'Longhorn Developers is the best UT Student Org',
'The Eiffel Tower is the UT Tower of Paris', 'The Eiffel Tower is the UT Tower of Paris',
'A pen and paper is old fashioned, but sometimes old ways are best',
'A heart is like bedrock, destroyable only by cheating',
'You may not rest now, there are Canvas assignments nearby',
'You are filled with DETERMINATION',
'60k+ users!',
'Almost Turing complete',
'#BF5700',
'The waitlist is a lie!',
"He's a CS Major, but he showers regularly. 🧢", "He's a CS Major, but he showers regularly. 🧢",
'A CS major walks into a bar. The bar is empty because it is a CS major.', 'A CS major walks into a bar. The bar is empty because it is a CS major.',
'UT Registration Plus - The only thing that can make registration worse is not having it', 'UT Registration Plus - The only thing that can make registration worse is not having it',
@@ -112,7 +114,6 @@ const splashText: string[] = [
'Befriend the raccoons on campus', 'Befriend the raccoons on campus',
`It's ${new Date().toLocaleString('en-US', { month: 'long', day: 'numeric' })} and OU still sucks`, `It's ${new Date().toLocaleString('en-US', { month: 'long', day: 'numeric' })} and OU still sucks`,
'As seen on TV!', 'As seen on TV!',
"Should you major in Compsci? well, here's a better question. do you wanna have a bad time?",
]; ];
export default splashText; export default splashText;

View File

@@ -271,12 +271,12 @@ export default function Page404(): JSX.Element {
} }
function _0x5629d1() { function _0x5629d1() {
let _0x13c635 = _0xdd3699; let _0x13c635 = _0xdd3699;
_0x5b7f43(), (_0x5b7f43(),
_0x16f39e[_0x13c635(0x81)]( _0x16f39e[_0x13c635(0x81)](
_0x228047, _0x228047,
0x9c + -0x1 * 0x23ab + 0x230f * 0x1, 0x9c + -0x1 * 0x23ab + 0x230f * 0x1,
-0x1c26 + 0x7bf + -0x6cd * -0x3 -0x1c26 + 0x7bf + -0x6cd * -0x3
); ));
} }
let _0x93f360 = 0x64 * 0x49 + 0x1e1e + -0x3aa2; let _0x93f360 = 0x64 * 0x49 + 0x1e1e + -0x3aa2;
function _0x5b7f43() { function _0x5b7f43() {
@@ -373,12 +373,12 @@ export default function Page404(): JSX.Element {
(-0x2469 + 0x156a * -0x1 + 0x39e2)) + (-0x2469 + 0x156a * -0x1 + 0x39e2)) +
(-0x1 * 0x13f8 + 0x6df + -0x1 * -0xd29); (-0x1 * 0x13f8 + 0x6df + -0x1 * -0xd29);
if (_0x3e178a == 0x1 * -0x1a87 + 0x1fdd + -0x555 * 0x1) { if (_0x3e178a == 0x1 * -0x1a87 + 0x1fdd + -0x555 * 0x1) {
(_0x546fb5 = ((_0x546fb5 =
(_0x227002 * (-0x10d7 + 0x1 * 0x15ad + -0x2 * 0x263)) & (_0x227002 * (-0x10d7 + 0x1 * 0x15ad + -0x2 * 0x263)) &
(-0x25ca * 0x1 + 0x8 * 0x278 + -0x1 * -0x1219)), (-0x25ca * 0x1 + 0x8 * 0x278 + -0x1 * -0x1219)),
(_0x1667c5 = (_0x1667c5 =
(_0x32116b * (0x4d3 + 0x1c09 * -0x1 + 0x3 * 0x7c2)) & (_0x32116b * (0x4d3 + 0x1c09 * -0x1 + 0x3 * 0x7c2)) &
(-0xf06 * 0x2 + -0x144f * -0x1 + -0x344 * -0x3)); (-0xf06 * 0x2 + -0x144f * -0x1 + -0x344 * -0x3)));
if (_0x5b3085 < -0xa * 0xed + -0xd19 + 0x1 * 0x165b) if (_0x5b3085 < -0xa * 0xed + -0xd19 + 0x1 * 0x165b)
_0x1667c5 += -0xd48 + 0xf6c + 0xc * -0x2b; _0x1667c5 += -0xd48 + 0xf6c + 0xc * -0x2b;
} }
@@ -410,10 +410,10 @@ export default function Page404(): JSX.Element {
(-0x2709 + -0x6 * -0x312 + -0x39a * -0x6)), (-0x2709 + -0x6 * -0x312 + -0x39a * -0x6)),
(_0x267dd3 = _0x38c463)); (_0x267dd3 = _0x38c463));
} }
(_0x227002 += _0x4b089b), ((_0x227002 += _0x4b089b),
(_0x2aec99 += _0x5b3085), (_0x2aec99 += _0x5b3085),
(_0x32116b += _0x1eaaad), (_0x32116b += _0x1eaaad),
(_0x38c463 += _0x57383c); (_0x38c463 += _0x57383c));
} }
} }
let _0x5cba48 = let _0x5cba48 =
@@ -430,7 +430,7 @@ export default function Page404(): JSX.Element {
let _0xdf8389 = let _0xdf8389 =
((_0x13f1b0 & (-0x247a + -0x4 * -0x9c2 + -0x39 * 0x7)) * _0x2062a9 * _0x5c387a) / ((_0x13f1b0 & (-0x247a + -0x4 * -0x9c2 + -0x39 * 0x7)) * _0x2062a9 * _0x5c387a) /
((0x1d5 * 0xa + -0x250a + -0x31 * -0x67) * (-0x7 * 0x25f + -0xae7 + 0x1c7f * 0x1)); ((0x1d5 * 0xa + -0x250a + -0x31 * -0x67) * (-0x7 * 0x25f + -0xae7 + 0x1c7f * 0x1));
(_0x228047[_0x4626de(0x8e)][ ((_0x228047[_0x4626de(0x8e)][
(_0x132623 + _0x1a573d * _0x124180) * (0x29 * -0xa9 + -0x94 * -0x2b + -0x239 * -0x1) + (_0x132623 + _0x1a573d * _0x124180) * (0x29 * -0xa9 + -0x94 * -0x2b + -0x239 * -0x1) +
(0x55d * 0x2 + 0xeed * 0x1 + -0xc7 * 0x21) (0x55d * 0x2 + 0xeed * 0x1 + -0xc7 * 0x21)
] = _0x5cba48), ] = _0x5cba48),
@@ -441,7 +441,7 @@ export default function Page404(): JSX.Element {
(_0x228047[_0x4626de(0x8e)][ (_0x228047[_0x4626de(0x8e)][
(_0x132623 + _0x1a573d * _0x124180) * (0x1e2a + -0x21df + -0x1 * -0x3b9) + (_0x132623 + _0x1a573d * _0x124180) * (0x1e2a + -0x21df + -0x1 * -0x3b9) +
(0x1e79 + 0x860 * -0x2 + 0x1 * -0xdb7) (0x1e79 + 0x860 * -0x2 + 0x1 * -0xdb7)
] = _0xdf8389); ] = _0xdf8389));
} }
} }
} }

View File

@@ -37,6 +37,9 @@ export default async function createSchedule(scheduleName: string) {
await UserScheduleStore.set('schedules', schedules); await UserScheduleStore.set('schedules', schedules);
// Automatically switch to the new schedule
await UserScheduleStore.set('activeIndex', schedules.length - 1);
// If there is only one schedule, set the active index to the new schedule // If there is only one schedule, set the active index to the new schedule
if (schedules.length <= 1) { if (schedules.length <= 1) {
await UserScheduleStore.set('activeIndex', 0); await UserScheduleStore.set('activeIndex', 0);

View File

@@ -31,5 +31,9 @@ export default async function duplicateSchedule(scheduleId: string): Promise<str
} satisfies typeof schedule); } satisfies typeof schedule);
await UserScheduleStore.set('schedules', schedules); await UserScheduleStore.set('schedules', schedules);
// Automatically switch to the duplicated schedule
await UserScheduleStore.set('activeIndex', scheduleIndex + 1);
return undefined; return undefined;
} }

View File

@@ -1,6 +1,7 @@
import CourseCatalogMain from '@views/components/CourseCatalogMain'; import CourseCatalogMain from '@views/components/CourseCatalogMain';
import InjectedButton from '@views/components/injected/AddAllButton'; import InjectedButton from '@views/components/injected/AddAllButton';
import DaysCheckbox from '@views/components/injected/DaysCheckbox'; import DaysCheckbox from '@views/components/injected/DaysCheckbox';
import ShadedResults from '@views/components/injected/SearchResultShader';
import getSiteSupport, { SiteSupport } from '@views/lib/getSiteSupport'; import getSiteSupport, { SiteSupport } from '@views/lib/getSiteSupport';
import React from 'react'; import React from 'react';
import { createRoot } from 'react-dom/client'; import { createRoot } from 'react-dom/client';
@@ -30,3 +31,7 @@ if (support === SiteSupport.MY_UT) {
if (support === SiteSupport.COURSE_CATALOG_SEARCH) { if (support === SiteSupport.COURSE_CATALOG_SEARCH) {
renderComponent(DaysCheckbox); renderComponent(DaysCheckbox);
} }
if (support === SiteSupport.COURSE_CATALOG_KWS) {
renderComponent(ShadedResults);
}

View File

@@ -21,6 +21,11 @@ export interface IOptionsStore {
/** whether the calendar sidebar should be shown when the calendar is opened */ /** whether the calendar sidebar should be shown when the calendar is opened */
showCalendarSidebar: boolean; showCalendarSidebar: boolean;
/** whether the promo should be shown */
showUTDiningPromo: boolean;
/** whether users are allowed to bypass the 10 schedule limit */
allowMoreSchedules: boolean;
} }
export const OptionsStore = createSyncStore<IOptionsStore>({ export const OptionsStore = createSyncStore<IOptionsStore>({
@@ -30,6 +35,8 @@ export const OptionsStore = createSyncStore<IOptionsStore>({
enableDataRefreshing: false, enableDataRefreshing: false,
alwaysOpenCalendarInNewTab: false, alwaysOpenCalendarInNewTab: false,
showCalendarSidebar: true, showCalendarSidebar: true,
showUTDiningPromo: true,
allowMoreSchedules: false,
}); });
/** /**
@@ -45,6 +52,8 @@ export const initSettings = async () =>
enableDataRefreshing: await OptionsStore.get('enableDataRefreshing'), enableDataRefreshing: await OptionsStore.get('enableDataRefreshing'),
alwaysOpenCalendarInNewTab: await OptionsStore.get('alwaysOpenCalendarInNewTab'), alwaysOpenCalendarInNewTab: await OptionsStore.get('alwaysOpenCalendarInNewTab'),
showCalendarSidebar: await OptionsStore.get('showCalendarSidebar'), showCalendarSidebar: await OptionsStore.get('showCalendarSidebar'),
showUTDiningPromo: await OptionsStore.get('showUTDiningPromo'),
allowMoreSchedules: await OptionsStore.get('allowMoreSchedules'),
}) satisfies IOptionsStore; }) satisfies IOptionsStore;
// Clothing retailer right // Clothing retailer right

View File

@@ -44,7 +44,12 @@ export type Semester = {
export class Course { export class Course {
/** Every course has a uniqueId within UT's registrar system corresponding to each course section */ /** Every course has a uniqueId within UT's registrar system corresponding to each course section */
uniqueId!: number; uniqueId!: number;
/** This is the course number for a course, i.e CS 314 would be 314, MAL 306H would be 306H */ /**
* This is the course number for a course, i.e CS 314 would be 314, MAL 306H would be 306H.
* UT prefixes summer courses with f, s, n, or w:
* [f]irst term, [s]econd term, [n]ine week term, [w]hole term.
* So, the first term of PSY 301 over the summer would be 'f301'
*/
number!: string; number!: string;
/** The full name of the course, i.e. CS 314 Data Structures and Algorithms */ /** The full name of the course, i.e. CS 314 Data Structures and Algorithms */
fullName!: string; fullName!: string;
@@ -91,6 +96,46 @@ export class Course {
} }
this.colors = course.colors ? structuredClone(course.colors) : getCourseColors('emerald', 500); this.colors = course.colors ? structuredClone(course.colors) : getCourseColors('emerald', 500);
this.core = course.core ?? []; this.core = course.core ?? [];
if (course.semester.season === 'Summer') {
// A bug from and old version put the summer term in the course,
// so we need to handle that case
const { department, number } = Course.cleanSummerTerm(course.department, course.number);
this.department = department;
this.number = number;
}
}
/**
* Due to a bug in an older version, the summer term was included in the course department code,
* instead of the course number.
* UT prefixes summer courses with f, s, n, or w:
* [f]irst term, [s]econd term, [n]ine week term, [w]hole term
*
* @param department - The course department code, like 'C S'
* @param number - The course number, like '314H'
* @returns The properly formatted department and course number
* @example
* ```ts
* cleanSummerTerm('C S', '314H') // { department: 'C S', number: '314H' }
* cleanSummerTerm('P R', 'f378') // { department: 'P R', number: 'f378' }
* cleanSummerTerm('P R f', '378') // { department: 'P R', number: 'f378' }
* cleanSummerTerm('P S', 'n303') // { department: 'P S', number: 'n303' }
* cleanSummerTerm('P S n', '303') // { department: 'P S', number: 'n303' }
* ```
*/
static cleanSummerTerm(department: string, number: string): { department: string; number: string } {
// UT prefixes summer courses with f, s, n, or w:
// [f]irst term, [s]econd term, [n]ine week term, [w]hole term
const summerTerm = department.match(/[fsnw]$/);
if (!summerTerm) {
return { department, number };
}
return {
department: department.slice(0, -1).trim(),
number: summerTerm[0] + number,
};
} }
/** /**
@@ -111,6 +156,18 @@ export class Course {
return conflicts; return conflicts;
} }
/**
* @returns The course number without the summer term
* @example
* ```ts
* const c = new Course({ number: 'f301', ... });
* c.getNumberWithoutTerm() // '301'
* ```
*/
getNumberWithoutTerm(): string {
return this.number.replace(/^\D/, ''); // Remove nondigit at start, if it exists
}
} }
/** /**

View File

@@ -0,0 +1,57 @@
import { describe, expect, it } from 'vitest';
import { Course } from '../Course';
describe('Course::cleanSummerTerm', () => {
it("shouldn't affect already cleaned summer terms", () => {
const inputs = [
['C S', '314H'],
['P R', 'f378'],
['P S', 'f303'],
['WGS', 's301'],
['S W', 'n360K'],
['GOV', 'w312L'],
['J', 's311F'],
['J S', '311F'],
] as const;
const expected = [
{ department: 'C S', number: '314H' },
{ department: 'P R', number: 'f378' },
{ department: 'P S', number: 'f303' },
{ department: 'WGS', number: 's301' },
{ department: 'S W', number: 'n360K' },
{ department: 'GOV', number: 'w312L' },
{ department: 'J', number: 's311F' },
{ department: 'J S', number: '311F' },
];
const results = inputs.map(input => Course.cleanSummerTerm(input[0], input[1]));
expect(results).toEqual(expected);
});
it('should move summer term indicator to course number', () => {
const inputs = [
['P R f', '378'],
['P S f', '303'],
['WGS s', '301'],
['S W n', '360K'],
['GOV w', '312L'],
['J s', '311F'],
['J S', '311F'],
] as const;
const expected = [
{ department: 'P R', number: 'f378' },
{ department: 'P S', number: 'f303' },
{ department: 'WGS', number: 's301' },
{ department: 'S W', number: 'n360K' },
{ department: 'GOV', number: 'w312L' },
{ department: 'J', number: 's311F' },
{ department: 'J S', number: '311F' },
];
const results = inputs.map(input => Course.cleanSummerTerm(input[0], input[1]));
expect(results).toEqual(expected);
});
});

View File

@@ -0,0 +1,19 @@
/**
* This file contains URLs for external applications and resources.
* Centralizing these URLs makes it easier to track, update, and manage them in a single place.
*/
/**
* URL to the UT Dining app on the App Store
*/
export const UT_DINING_APP_STORE_URL = new URL('https://apps.apple.com/us/app/ut-dining/id6743042002').toString();
/**
* URL to the UT Dining app on the Google Play Store (currently not available)
*/
export const UT_DINING_GOOGLE_PLAY_URL = ''; // Placeholder for Google Play URL, Android app not available yet
/**
* URL to the promo image
*/
export const UT_DINING_PROMO_IMAGE_URL = new URL('https://cdn.longhorns.dev/ut-dining-advert1.png').toString();

View File

@@ -0,0 +1,19 @@
import type { Meta, StoryObj } from '@storybook/react';
import CalendarFooter from '@views/components/calendar/CalendarFooter';
import React from 'react';
const meta = {
title: 'Components/Calendar/CalendarFooter',
component: CalendarFooter,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
} satisfies Meta<typeof CalendarFooter>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {},
};

View File

@@ -0,0 +1,14 @@
import type { Meta, StoryObj } from '@storybook/react';
import DiningAppPromo from '@views/components/calendar/DiningAppPromo';
export default {
title: 'Components/Calendar/DiningAppPromo',
component: DiningAppPromo,
parameters: {
layout: 'centered',
},
} satisfies Meta<typeof DiningAppPromo>;
type Story = StoryObj<typeof DiningAppPromo>;
export const Default: Story = {};

View File

@@ -73,7 +73,7 @@ const generateCourses = (count: number): Course[] => {
const exampleCourses = generateCourses(numberOfCourses); const exampleCourses = generateCourses(numberOfCourses);
type CourseWithId = Course & BaseItem; type CourseWithId = { course: Course } & BaseItem;
const meta = { const meta = {
title: 'Components/Common/SortableList', title: 'Components/Common/SortableList',
@@ -91,11 +91,10 @@ export const Default: Story = {
args: { args: {
draggables: exampleCourses.map(course => ({ draggables: exampleCourses.map(course => ({
id: course.uniqueId, id: course.uniqueId,
...course, course,
getConflicts: course.getConflicts,
})), })),
onChange: () => {}, onChange: () => {},
renderItem: course => <PopupCourseBlock key={course.id} course={course} colors={course.colors} />, renderItem: ({ id, course }) => <PopupCourseBlock key={id} course={course} colors={course.colors} />,
}, },
render: args => ( render: args => (
<div className='h-3xl w-3xl transform-none'> <div className='h-3xl w-3xl transform-none'>

View File

@@ -15,6 +15,8 @@ import type { SiteSupportType } from '@views/lib/getSiteSupport';
import { populateSearchInputs } from '@views/lib/populateSearchInputs'; import { populateSearchInputs } from '@views/lib/populateSearchInputs';
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import DialogProvider from './common/DialogProvider/DialogProvider';
interface Props { interface Props {
support: Extract<SiteSupportType, 'COURSE_CATALOG_DETAILS' | 'COURSE_CATALOG_LIST'>; support: Extract<SiteSupportType, 'COURSE_CATALOG_DETAILS' | 'COURSE_CATALOG_LIST'>;
} }
@@ -82,28 +84,30 @@ export default function CourseCatalogMain({ support }: Props): JSX.Element | nul
return ( return (
<ExtensionRoot> <ExtensionRoot>
<NewSearchLink /> <DialogProvider>
<RecruitmentBanner /> <NewSearchLink />
<TableHead>Plus</TableHead> <RecruitmentBanner />
{rows.map( <TableHead>Plus</TableHead>
row => {rows.map(
row.course && ( row =>
<TableRow row.course && (
key={row.course.uniqueId} <TableRow
row={row} key={row.course.uniqueId}
isSelected={row.course.uniqueId === selectedCourse?.uniqueId} row={row}
activeSchedule={activeSchedule} isSelected={row.course.uniqueId === selectedCourse?.uniqueId}
onClick={handleRowButtonClick(row.course)} activeSchedule={activeSchedule}
/> onClick={handleRowButtonClick(row.course)}
) />
)} )
<CourseCatalogInjectedPopup )}
course={selectedCourse!} // always defined when showPopup is true <CourseCatalogInjectedPopup
show={showPopup} course={selectedCourse!} // always defined when showPopup is true
onClose={() => setShowPopup(false)} show={showPopup}
afterLeave={() => setSelectedCourse(null)} onClose={() => setShowPopup(false)}
/> afterLeave={() => setSelectedCourse(null)}
{enableScrollToLoad && <AutoLoad addRows={addRows} />} />
{enableScrollToLoad && <AutoLoad addRows={addRows} />}
</DialogProvider>
</ExtensionRoot> </ExtensionRoot>
); );
} }

View File

@@ -155,15 +155,14 @@ export default function PopupMain(): JSX.Element {
<SortableList <SortableList
draggables={activeSchedule.courses.map(course => ({ draggables={activeSchedule.courses.map(course => ({
id: course.uniqueId, id: course.uniqueId,
...course, course,
getConflicts: course.getConflicts,
}))} }))}
onChange={reordered => { onChange={reordered => {
activeSchedule.courses = reordered.map(({ id: _id, ...course }) => course); activeSchedule.courses = reordered.map(({ course }) => course);
replaceSchedule(getActiveSchedule(), activeSchedule); replaceSchedule(getActiveSchedule(), activeSchedule);
}} }}
renderItem={course => ( renderItem={({ id, course }) => (
<PopupCourseBlock key={course.id} course={course} colors={course.colors} /> <PopupCourseBlock key={id} course={course} colors={course.colors} />
)} )}
/> />
)} )}

View File

@@ -27,6 +27,7 @@ import { Button } from '../common/Button';
import { LargeLogo } from '../common/LogoIcon'; import { LargeLogo } from '../common/LogoIcon';
import Text from '../common/Text/Text'; import Text from '../common/Text/Text';
import CalendarFooter from './CalendarFooter'; import CalendarFooter from './CalendarFooter';
import DiningAppPromo from './DiningAppPromo';
/** /**
* Calendar page component * Calendar page component
@@ -41,6 +42,8 @@ export default function Calendar(): ReactNode {
const [showPopup, setShowPopup] = useState<boolean>(course !== null); const [showPopup, setShowPopup] = useState<boolean>(course !== null);
const showWhatsNewDialog = useWhatsNewPopUp(); const showWhatsNewDialog = useWhatsNewPopUp();
const [showUTDiningPromo, setShowUTDiningPromo] = useState<boolean>(false);
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const { data: showSidebar, isPending: isSidebarStatePending } = useQuery({ const { data: showSidebar, isPending: isSidebarStatePending } = useQuery({
queryKey: ['settings', 'showCalendarSidebar'], queryKey: ['settings', 'showCalendarSidebar'],
@@ -82,12 +85,19 @@ export default function Calendar(): ReactNode {
if (course) setShowPopup(true); if (course) setShowPopup(true);
}, [course]); }, [course]);
useEffect(() => {
// Load the user's preference for the promo
OptionsStore.get('showUTDiningPromo').then(show => {
setShowUTDiningPromo(show);
});
}, []);
if (isSidebarStatePending) return null; if (isSidebarStatePending) return null;
return ( return (
<CalendarContext.Provider value> <CalendarContext.Provider value>
<div className='h-full w-full flex flex-col'> <div className='h-full w-full flex flex-col'>
<div className='h-screen flex overflow-auto screenshot:calendar-target'> <div className='screenshot:calendar-target h-screen flex overflow-auto'>
<div <div
className={clsx( className={clsx(
'py-spacing-6 relative h-full min-h-screen w-full flex flex-none flex-col justify-between overflow-clip whitespace-nowrap border-r border-ut-offwhite/50 shadow-[2px_0_10px,rgba(214_210_196_/_.1)] motion-safe:duration-300 motion-safe:ease-out-expo motion-safe:transition-[max-width] screenshot:hidden', 'py-spacing-6 relative h-full min-h-screen w-full flex flex-none flex-col justify-between overflow-clip whitespace-nowrap border-r border-ut-offwhite/50 shadow-[2px_0_10px,rgba(214_210_196_/_.1)] motion-safe:duration-300 motion-safe:ease-out-expo motion-safe:transition-[max-width] screenshot:hidden',
@@ -104,11 +114,12 @@ export default function Calendar(): ReactNode {
<LargeLogo /> <LargeLogo />
<Button <Button
variant='minimal' variant='minimal'
size='small'
color='theme-black' color='theme-black'
onClick={() => { onClick={() => {
setShowSidebar(!showSidebar); setShowSidebar(!showSidebar);
}} }}
className='h-fit screenshot:hidden !p-0' className='screenshot:hidden'
icon={Sidebar} icon={Sidebar}
/> />
</div> </div>
@@ -122,8 +133,16 @@ export default function Calendar(): ReactNode {
<CalendarSchedules /> <CalendarSchedules />
<Divider orientation='horizontal' size='100%' /> <Divider orientation='horizontal' size='100%' />
<ResourceLinks /> <ResourceLinks />
<Divider orientation='horizontal' size='100%' />
{/* <TeamLinks /> */} {/* <TeamLinks /> */}
<Divider orientation='horizontal' size='100%' />
{showUTDiningPromo && (
<DiningAppPromo
onClose={() => {
setShowUTDiningPromo(false);
OptionsStore.set('showUTDiningPromo', false);
}}
/>
)}
<div className='flex flex-col gap-spacing-3'> <div className='flex flex-col gap-spacing-3'>
<a <a
href={CRX_PAGES.REPORT} href={CRX_PAGES.REPORT}

View File

@@ -124,17 +124,15 @@ export default function CourseCellColorPicker({ defaultColor }: CourseCellColorP
<> <>
<Divider orientation='horizontal' size='100%' className='my-1' /> <Divider orientation='horizontal' size='100%' className='my-1' />
<div className='grid grid-cols-6 gap-1'> <div className='grid grid-cols-6 gap-1'>
{colorPatchColors {colorPatchColors.get(selectedBaseColor)?.map(shadeColor => (
.get(selectedBaseColor) <ColorPatch
?.map(shadeColor => ( key={shadeColor}
<ColorPatch color={shadeColor}
key={shadeColor} isSelected={shadeColor === hexCodeWithHash}
color={shadeColor} handleSelectColorPatch={handleSelectColorPatch}
isSelected={shadeColor === hexCodeWithHash} defaultColor={defaultColor}
handleSelectColorPatch={handleSelectColorPatch} />
defaultColor={defaultColor} ))}
/>
))}
</div> </div>
</> </>
)} )}

View File

@@ -27,12 +27,10 @@ export default function HexColorEditor({ hexCode, setHexCode }: HexColorEditorPr
const tagColor = pickFontColor(previewColor.slice(1) as `#${string}`); const tagColor = pickFontColor(previewColor.slice(1) as `#${string}`);
const [localHexCode, setLocalHexCode] = React.useState(hexCode); const [localHexCode, setLocalHexCode] = React.useState(hexCode);
const debouncedSetHexCode = useDebounce((value: string) => setHexCode(value), 500); const debouncedSetHexCode = useDebounce(setHexCode, 500);
React.useEffect(() => { React.useEffect(() => {
if (hexCode !== localHexCode) { setLocalHexCode(hexCode);
setLocalHexCode(hexCode);
}
}, [hexCode]); }, [hexCode]);
React.useEffect(() => { React.useEffect(() => {

View File

@@ -58,13 +58,7 @@ export default function CalendarFooter(): JSX.Element {
))} ))}
</div> </div>
<div> <div>
<Button <Button variant='minimal' size='small' icon={GearSix} color='ut-black' onClick={handleOpenOptions} />
className='h-fit w-fit !p-0'
variant='minimal'
icon={GearSix}
color='ut-black'
onClick={handleOpenOptions}
/>
</div> </div>
</footer> </footer>
); );

View File

@@ -2,14 +2,18 @@ import type { Course } from '@shared/types/Course';
import CalendarCourseCell from '@views/components/calendar/CalendarCourseCell'; import CalendarCourseCell from '@views/components/calendar/CalendarCourseCell';
import Text from '@views/components/common/Text/Text'; import Text from '@views/components/common/Text/Text';
import { ColorPickerProvider } from '@views/contexts/ColorPickerContext'; import { ColorPickerProvider } from '@views/contexts/ColorPickerContext';
import { useSentryScope } from '@views/contexts/SentryContext';
import type { CalendarGridCourse } from '@views/hooks/useFlattenedCourseSchedule'; import type { CalendarGridCourse } from '@views/hooks/useFlattenedCourseSchedule';
import React, { Fragment } from 'react'; import React, { Fragment } from 'react';
import CalendarCell from './CalendarGridCell'; import CalendarCell from './CalendarGridCell';
import { calculateCourseCellColumns } from './utils';
const daysOfWeek = ['MON', 'TUE', 'WED', 'THU', 'FRI']; const daysOfWeek = ['MON', 'TUE', 'WED', 'THU', 'FRI'];
const hoursOfDay = Array.from({ length: 14 }, (_, index) => index + 8); const hoursOfDay = Array.from({ length: 14 }, (_, index) => index + 8);
const IS_STORYBOOK = import.meta.env.STORYBOOK;
interface Props { interface Props {
courseCells?: CalendarGridCourse[]; courseCells?: CalendarGridCourse[];
saturdayClass?: boolean; saturdayClass?: boolean;
@@ -106,6 +110,12 @@ interface AccountForCourseConflictsProps {
// TODO: Possibly refactor to be more concise // TODO: Possibly refactor to be more concise
// TODO: Deal with react strict mode (wacky movements) // TODO: Deal with react strict mode (wacky movements)
function AccountForCourseConflicts({ courseCells, setCourse }: AccountForCourseConflictsProps): JSX.Element[] { function AccountForCourseConflicts({ courseCells, setCourse }: AccountForCourseConflictsProps): JSX.Element[] {
// Sentry is not defined in storybook.
// This is a valid use case for a condition hook, since IS_STORYBOOK is determined at build time,
// it doesn't change between renders.
// eslint-disable-next-line react-hooks/rules-of-hooks
const [sentryScope] = IS_STORYBOOK ? [undefined] : useSentryScope();
// Groups by dayIndex to identify overlaps // Groups by dayIndex to identify overlaps
const days = courseCells.reduce( const days = courseCells.reduce(
(acc, cell: CalendarGridCourse) => { (acc, cell: CalendarGridCourse) => {
@@ -120,31 +130,15 @@ function AccountForCourseConflicts({ courseCells, setCourse }: AccountForCourseC
); );
// Check for overlaps within each day and adjust gridColumnIndex and totalColumns // Check for overlaps within each day and adjust gridColumnIndex and totalColumns
Object.values(days).forEach((dayCells: CalendarGridCourse[]) => { Object.values(days).forEach((dayCells: CalendarGridCourse[], idx) => {
// Sort by start time to ensure proper columnIndex assignment try {
dayCells.sort((a, b) => a.calendarGridPoint.startIndex - b.calendarGridPoint.startIndex); calculateCourseCellColumns(dayCells);
} catch (error) {
dayCells.forEach((cell, _, arr) => { console.error(`Error calculating course cell columns ${idx}`, error);
let columnIndex = 1; if (sentryScope) {
cell.totalColumns = 1; sentryScope.captureException(error);
// Check for overlaps and adjust columnIndex as needed
for (let otherCell of arr) {
if (otherCell !== cell) {
const isOverlapping =
otherCell.calendarGridPoint.startIndex < cell.calendarGridPoint.endIndex &&
otherCell.calendarGridPoint.endIndex > cell.calendarGridPoint.startIndex;
if (isOverlapping) {
// Adjust columnIndex to not overlap with the otherCell
if (otherCell.gridColumnStart && otherCell.gridColumnStart >= columnIndex) {
columnIndex = otherCell.gridColumnStart + 1;
}
cell.totalColumns += 1;
}
}
} }
cell.gridColumnStart = columnIndex; }
cell.gridColumnEnd = columnIndex + 1;
});
}); });
return courseCells return courseCells

View File

@@ -1,5 +1,5 @@
import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react'; import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react';
import { CalendarDots, Export, FilePng, Sidebar } from '@phosphor-icons/react'; import { CalendarDots, Export, FileCode, FilePng, Sidebar } from '@phosphor-icons/react';
import styles from '@views/components/calendar/CalendarHeader/CalendarHeader.module.scss'; import styles from '@views/components/calendar/CalendarHeader/CalendarHeader.module.scss';
import { Button } from '@views/components/common/Button'; import { Button } from '@views/components/common/Button';
import DialogProvider from '@views/components/common/DialogProvider/DialogProvider'; import DialogProvider from '@views/components/common/DialogProvider/DialogProvider';
@@ -11,7 +11,7 @@ import useSchedules from '@views/hooks/useSchedules';
import clsx from 'clsx'; import clsx from 'clsx';
import React from 'react'; import React from 'react';
import { saveAsCal, saveCalAsPng } from '../utils'; import { handleExportJson, saveAsCal, saveCalAsPng } from '../utils';
interface CalendarHeaderProps { interface CalendarHeaderProps {
sidebarOpen?: boolean; sidebarOpen?: boolean;
@@ -28,14 +28,15 @@ export default function CalendarHeader({ sidebarOpen, onSidebarToggle }: Calenda
return ( return (
<div <div
style={{ scrollbarGutter: 'stable' }} style={{ scrollbarGutter: 'stable' }}
className='sticky left-0 right-0 top-0 z-10 min-h-[85px] flex items-center gap-5 overflow-x-scroll overflow-y-hidden bg-white pl-spacing-7 pt-spacing-5' className='sticky left-0 right-0 top-0 z-10 min-h-[85px] flex items-center gap-5 overflow-x-auto overflow-y-hidden bg-white pl-spacing-7 pt-spacing-5'
> >
{!sidebarOpen && ( {!sidebarOpen && (
<Button <Button
variant='minimal' variant='minimal'
size='small'
color='theme-black' color='theme-black'
onClick={onSidebarToggle} onClick={onSidebarToggle}
className='h-fit w-fit screenshot:hidden !p-0' className='screenshot:hidden'
icon={Sidebar} icon={Sidebar}
/> />
)} )}
@@ -98,6 +99,18 @@ export default function CalendarHeader({ sidebarOpen, onSidebarToggle }: Calenda
Save as .cal Save as .cal
</Button> </Button>
</MenuItem> </MenuItem>
<MenuItem>
<Button
className='w-full flex justify-start'
onClick={() => handleExportJson(activeSchedule.id)}
color='ut-black'
size='small'
variant='minimal'
icon={FileCode}
>
Save as .json
</Button>
</MenuItem>
{/* <MenuItem> {/* <MenuItem>
<Button color='ut-black' size='small' variant='minimal' icon={FileTxt}> <Button color='ut-black' size='small' variant='minimal' icon={FileTxt}>
Export Unique IDs Export Unique IDs

View File

@@ -26,15 +26,16 @@ export function CalendarSchedules() {
}; };
return ( return (
<div className='min-w-full w-0 flex flex-col items-center gap-y-spacing-3'> <div className='min-w-full w-0 flex flex-col items-center gap-y-spacing-2'>
<div className='m0 w-full flex justify-between'> <div className='m0 w-full flex items-center justify-between'>
<Text variant='h3' className='text-nowrap text-theme-black'> <Text variant='h3' className='text-nowrap text-theme-black'>
MY SCHEDULES MY SCHEDULES
</Text> </Text>
<Button <Button
variant='minimal' variant='minimal'
size='small'
color='theme-black' color='theme-black'
className='h-fit w-fit !p-0 btn' className='!p-0 btn'
onClick={handleAddSchedule} onClick={handleAddSchedule}
icon={Plus} icon={Plus}
/> />

View File

@@ -0,0 +1,69 @@
import { AppStoreLogo, ForkKnife, X as CloseIcon } from '@phosphor-icons/react';
import { UT_DINING_APP_STORE_URL } from '@shared/util/appUrls';
import { Button } from '@views/components/common/Button';
import Text from '@views/components/common/Text/Text';
import React from 'react';
interface DiningAppPromoProps {
onClose: () => void;
}
/**
* Promotional component for the UT Dining app
*/
export default function DiningAppPromo({ onClose }: DiningAppPromoProps) {
return (
<div className='relative min-w-[16.25rem] w-full flex items-center gap-spacing-3 border border-ut-offwhite/50 rounded p-spacing-4'>
<div className='flex items-center justify-center'>
<ForkKnife className='h-6 w-6 text-ut-black' />
</div>
<div className='flex flex-col gap-spacing-1'>
<Text as='p' variant='small' className='whitespace-normal text-ut-black'>
Download our new{' '}
<a
href={UT_DINING_APP_STORE_URL}
target='_blank'
rel='noreferrer'
aria-label='UT Dining app'
className='text-ut-burntorange underline'
>
UT Dining app
</a>{' '}
to explore all dining options on campus!
</Text>
<div className='mt-spacing-2 flex items-center gap-spacing-2'>
<Text variant='mini' className='text-ut-black'>
Available on
</Text>
<a
href={UT_DINING_APP_STORE_URL}
target='_blank'
rel='noreferrer'
aria-label='Download on App Store'
className='text-theme-black transition-colors hover:text-ut-burntorange'
>
<AppStoreLogo className='h-4.5 w-4.5' />
</a>
{/* <a
href={UT_DINING_GOOGLE_PLAY_URL}
target='_blank'
rel='noreferrer'
aria-label='Download on Google Play'
className='text-theme-black hover:text-ut-burntorange transition-colors'
>
<GooglePlayLogo className='h-4.5 w-4.5' />
</a> */}
</div>
</div>
<Button
variant='minimal'
color='theme-black'
onClick={onClose}
className='absolute right-1 top-1 h-5 w-5 p-0'
icon={CloseIcon}
aria-label='Close dining app promo'
title='Close'
/>
</div>
);
}

View File

@@ -13,10 +13,10 @@ interface LinkItem {
} }
const links: LinkItem[] = [ const links: LinkItem[] = [
{ // {
text: "Spring '25 Course Schedule", // text: "Spring '25 Course Schedule",
url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20252/', // url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20252/',
}, // },
{ {
text: 'Course Schedule Archives', text: 'Course Schedule Archives',
url: 'https://registrar.utexas.edu/schedules/archive', url: 'https://registrar.utexas.edu/schedules/archive',

View File

@@ -14,30 +14,30 @@ interface LinkItem {
} }
const links: LinkItem[] = [ const links: LinkItem[] = [
// {
// text: "Fall '25 Course Schedule",
// url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20259/',
// },
// {
// text: 'Course Schedule Archives',
// url: 'https://registrar.utexas.edu/schedules/archive',
// },
{ {
text: "Fall '25 Course Schedule", text: "Spring '26 Course Schedule",
url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20259/', url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20262/',
}, },
{ {
text: "Summer '25 Course Schedule", text: 'Other Course Schedules',
url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20256/', url: 'https://registrar.utexas.edu/schedules',
},
{
text: "Spring '25 Course Schedule",
url: 'https://utdirect.utexas.edu/apps/registrar/course_schedule/20252/',
},
{
text: 'Course Schedule Archives',
url: 'https://registrar.utexas.edu/schedules/archive',
}, },
{ {
text: 'My Degree Audit (IDA)', text: 'My Degree Audit (IDA)',
url: 'https://utdirect.utexas.edu/apps/degree/audits/', url: 'https://utdirect.utexas.edu/apps/degree/audits/',
}, },
// { {
// text: "'24-'25 Academic Calendar", text: "'25-'26 Academic Calendar",
// url: 'https://registrar.utexas.edu/calendars/24-25', url: 'https://registrar.utexas.edu/calendars/25-26',
// }, },
{ {
text: 'Registration Info Sheet (RIS)', text: 'Registration Info Sheet (RIS)',
url: 'https://utdirect.utexas.edu/registrar/ris.WBX', url: 'https://utdirect.utexas.edu/registrar/ris.WBX',

View File

@@ -1,6 +1,7 @@
import { tz } from '@date-fns/tz'; import { tz } from '@date-fns/tz';
import { Course } from '@shared/types/Course'; import { Course } from '@shared/types/Course';
import { UserSchedule } from '@shared/types/UserSchedule'; import { UserSchedule } from '@shared/types/UserSchedule';
import type { CalendarGridCourse } from '@views/hooks/useFlattenedCourseSchedule';
import type { Serialized } from 'chrome-extension-toolkit'; import type { Serialized } from 'chrome-extension-toolkit';
import { format as formatDate, parseISO } from 'date-fns'; import { format as formatDate, parseISO } from 'date-fns';
import { import {
@@ -8,9 +9,17 @@ import {
multiMeetingMultiInstructorCourse, multiMeetingMultiInstructorCourse,
multiMeetingMultiInstructorSchedule, multiMeetingMultiInstructorSchedule,
} from 'src/stories/injected/mocked'; } from 'src/stories/injected/mocked';
import { afterEach, describe, expect, it, vi } from 'vitest'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { allDatesInRanges, formatToHHMMSS, meetingToIcsString, nextDayInclusive, scheduleToIcsString } from './utils'; import type { CalendarCourseCellProps } from './CalendarCourseCell';
import {
allDatesInRanges,
calculateCourseCellColumns,
formatToHHMMSS,
meetingToIcsString,
nextDayInclusive,
scheduleToIcsString,
} from './utils';
// Do all timezone calculations relative to UT's timezone // Do all timezone calculations relative to UT's timezone
const TIMEZONE = 'America/Chicago'; const TIMEZONE = 'America/Chicago';
@@ -477,3 +486,196 @@ describe('scheduleToIcsString', () => {
vi.restoreAllMocks(); vi.restoreAllMocks();
}); });
}); });
describe('calculateCourseCellColumns', () => {
let testIdCounter = 0;
const makeCell = (startIndex: number, endIndex: number): CalendarGridCourse => {
if (endIndex <= startIndex && !(startIndex === -1 && endIndex === -1)) {
throw new Error('Test writer error: startIndex must be strictly less than endIndex');
}
const cell = {
calendarGridPoint: {
dayIndex: 1,
startIndex,
endIndex,
},
componentProps: {} as unknown as CalendarCourseCellProps,
course: {} as unknown as Course,
async: false,
} satisfies CalendarGridCourse;
/* eslint no-underscore-dangle: ["error", { "allow": ["__test_id"] }] */
(cell as unknown as { __test_id: number }).__test_id = testIdCounter++;
return cell;
};
/**
* Creates test cases for calculateCourseCellColumns
* @param cellConfigs - Array of [startIndex, endIndex, totalColumns, gridColumnStart, gridColumnEnd]
* @returns Tuple of [cells, expectedCells]
*/
const makeCellsTest = (
cellConfigs: Array<[number, number, number, number, number]>
): [CalendarGridCourse[], CalendarGridCourse[]] => {
// Create cells with only start/end indices
const cells = cellConfigs.map(([startIndex, endIndex]) => makeCell(startIndex, endIndex));
// Create expected cells with all properties set
const expectedCells = structuredClone<CalendarGridCourse[]>(cells);
cellConfigs.forEach((config, index) => {
const [, , totalColumns, gridColumnStart, gridColumnEnd] = config;
expectedCells[index]!.totalColumns = totalColumns;
expectedCells[index]!.gridColumnStart = gridColumnStart;
expectedCells[index]!.gridColumnEnd = gridColumnEnd;
});
return [cells, expectedCells];
};
beforeEach(() => {
// Ensure independence between tests
testIdCounter = 0;
});
it('should do nothing to an empty array if no courses are present', () => {
const cells: CalendarGridCourse[] = [];
calculateCourseCellColumns(cells);
expect(cells).toEqual([]);
});
it('should set the right values for one course cell', () => {
const [cells, expectedCells] = makeCellsTest([[13, 15, 1, 1, 2]]);
calculateCourseCellColumns(cells);
expect(cells).toEqual(expectedCells);
});
it('should handle two separated courses', () => {
// These two cells can share a column, because they aren't concurrent
const [cells, expectedCells] = makeCellsTest([
[13, 15, 1, 1, 2],
[16, 18, 1, 1, 2],
]);
calculateCourseCellColumns(cells);
expect(cells).toEqual(expectedCells);
});
it('should handle two back-to-back courses', () => {
// These two cells can share a column, because they aren't concurrent
const [cells, expectedCells] = makeCellsTest([
[13, 15, 1, 1, 2],
[15, 17, 1, 1, 2],
]);
calculateCourseCellColumns(cells);
expect(cells).toEqual(expectedCells);
});
it('should handle two concurrent courses', () => {
// These two cells must be in separate columns, because they are concurrent
const [cells, expectedCells] = makeCellsTest([
[13, 15, 2, 1, 2],
[14, 16, 2, 2, 3],
]);
calculateCourseCellColumns(cells);
expect(cells).toEqual(expectedCells);
});
it('should handle a simple grid', () => {
// Two columns
const [cells, expectedCells] = makeCellsTest([
[13, 15, 2, 1, 2], // start in left-most column
[15, 17, 2, 1, 2], // compact into left column
[13, 17, 2, 2, 3], // take up second column
]);
calculateCourseCellColumns(cells);
expect(cells).toEqual(expectedCells);
});
it('should handle a simple grid, flipped', () => {
// Ensures `totalColumns` is calculated correctly
const [cells, expectedCells] = makeCellsTest([
[13, 17, 2, 1, 2],
[15, 17, 2, 2, 3],
[13, 15, 2, 2, 3],
]);
calculateCourseCellColumns(cells);
expect(cells).toEqual(expectedCells);
});
it('should handle a weird grid', () => {
// Three columns
const [cells, expectedCells] = makeCellsTest([
[13, 15, 3, 1, 2],
[14, 18, 3, 2, 3],
[14, 16, 3, 3, 4],
[15, 17, 3, 1, 2], // compacted into left-most columns
]);
calculateCourseCellColumns(cells);
expect(cells).toEqual(expectedCells);
});
it('should handle many clean concurrent courses', () => {
// All cells here are concurrent, 8 columns
const [cells, expectedCells] = makeCellsTest([
[10, 16, 8, 1, 2],
[12, 16, 8, 2, 3],
[13, 16, 8, 3, 4],
[13, 16, 8, 4, 5],
[13, 19, 8, 5, 6],
[13, 19, 8, 6, 7],
[14, 18, 8, 7, 8],
[15, 19, 8, 8, 9],
]);
calculateCourseCellColumns(cells);
expect(cells).toEqual(expectedCells);
});
it('should handle many clean concurrent courses with one partially-concurrent', () => {
// Despite adding another course, we don't need to increase
// the number of columns, because we can compact
const [cells, expectedCells] = makeCellsTest([
[10, 16, 8, 1, 2],
[11, 15, 8, 2, 3], // new course, only overlaps with some
[12, 16, 8, 3, 4],
[13, 16, 8, 4, 5],
[13, 16, 8, 5, 6],
[13, 19, 8, 6, 7],
[13, 19, 8, 7, 8],
[14, 18, 8, 8, 9],
[15, 19, 8, 2, 3], // compacts to be under new course
]);
calculateCourseCellColumns(cells);
expect(cells).toEqual(expectedCells);
});
it("shouldn't crash on courses without times", () => {
const cells = [makeCell(-1, -1), makeCell(-1, -1)];
cells[1]!.async = true; // see if we can ignore async and non-async courses without times
const expectedCells = structuredClone<CalendarGridCourse[]>(cells);
calculateCourseCellColumns(cells);
expect(cells).toEqual(expectedCells);
});
});

View File

@@ -1,4 +1,5 @@
import { tz, TZDate } from '@date-fns/tz'; import { tz, TZDate } from '@date-fns/tz';
import exportSchedule from '@pages/background/lib/exportSchedule';
import { UserScheduleStore } from '@shared/storage/UserScheduleStore'; import { UserScheduleStore } from '@shared/storage/UserScheduleStore';
import type { Course } from '@shared/types/Course'; import type { Course } from '@shared/types/Course';
import type { CourseMeeting } from '@shared/types/CourseMeeting'; import type { CourseMeeting } from '@shared/types/CourseMeeting';
@@ -6,6 +7,7 @@ import Instructor from '@shared/types/Instructor';
import type { UserSchedule } from '@shared/types/UserSchedule'; import type { UserSchedule } from '@shared/types/UserSchedule';
import { downloadBlob } from '@shared/util/downloadBlob'; import { downloadBlob } from '@shared/util/downloadBlob';
import { englishStringifyList } from '@shared/util/string'; import { englishStringifyList } from '@shared/util/string';
import type { CalendarGridCourse } from '@views/hooks/useFlattenedCourseSchedule';
import type { Serialized } from 'chrome-extension-toolkit'; import type { Serialized } from 'chrome-extension-toolkit';
import type { DateArg, Day } from 'date-fns'; import type { DateArg, Day } from 'date-fns';
import { import {
@@ -260,6 +262,22 @@ export const saveAsCal = async () => {
downloadBlob(icsString, 'CALENDAR', 'schedule.ics'); downloadBlob(icsString, 'CALENDAR', 'schedule.ics');
}; };
/**
* Saves current schedule to JSON that can be imported on other devices.
* @param id - Provided schedule ID to download
*/
export const handleExportJson = async (id: string) => {
const jsonString = await exportSchedule(id);
if (jsonString) {
const schedules = await UserScheduleStore.get('schedules');
const schedule = schedules.find(s => s.id === id);
const fileName = `${schedule?.name ?? `schedule_${id}`}_${new Date().toISOString().replace(/[:.]/g, '-')}.json`;
await downloadBlob(jsonString, 'JSON', fileName);
} else {
console.error('Error exporting schedule: jsonString is undefined');
}
};
/** /**
* Saves the calendar as a PNG image. * Saves the calendar as a PNG image.
* *
@@ -315,3 +333,137 @@ export const saveCalAsPng = () => {
}); });
}); });
}; };
/**
* Determines all the connected components in the list of cells, where two cells
* are "connected" if there is a path (potentially through other cells) where
* each neighboring cells have overlapping start/end times
*
* @param cells - An array of cells to go on the calendar grid
* @returns An array of connected components, where the inner array is a list of
* all cells that there's a path to (potentially through other intervals)
* without crossing a time gap
*
* @remarks The internal fields cell.concurrentCells and cell.hasParent are
* modified by this function
*
* @example [[8am, 9am), [8:30am, 10am), [9:30am, 11am)] // is all one connected component
* @example [[8am, 9am), [8:30am, 10am), [10am, 11am)] // has two connected components, [[8am, 9am), [8:30am, 10am)] and [[10am, 11am)]]
*/
const findConnectedComponents = (cells: CalendarGridCourse[]): CalendarGridCourse[][] => {
const connectedComponents: CalendarGridCourse[][] = [];
for (let i = 0; i < cells.length; i++) {
const cell = cells[i]!;
if (!cell.concurrentCells || cell.concurrentCells.length === 0) {
// If this cell isn't already part of an existing connected component,
// then we need to make a new one.
connectedComponents.push([]);
}
connectedComponents.at(-1)!.push(cell);
for (let j = i + 1; j < cells.length; j++) {
const otherCell = cells[j]!;
if (otherCell.calendarGridPoint.startIndex >= cell.calendarGridPoint.endIndex) {
break;
}
// By ordering of cells array, we know cell.startTime <= other.startTime
// By the if check above, we know cell.endTime > other.endTime
// So, they're concurrent
// Also, by initializing j to i + 1, we know we don't have duplicates
cell.concurrentCells!.push(otherCell);
otherCell.concurrentCells!.push(cell);
}
}
return connectedComponents;
};
/**
* Assigns column positions to each cell in a set of calendar grid cells.
* Ensures that overlapping cells are placed in different columns.
*
* Inspired by the Greedy Interval-Partitioning algorithm.
*
* @param cells - An array of calendar grid course cells to position, must be
* sorted in increasing order of start time
* @throws Error if there's no available column for a cell (should never happen if totalColumns is calculated correctly)
* @remarks The number of columns created is strictly equal to the minimum needed by a perfectly optimal algorithm.
* The minimum number of columns needed is the maximum number of events that happen concurrently.
* Research Interval Graphs for more info https://en.wikipedia.org/wiki/Interval_graph
*/
const assignColumns = (cells: CalendarGridCourse[]) => {
const availableColumns = [true];
for (const cell of cells) {
availableColumns.fill(true);
for (const otherCell of cell.concurrentCells!) {
if (otherCell.gridColumnStart !== undefined) {
availableColumns[otherCell.gridColumnStart - 1] = false;
}
}
// Find an available column, or create one if all columns are full
let column = availableColumns.indexOf(true);
if (column === -1) {
column = availableColumns.length;
availableColumns.push(true);
}
// CSS Grid uses 1-based indexing
cell.gridColumnStart = column + 1;
cell.gridColumnEnd = column + 2;
}
for (const cell of cells) {
cell.totalColumns = availableColumns.length;
}
};
/**
* Calculates the column positions for course cells in a calendar grid.
* This function handles the layout algorithm for displaying overlapping course meetings
* in a calendar view. It identifies connected components of overlapping courses,
* determines the number of columns needed for each component, and assigns appropriate
* column positions to each cell.
*
* @param dayCells - An array of calendar grid course cells for a specific day
*/
export const calculateCourseCellColumns = (dayCells: CalendarGridCourse[]) => {
// Sort by start time, increasing
// This is necessary for the correctness of the column assignment
const cells = dayCells
.filter(
cell =>
!cell.async &&
cell.calendarGridPoint &&
typeof cell.calendarGridPoint.startIndex === 'number' &&
cell.calendarGridPoint.startIndex >= 0
)
.slice()
.sort((a, b) => a.calendarGridPoint.startIndex - b.calendarGridPoint.startIndex);
// Initialize metadata
for (const cell of cells) {
cell.concurrentCells = [];
cell.gridColumnStart = undefined;
cell.gridColumnEnd = undefined;
}
// Construct connected components, set concurrent neighbors
const connectedComponents = findConnectedComponents(cells);
// Assign columns for each connectedComponents
for (const cc of connectedComponents) {
assignColumns(cc);
}
// Clean up
for (const cell of cells) {
delete cell.concurrentCells;
}
};

View File

@@ -15,6 +15,11 @@
@apply font-sans; @apply font-sans;
color: #303030; color: #303030;
// fix font-family on injected pages
* {
@apply font-sans;
}
[data-rfd-drag-handle-context-id=':r1:'] { [data-rfd-drag-handle-context-id=':r1:'] {
cursor: move; cursor: move;
} }

View File

@@ -4,7 +4,7 @@ import type { ThemeColor } from '@shared/types/ThemeColors';
import { getThemeColorHexByName, getThemeColorRgbByName } from '@shared/util/themeColors'; import { getThemeColorHexByName, getThemeColorRgbByName } from '@shared/util/themeColors';
import Text from '@views/components/common/Text/Text'; import Text from '@views/components/common/Text/Text';
import clsx from 'clsx'; import clsx from 'clsx';
import React from 'react'; import React, { useEffect, useRef, useState } from 'react';
interface Props { interface Props {
className?: string; className?: string;
@@ -21,9 +21,8 @@ interface Props {
} }
/** /**
* A reusable input button component that follows the Button.tsx consistency * A reusable input button component that follows Button.tsx consistency.
* * Now supports drag-and-drop file uploads (issue #446).
* @returns
*/ */
export default function FileUpload({ export default function FileUpload({
className, className,
@@ -43,22 +42,74 @@ export default function FileUpload({
const isIconOnly = !children && !!icon; const isIconOnly = !children && !!icon;
const colorHex = getThemeColorHexByName(color); const colorHex = getThemeColorHexByName(color);
const colorRgb = getThemeColorRgbByName(color)?.join(' '); const colorRgb = getThemeColorRgbByName(color)?.join(' ');
const inputRef = useRef<HTMLInputElement>(null);
const [isDragging, setIsDragging] = useState(false);
// Convert accept to a comma-separated string if it's an array // Convert accept array to comma-separated list
const acceptValue = Array.isArray(accept) ? accept.join(',') : accept; const acceptValue = Array.isArray(accept) ? accept.join(',') : accept;
// --- Prevent Chrome from opening the file on drop anywhere else ---
useEffect(() => {
const preventDefault = (e: DragEvent) => {
e.preventDefault();
e.stopPropagation();
};
window.addEventListener('dragover', preventDefault);
window.addEventListener('drop', preventDefault);
return () => {
window.removeEventListener('dragover', preventDefault);
window.removeEventListener('drop', preventDefault);
};
}, []);
// ------------------------------------------------------------------
// --- Local drag and drop handlers for this button only -------------
const handleDrop = (event: React.DragEvent<HTMLLabelElement>) => {
event.preventDefault();
event.stopPropagation();
setIsDragging(false);
if (disabled) return;
const file = event.dataTransfer.files?.[0];
if (file && inputRef.current && onChange) {
const dataTransfer = new DataTransfer();
dataTransfer.items.add(file);
inputRef.current.files = dataTransfer.files;
// Trigger change event manually
onChange({ target: inputRef.current } as React.ChangeEvent<HTMLInputElement>);
}
};
const handleDragOver = (event: React.DragEvent<HTMLLabelElement>) => {
event.preventDefault();
event.stopPropagation();
if (!disabled) setIsDragging(true);
};
const handleDragLeave = (event: React.DragEvent<HTMLLabelElement>) => {
event.preventDefault();
event.stopPropagation();
setIsDragging(false);
};
// ------------------------------------------------------------------
return ( return (
<label <label
style={ onDrop={handleDrop}
{ onDragOver={handleDragOver}
...style, onDragLeave={handleDragLeave}
color: disabled ? 'ut-gray' : colorHex, style={{
backgroundColor: `rgb(${colorRgb} / var(--un-bg-opacity)`, ...style,
} satisfies React.CSSProperties color: disabled ? 'ut-gray' : colorHex,
} backgroundColor: `rgb(${colorRgb} / var(--un-bg-opacity))`,
}}
className={clsx( className={clsx(
'btn', 'btn transition-colors select-none',
{ {
'ring-2 ring-offset-2 ring-blue-400': isDragging && !disabled,
'text-white! bg-opacity-100 hover:enabled:shadow-md active:enabled:shadow-sm shadow-black/20': 'text-white! bg-opacity-100 hover:enabled:shadow-md active:enabled:shadow-sm shadow-black/20':
variant === 'filled', variant === 'filled',
'bg-opacity-0 border-current hover:enabled:bg-opacity-8 border stroke-width-[1px]': 'bg-opacity-0 border-current hover:enabled:bg-opacity-8 border stroke-width-[1px]':
@@ -70,6 +121,7 @@ export default function FileUpload({
'h-[35px] w-[35px] p-spacing-2': size === 'small' && isIconOnly, 'h-[35px] w-[35px] p-spacing-2': size === 'small' && isIconOnly,
'h-6 p-spacing-2': size === 'mini' && !isIconOnly, 'h-6 p-spacing-2': size === 'mini' && !isIconOnly,
'h-6 w-6 p-0': size === 'mini' && isIconOnly, 'h-6 w-6 p-0': size === 'mini' && isIconOnly,
'opacity-60 cursor-not-allowed': disabled,
}, },
className className
)} )}
@@ -85,6 +137,7 @@ export default function FileUpload({
</Text> </Text>
)} )}
<input <input
ref={inputRef}
type='file' type='file'
{...(accept ? { accept: acceptValue } : {})} {...(accept ? { accept: acceptValue } : {})}
className='hidden' className='hidden'

View File

@@ -34,7 +34,7 @@ export default function Link(props: PropsWithChildren<Props>): JSX.Element {
tabIndex={isDisabled ? -1 : 0} tabIndex={isDisabled ? -1 : 0}
className={clsx( className={clsx(
{ {
'underline cursor-pointer': !isDisabled, 'underline cursor-pointer p-2': !isDisabled,
'cursor-not-allowed color-ut-gray': isDisabled, 'cursor-not-allowed color-ut-gray': isDisabled,
}, },
className className

View File

@@ -19,12 +19,12 @@ export default function ScheduleDropdown({ defaultOpen, children }: ScheduleDrop
const [activeSchedule] = useSchedules(); const [activeSchedule] = useSchedules();
return ( return (
<div className='border border-ut-offwhite/50 rounded bg-white'> <div className='max-h-[200px] flex flex-col border border-ut-offwhite/50 rounded bg-white'>
<Disclosure defaultOpen={defaultOpen}> <Disclosure defaultOpen={defaultOpen}>
{({ open }) => ( {({ open }) => (
<> <>
<DisclosureButton className='w-full flex items-center border-none bg-transparent px-3.5 py-2.5 text-left'> <DisclosureButton className='w-full flex items-center border-none bg-transparent px-3.5 py-2.5 text-left'>
<div className='flex-1 min-w-0 overflow-hidden'> <div className='min-w-0 flex-1 overflow-hidden'>
<Text <Text
as='div' as='div'
variant='h3' variant='h3'
@@ -54,17 +54,17 @@ export default function ScheduleDropdown({ defaultOpen, children }: ScheduleDrop
<Transition <Transition
as='div' as='div'
className='overflow-hidden' className='flex flex-1 flex-col overflow-y-hidden'
enter='transition-[max-height,opacity,padding] duration-300 ease-in-out-expo' enter='transition-[max-height,opacity,padding] duration-300 ease-in-out-expo'
enterFrom='max-h-0 opacity-0 p-0.5' enterFrom='max-h-0 opacity-0 p-0.5'
enterTo='max-h-[440px] opacity-100 p-0' enterTo='max-h-[200px] opacity-100 p-0'
leave='transition-[max-height,opacity,padding] duration-300 ease-in-out-expo' leave='transition-[max-height,opacity,padding] duration-300 ease-in-out-expo'
leaveFrom='max-h-[440px] opacity-100 p-0' leaveFrom='max-h-[200px] opacity-100 p-0'
leaveTo='max-h-0 opacity-0 p-0.5' leaveTo='max-h-0 opacity-0 p-0.5'
> >
<div className='px-3.5 pb-2.5 pt-2'> <DisclosurePanel className='mx-1.75 mb-2.5 mt-2 flex flex-1 flex-col overflow-y-auto'>
<DisclosurePanel>{children}</DisclosurePanel> <div className='mx-1.75'>{children}</div>
</div> </DisclosurePanel>
</Transition> </Transition>
</> </>
)} )}

View File

@@ -1,6 +1,7 @@
import type { IconProps } from '@phosphor-icons/react'; import type { IconProps } from '@phosphor-icons/react';
import { CloudX, Copy, Exam, MapPinArea, Palette } from '@phosphor-icons/react'; import { CloudX, Coffee, ForkKnife, MapTrifold, Storefront } from '@phosphor-icons/react';
import { ExtensionStore } from '@shared/storage/ExtensionStore'; import { ExtensionStore } from '@shared/storage/ExtensionStore';
import { UT_DINING_PROMO_IMAGE_URL } from '@shared/util/appUrls';
import Text from '@views/components/common/Text/Text'; import Text from '@views/components/common/Text/Text';
import useWhatsNewPopUp from '@views/hooks/useWhatsNew'; import useWhatsNewPopUp from '@views/hooks/useWhatsNew';
import React, { useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
@@ -12,9 +13,9 @@ import React, { useEffect, useState } from 'react';
* *
* It should be incremented every time the "What's New" popup is updated. * It should be incremented every time the "What's New" popup is updated.
*/ */
const WHATSNEW_POPUP_VERSION = 1; const WHATSNEW_POPUP_VERSION = 2;
const WHATSNEW_VIDEO_URL = 'https://cdn.longhorns.dev/whats-new-v2.1.2.mp4'; // const WHATSNEW_VIDEO_URL = 'https://cdn.longhorns.dev/whats-new-v2.1.2.mp4';
type Feature = { type Feature = {
id: string; id: string;
@@ -25,35 +26,28 @@ type Feature = {
const NEW_FEATURES = [ const NEW_FEATURES = [
{ {
id: 'custom-course-colors', id: 'dining-halls-info',
icon: Palette, icon: ForkKnife,
title: 'Custom Course Colors', title: 'Dining Halls Info',
description: 'Paint your schedule in your favorite color theme', description: 'See daily menus and nutritional deets for J2, JCL, and Kins',
}, },
{ {
id: 'quick-copy', id: 'coffee-shops',
icon: Copy, icon: Coffee,
title: 'Quick Copy', title: 'Coffee Shops',
description: 'Quickly copy a course unique number to your clipboard', description: 'Need a Coffee Fix? Check operating times for your favorite campus cafes.',
}, },
{ {
id: 'updated-grades', id: 'convenience-stores',
icon: Exam, icon: Storefront,
title: 'Updated Grades', title: 'Convenience Stores',
description: 'Fall 2024 grades are now available in the grade distribution', description: 'Find hours for quick snacks and essentials on campus.',
}, },
{ {
id: 'ut-map', id: 'microwave-map',
icon: MapPinArea, icon: MapTrifold,
title: ( title: 'Microwave Map',
<div className='flex flex-row items-center'> description: 'Need to heat up your lunch? Find microwaves across campus!',
UTRP Map
<span className='mx-2 border border-ut-burntorange rounded px-2 py-0.5 text-xs text-ut-burntorange font-medium'>
BETA
</span>
</div>
),
description: 'Find directions to your classes with our beta map feature in the settings page',
}, },
] as const satisfies readonly Feature[]; ] as const satisfies readonly Feature[];
@@ -66,7 +60,7 @@ const NEW_FEATURES = [
* @returns A JSX of WhatsNewPopupContent component. * @returns A JSX of WhatsNewPopupContent component.
*/ */
export default function WhatsNewPopupContent(): JSX.Element { export default function WhatsNewPopupContent(): JSX.Element {
const [videoError, setVideoError] = useState(false); const [videoError, _setVideoError] = useState(false);
return ( return (
<div className='w-full flex flex-row justify-between'> <div className='w-full flex flex-row justify-between'>
@@ -97,14 +91,11 @@ export default function WhatsNewPopupContent(): JSX.Element {
</div> </div>
</div> </div>
) : ( ) : (
<video <img
className='h-fit w-full flex items-center justify-center border border-ut-offwhite/50 rounded object-cover' className='h-full w-full border border-ut-offwhite/50 rounded object-cover'
autoPlay src={UT_DINING_PROMO_IMAGE_URL}
loop alt='UT Dining Promo'
muted />
>
<source src={WHATSNEW_VIDEO_URL} type='video/mp4' onError={() => setVideoError(true)} />
</video>
)} )}
</div> </div>
</div> </div>

View File

@@ -1,6 +1,5 @@
import { addCourseByURL } from '@pages/background/lib/addCourseByURL'; import { addCourseByURL } from '@pages/background/lib/addCourseByURL';
import { background } from '@shared/messages'; import { background } from '@shared/messages';
import { validateLoginStatus } from '@shared/util/checkLoginStatus';
import { Button } from '@views/components/common/Button'; import { Button } from '@views/components/common/Button';
import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot'; import ExtensionRoot from '@views/components/common/ExtensionRoot/ExtensionRoot';
import useSchedules from '@views/hooks/useSchedules'; import useSchedules from '@views/hooks/useSchedules';
@@ -43,6 +42,8 @@ export default function InjectedButton(): JSX.Element | null {
await addCourseByURL(activeSchedule, a); await addCourseByURL(activeSchedule, a);
} }
} else { } else {
// We'll allow the alert for this WIP feature
// eslint-disable-next-line no-alert
window.alert('Logged into UT Registrar.'); window.alert('Logged into UT Registrar.');
} }
}; };

View File

@@ -215,7 +215,7 @@ export default function GradeDistribution({ course }: GradeDistributionProps): J
options={{ options={{
...chartOptions, ...chartOptions,
title: { title: {
text: `There is currently no grade distribution data for ${course.department} ${course.number}`, text: `There is currently no grade distribution data for ${course.department} ${course.getNumberWithoutTerm()}`,
}, },
tooltip: { enabled: false }, tooltip: { enabled: false },
}} }}
@@ -228,7 +228,7 @@ export default function GradeDistribution({ course }: GradeDistributionProps): J
<Text variant='small' className='text-ut-black'> <Text variant='small' className='text-ut-black'>
Grade Distribution for{' '} Grade Distribution for{' '}
<Text variant='small' className='font-extrabold!' as='strong'> <Text variant='small' className='font-extrabold!' as='strong'>
{course.department} {course.number} {course.department} {course.getNumberWithoutTerm()}
</Text> </Text>
</Text> </Text>
<select <select
@@ -267,7 +267,8 @@ export default function GradeDistribution({ course }: GradeDistributionProps): J
<div className='mt-3 flex flex-wrap content-center items-center self-stretch justify-center gap-3 text-center'> <div className='mt-3 flex flex-wrap content-center items-center self-stretch justify-center gap-3 text-center'>
<Text variant='small' className='text-theme-red'> <Text variant='small' className='text-theme-red'>
We couldn&apos;t find {semester !== 'Aggregate' && ` ${semester}`} grades for this We couldn&apos;t find {semester !== 'Aggregate' && ` ${semester}`} grades for this
instructor, so here are the grades for all {course.department} {course.number} sections. instructor, so here are the grades for all {course.department}{' '}
{course.getNumberWithoutTerm()} sections.
</Text> </Text>
</div> </div>
)} )}

View File

@@ -1,3 +1,5 @@
import createSchedule from '@pages/background/lib/createSchedule';
import switchSchedule from '@pages/background/lib/switchSchedule';
import { import {
ArrowUpRight, ArrowUpRight,
CalendarDots, CalendarDots,
@@ -14,8 +16,10 @@ import { background } from '@shared/messages';
import type { Course } from '@shared/types/Course'; import type { Course } from '@shared/types/Course';
import type Instructor from '@shared/types/Instructor'; import type Instructor from '@shared/types/Instructor';
import type { UserSchedule } from '@shared/types/UserSchedule'; import type { UserSchedule } from '@shared/types/UserSchedule';
import { englishStringifyList } from '@shared/util/string';
import { Button } from '@views/components/common/Button'; import { Button } from '@views/components/common/Button';
import { Chip, coreMap, flagMap } from '@views/components/common/Chip'; import { Chip, coreMap, flagMap } from '@views/components/common/Chip';
import { usePrompt } from '@views/components/common/DialogProvider/DialogProvider';
import Divider from '@views/components/common/Divider'; import Divider from '@views/components/common/Divider';
import Link from '@views/components/common/Link'; import Link from '@views/components/common/Link';
import Text from '@views/components/common/Text/Text'; import Text from '@views/components/common/Text/Text';
@@ -60,7 +64,7 @@ export default function HeadingAndActions({ course, activeSchedule, onClose }: H
const [isCopied, setIsCopied] = useState<boolean>(false); const [isCopied, setIsCopied] = useState<boolean>(false);
const lastCopyTime = useRef<number>(0); const lastCopyTime = useRef<number>(0);
const showDialog = usePrompt();
const getInstructorFullName = (instructor: Instructor) => instructor.toString({ format: 'first_last' }); const getInstructorFullName = (instructor: Instructor) => instructor.toString({ format: 'first_last' });
const handleCopy = async (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => { const handleCopy = async (e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
@@ -112,10 +116,78 @@ export default function HeadingAndActions({ course, activeSchedule, onClose }: H
} }
}; };
const handleAddToNewSchedule = async (close: () => void) => {
const newScheduleId = await createSchedule(`${course.semester.season} ${course.semester.year}`);
switchSchedule(newScheduleId);
addCourse({ course, scheduleId: newScheduleId });
close();
};
const handleAddOrRemoveCourse = async () => { const handleAddOrRemoveCourse = async () => {
const uniqueSemesterCodes = [
...new Set(
activeSchedule.courses
.map(course => course.semester.code)
.filter((code): code is string => code !== undefined)
),
];
uniqueSemesterCodes.sort();
const codeToReadableMap: Record<string, string> = {};
activeSchedule.courses.forEach(course => {
const { code } = course.semester;
if (code) {
const readable = `${course.semester.season} ${course.semester.year}`;
codeToReadableMap[code] = readable;
}
});
const sortedSemesters = uniqueSemesterCodes
.map(code => codeToReadableMap[code])
.filter((value): value is string => value !== undefined);
const activeSemesters = englishStringifyList(sortedSemesters);
if (!activeSchedule) return; if (!activeSchedule) return;
if (!courseAdded) { if (!courseAdded) {
addCourse({ course, scheduleId: activeSchedule.id }); const currentSemesterCode = course.semester.code;
// Show warning if this course is for a different semester than the selected schedule
if (
activeSchedule.courses.length > 0 &&
activeSchedule.courses.every(otherCourse => otherCourse.semester.code !== currentSemesterCode)
) {
const dialogButtons = (close: () => void) => (
<>
<Button variant='minimal' color='ut-black' onClick={close}>
Cancel
</Button>
<Button
variant='filled'
color='ut-burntorange'
onClick={() => {
handleAddToNewSchedule(close);
}}
>
Start a new schedule
</Button>
</>
);
showDialog({
title: 'This course section is from a different semester!',
description: (
<>
The section you&apos;re adding is for{' '}
<span className='whitespace-nowrap text-ut-burntorange'>
{course.semester.season} {course.semester.year}
</span>
, but your current schedule contains sections in{' '}
<span className='whitespace-nowrap text-ut-burntorange'>{activeSemesters}</span>. Mixing
semesters in one schedule may cause confusion.
</>
),
buttons: dialogButtons,
});
} else {
addCourse({ course, scheduleId: activeSchedule.id });
}
} else { } else {
removeCourse({ course, scheduleId: activeSchedule.id }); removeCourse({ course, scheduleId: activeSchedule.id });
} }

View File

@@ -0,0 +1,39 @@
import { useEffect } from 'react';
// @TODO Get a better name for this class
/**
* The existing search results (kws), only with alternate shading for easier readability
*
*/
export default function ShadedResults(): null {
useEffect(() => {
const table = document.getElementById('kw_results_table');
if (!table) {
console.error('Results table not found');
return;
}
const tbody = table.querySelector('tbody');
if (!tbody) {
console.error('Table tbody not found');
return;
}
const style = document.createElement('style');
style.textContent = `
#kw_results_table tbody tr:nth-child(even) {
background-color: #f0f0f0 !important;
}
#kw_results_table tbody tr:nth-child(even) td {
background-color: #f0f0f0 !important;
}
`;
document.head.appendChild(style);
return () => {
style.remove();
};
}, []);
return null;
}

View File

@@ -0,0 +1,197 @@
import { Trash } from '@phosphor-icons/react';
import { OptionsStore } from '@shared/storage/OptionsStore';
import MIMEType from '@shared/types/MIMEType';
import type { UserSchedule } from '@shared/types/UserSchedule';
import { handleExportJson } from '@views/components/calendar/utils';
import { Button } from '@views/components/common/Button';
import Divider from '@views/components/common/Divider';
import SwitchButton from '@views/components/common/SwitchButton';
import Text from '@views/components/common/Text/Text';
import clsx from 'clsx';
import React from 'react';
import FileUpload from '../common/FileUpload';
import { DISPLAY_PREVIEWS, PREVIEW_SECTION_DIV_CLASSNAME } from './constants';
import Preview from './Preview';
interface AdvancedSettingsProps {
highlightConflicts: boolean;
setHighlightConflicts: (value: boolean) => void;
loadAllCourses: boolean;
setLoadAllCourses: (value: boolean) => void;
increaseScheduleLimit: boolean;
setIncreaseScheduleLimit: (value: boolean) => void;
calendarNewTab: boolean;
setCalendarNewTab: (value: boolean) => void;
activeSchedule: UserSchedule;
handleEraseAll: () => void;
handleImportClick: (event: React.ChangeEvent<HTMLInputElement>) => Promise<void>;
}
/**
* Settings section component for advanced settings
*/
export const AdvancedSettings: React.FC<AdvancedSettingsProps> = ({
highlightConflicts,
setHighlightConflicts,
loadAllCourses,
setLoadAllCourses,
increaseScheduleLimit,
setIncreaseScheduleLimit,
calendarNewTab,
setCalendarNewTab,
activeSchedule,
handleEraseAll,
handleImportClick,
}) => (
<section className='mb-8'>
<h2 className='mb-4 text-xl text-ut-black font-semibold'>ADVANCED SETTINGS</h2>
<div className='flex space-x-4'>
<div className={PREVIEW_SECTION_DIV_CLASSNAME}>
<div className='flex items-center justify-between'>
<div className='max-w-xs'>
<Text variant='h4' className='text-ut-burntorange font-semibold'>
Export Current Schedule
</Text>
<p className='text-sm text-gray-600'>Backup your active schedule to a portable file</p>
</div>
<Button
variant='outline'
color='ut-burntorange'
onClick={() => handleExportJson(activeSchedule.id)}
>
Export
</Button>
</div>
<Divider size='auto' orientation='horizontal' />
<div className='flex items-center justify-between'>
<div className='max-w-xs'>
<Text variant='h4' className='text-ut-burntorange font-semibold'>
Import Schedule
</Text>
<p className='text-sm text-gray-600'>Import from a schedule file</p>
</div>
<FileUpload
variant='filled'
color='ut-burntorange'
onChange={handleImportClick}
accept={MIMEType.JSON}
>
Import Schedule
</FileUpload>
</div>
<Divider size='auto' orientation='horizontal' />
<div className='flex items-center justify-between'>
<div className='max-w-xs'>
<Text variant='h4' className='text-ut-burntorange font-semibold'>
Course Conflict Highlight
</Text>
<p className='text-sm text-gray-600'>
Adds a red strikethrough to courses that have conflicting times.
</p>
</div>
<SwitchButton
isChecked={highlightConflicts}
onChange={() => {
setHighlightConflicts(!highlightConflicts);
OptionsStore.set('enableHighlightConflicts', !highlightConflicts);
}}
/>
</div>
<Divider size='auto' orientation='horizontal' />
<div className='flex items-center justify-between'>
<div className='max-w-xs'>
<Text variant='h4' className='text-ut-burntorange font-semibold'>
Load All Courses in Course Schedule
</Text>
<p className='text-sm text-gray-600'>
Loads all courses in the Course Schedule site by scrolling, instead of using next/prev page
buttons.
</p>
</div>
<SwitchButton
isChecked={loadAllCourses}
onChange={() => {
setLoadAllCourses(!loadAllCourses);
OptionsStore.set('enableScrollToLoad', !loadAllCourses);
}}
/>
</div>
<Divider size='auto' orientation='horizontal' />
<div className='flex items-center justify-between'>
<div className='max-w-xs'>
<Text variant='h4' className='text-ut-burntorange font-semibold'>
Allow more than 10 schedules
</Text>
<p className='text-sm text-gray-600'>
Allow bypassing the 10-schedule limit. Intended for advisors or staff who need to create
many schedules on behalf of students.
</p>
</div>
<SwitchButton
isChecked={increaseScheduleLimit}
onChange={() => {
setIncreaseScheduleLimit(!increaseScheduleLimit);
OptionsStore.set('allowMoreSchedules', !increaseScheduleLimit);
}}
/>
</div>
<Divider size='auto' orientation='horizontal' />
<div className='flex items-center justify-between'>
<div className='max-w-xs'>
<Text variant='h4' className='text-ut-burntorange font-semibold'>
Always Open Calendar in New Tab
</Text>
<p className='text-sm text-gray-600'>
Always opens the calendar view in a new tab when navigating to the calendar page. May
prevent issues where the calendar refuses to open.
</p>
</div>
<SwitchButton
isChecked={calendarNewTab}
onChange={() => {
setCalendarNewTab(!calendarNewTab);
OptionsStore.set('alwaysOpenCalendarInNewTab', !calendarNewTab);
}}
/>
</div>
<Divider size='auto' orientation='horizontal' />
<div className='flex items-center justify-between'>
<div className='max-w-xs'>
<Text variant='h4' className='text-ut-burntorange font-semibold'>
Reset All Data
</Text>
<p className='text-sm text-gray-600'>Erases all schedules and courses you have.</p>
</div>
<Button variant='outline' color='theme-red' icon={Trash} onClick={handleEraseAll}>
Erase All
</Button>
</div>
</div>
{DISPLAY_PREVIEWS && (
<Preview>
<Text
variant='h2-course'
className={clsx('text-center text-theme-red font-normal', {
'line-through': highlightConflicts,
})}
>
01234 MWF 10:00 AM - 11:00 AM UTC 1.234
</Text>
</Preview>
)}
</div>
</section>
);

View File

@@ -0,0 +1,54 @@
import Text from '@views/components/common/Text/Text';
import React from 'react';
interface ContributorCardProps {
name: string;
githubUsername: string;
roles: string[];
stats?: {
commits: number;
linesAdded: number;
linesDeleted: number;
mergedPRs?: number;
};
showStats: boolean;
includeMergedPRs: boolean;
}
/**
* GitHub contributor card component
*/
export const ContributorCard: React.FC<ContributorCardProps> = ({
name,
githubUsername,
roles,
stats,
showStats,
includeMergedPRs,
}) => (
<div className='border border-gray-300 rounded bg-ut-gray/10 p-4'>
<Text
variant='p'
className='text-ut-burntorange font-semibold hover:cursor-pointer'
onClick={() => window.open(`https://github.com/${githubUsername}`, '_blank')}
>
{name}
</Text>
{roles.map(role => (
<p key={`${githubUsername}-${role}`} className='text-sm text-gray-600'>
{role}
</p>
))}
{showStats && stats && (
<div className='mt-2'>
<p className='text-xs text-gray-500'>GitHub Stats (UTRP repo):</p>
{includeMergedPRs && stats.mergedPRs !== undefined && (
<p className='text-xs'>Merged PRs: {stats.mergedPRs}</p>
)}
<p className='text-xs'>Commits: {stats.commits}</p>
<p className='text-xs text-ut-green'>{stats.linesAdded}++</p>
<p className='text-xs text-theme-red'>{stats.linesDeleted}--</p>
</div>
)}
</div>
);

View File

@@ -1,116 +1,68 @@
// import addCourse from '@pages/background/lib/addCourse'; // Pages
import { addCourseByURL } from '@pages/background/lib/addCourseByURL'; import { addCourseByURL } from '@pages/background/lib/addCourseByURL';
import { deleteAllSchedules } from '@pages/background/lib/deleteSchedule'; import { deleteAllSchedules } from '@pages/background/lib/deleteSchedule';
import exportSchedule from '@pages/background/lib/exportSchedule';
import importSchedule from '@pages/background/lib/importSchedule'; import importSchedule from '@pages/background/lib/importSchedule';
import { CalendarDots, Trash } from '@phosphor-icons/react'; import { CalendarDots } from '@phosphor-icons/react';
// Shared
import { background } from '@shared/messages'; import { background } from '@shared/messages';
import { DevStore } from '@shared/storage/DevStore'; import { DevStore } from '@shared/storage/DevStore';
import { initSettings, OptionsStore } from '@shared/storage/OptionsStore'; import { initSettings, OptionsStore } from '@shared/storage/OptionsStore';
import { UserScheduleStore } from '@shared/storage/UserScheduleStore';
import { CRX_PAGES } from '@shared/types/CRXPages'; import { CRX_PAGES } from '@shared/types/CRXPages';
import MIMEType from '@shared/types/MIMEType'; import Particles from '@tsparticles/react';
import { downloadBlob } from '@shared/util/downloadBlob';
// import { addCourseByUrl } from '@shared/util/courseUtils';
// import { getCourseColors } from '@shared/util/colors';
// import CalendarCourseCell from '@views/components/calendar/CalendarCourseCell';
import { Button } from '@views/components/common/Button'; import { Button } from '@views/components/common/Button';
import { usePrompt } from '@views/components/common/DialogProvider/DialogProvider'; import { usePrompt } from '@views/components/common/DialogProvider/DialogProvider';
// Views
import Divider from '@views/components/common/Divider'; import Divider from '@views/components/common/Divider';
import { LargeLogo } from '@views/components/common/LogoIcon'; import { LargeLogo } from '@views/components/common/LogoIcon';
// import PopupCourseBlock from '@views/components/common/PopupCourseBlock';
import SwitchButton from '@views/components/common/SwitchButton';
import Text from '@views/components/common/Text/Text'; import Text from '@views/components/common/Text/Text';
// Hooks
import useChangelog from '@views/hooks/useChangelog'; import useChangelog from '@views/hooks/useChangelog';
import useSchedules from '@views/hooks/useSchedules'; import useSchedules from '@views/hooks/useSchedules';
// import { CourseCatalogScraper } from '@views/lib/CourseCatalogScraper';
// import getCourseTableRows from '@views/lib/getCourseTableRows';
import { GitHubStatsService, LONGHORN_DEVELOPERS_ADMINS, LONGHORN_DEVELOPERS_SWE } from '@views/lib/getGitHubStats'; import { GitHubStatsService, LONGHORN_DEVELOPERS_ADMINS, LONGHORN_DEVELOPERS_SWE } from '@views/lib/getGitHubStats';
// import { SiteSupport } from '@views/lib/getSiteSupport'; // Misc
import clsx from 'clsx'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import React, { useCallback, useEffect, useState } from 'react';
// Icons
import IconoirGitFork from '~icons/iconoir/git-fork'; import IconoirGitFork from '~icons/iconoir/git-fork';
// import { ExampleCourse } from 'src/stories/components/ConflictsWithWarning.stories';;
import FileUpload from '../common/FileUpload';
import { useMigrationDialog } from '../common/MigrationDialog'; import { useMigrationDialog } from '../common/MigrationDialog';
// import RefreshIcon from '~icons/material-symbols/refresh'; import { AdvancedSettings } from './AdvancedSettings';
import { DEV_MODE_CLICK_TARGET, INCLUDE_MERGED_PRS, STATS_TOGGLE_KEY } from './constants';
import { ContributorCard } from './ContributorCard';
import DevMode from './DevMode'; import DevMode from './DevMode';
import Preview from './Preview'; import { useBirthdayCelebration } from './useBirthdayCelebration';
import { useDevMode } from './useDevMode';
const manifest = chrome.runtime.getManifest(); const manifest = chrome.runtime.getManifest();
const gitHubStatsService = new GitHubStatsService();
const includeMergedPRs = false;
const DISPLAY_PREVIEWS = false;
const PREVIEW_SECTION_DIV_CLASSNAME = DISPLAY_PREVIEWS ? 'w-1/2 space-y-4' : 'flex-grow space-y-4';
/** /**
* Custom hook for enabling developer mode. * Main Settings Component for managing user settings and preferences.
*
* @param targetCount - The target count to activate developer mode.
* @returns A tuple containing a boolean indicating if developer mode is active and a function to increment the count.
*/
const useDevMode = (targetCount: number): [boolean, () => void] => {
const [count, setCount] = useState(0);
const [active, setActive] = useState(false);
const [lastClick, setLastClick] = useState(0);
const incrementCount = useCallback(() => {
const now = Date.now();
if (now - lastClick < 500) {
setCount(prevCount => {
const newCount = prevCount + 1;
if (newCount === targetCount) {
setActive(true);
}
return newCount;
});
} else {
setCount(1);
}
setLastClick(now);
}, [lastClick, targetCount]);
useEffect(() => {
const timer = setTimeout(() => setCount(0), 3000);
return () => clearTimeout(timer);
}, [count]);
return [active, incrementCount];
};
/**
* Component for managing user settings and preferences.
* *
* @returns The Settings component. * @returns The Settings component.
*/ */
export default function Settings(): JSX.Element { export default function Settings(): JSX.Element {
const [_enableCourseStatusChips, setEnableCourseStatusChips] = useState<boolean>(false); const gitHubStatsService = useMemo(() => new GitHubStatsService(), []);
// const [_showTimeLocation, setShowTimeLocation] = useState<boolean>(false);
const [highlightConflicts, setHighlightConflicts] = useState<boolean>(false);
const [loadAllCourses, setLoadAllCourses] = useState<boolean>(false);
const [_enableDataRefreshing, setEnableDataRefreshing] = useState<boolean>(false);
const [calendarNewTab, setCalendarNewTab] = useState<boolean>(false);
const showMigrationDialog = useMigrationDialog(); // State
const [highlightConflicts, setHighlightConflicts] = useState(false);
// Toggle GitHub stats when the user presses the 'S' key const [loadAllCourses, setLoadAllCourses] = useState(false);
const [showGitHubStats, setShowGitHubStats] = useState<boolean>(false); const [calendarNewTab, setCalendarNewTab] = useState(false);
const [increaseScheduleLimit, setIncreaseScheduleLimit] = useState(false);
const [showGitHubStats, setShowGitHubStats] = useState(false);
const [githubStats, setGitHubStats] = useState<Awaited< const [githubStats, setGitHubStats] = useState<Awaited<
ReturnType<typeof gitHubStatsService.fetchGitHubStats> ReturnType<typeof gitHubStatsService.fetchGitHubStats>
> | null>(null); > | null>(null);
const [isDeveloper, setIsDeveloper] = useState(false);
const [activeSchedule] = useSchedules(); const [activeSchedule] = useSchedules();
// const [isRefreshing, setIsRefreshing] = useState<boolean>(false);
const [isDeveloper, setIsDeveloper] = useState<boolean>(false);
const showDialog = usePrompt(); const showDialog = usePrompt();
const handleChangelogOnClick = useChangelog(); const handleChangelogOnClick = useChangelog();
const showMigrationDialog = useMigrationDialog();
const [devMode, toggleDevMode] = useDevMode(DEV_MODE_CLICK_TARGET);
const { showParticles, particlesInit, particlesOptions, triggerCelebration, isBirthday } = useBirthdayCelebration();
// Initialize settings and listeners
useEffect(() => { useEffect(() => {
const fetchGitHubStats = async () => { const fetchGitHubStats = async () => {
try { try {
@@ -122,19 +74,12 @@ export default function Settings(): JSX.Element {
}; };
const initAndSetSettings = async () => { const initAndSetSettings = async () => {
const { const { enableHighlightConflicts, enableScrollToLoad, alwaysOpenCalendarInNewTab, allowMoreSchedules } =
enableCourseStatusChips, await initSettings();
enableHighlightConflicts,
enableScrollToLoad,
enableDataRefreshing,
alwaysOpenCalendarInNewTab,
} = await initSettings();
setEnableCourseStatusChips(enableCourseStatusChips);
// setShowTimeLocation(enableTimeAndLocationInPopup);
setHighlightConflicts(enableHighlightConflicts); setHighlightConflicts(enableHighlightConflicts);
setLoadAllCourses(enableScrollToLoad); setLoadAllCourses(enableScrollToLoad);
setEnableDataRefreshing(enableDataRefreshing);
setCalendarNewTab(alwaysOpenCalendarInNewTab); setCalendarNewTab(alwaysOpenCalendarInNewTab);
setIncreaseScheduleLimit(allowMoreSchedules);
}; };
const initDS = async () => { const initDS = async () => {
@@ -142,68 +87,50 @@ export default function Settings(): JSX.Element {
setIsDeveloper(isDev); setIsDeveloper(isDev);
}; };
const handleKeyPress = (event: KeyboardEvent) => {
if (event.key === STATS_TOGGLE_KEY || event.key === STATS_TOGGLE_KEY.toUpperCase()) {
setShowGitHubStats(prev => !prev);
}
};
// Listeners
const ds_l1 = DevStore.listen('isDeveloper', async ({ newValue }) => { const ds_l1 = DevStore.listen('isDeveloper', async ({ newValue }) => {
setIsDeveloper(newValue); setIsDeveloper(newValue);
}); });
const l1 = OptionsStore.listen('enableHighlightConflicts', async ({ newValue }) => {
setHighlightConflicts(newValue);
});
const l2 = OptionsStore.listen('enableScrollToLoad', async ({ newValue }) => {
setLoadAllCourses(newValue);
});
const l3 = OptionsStore.listen('alwaysOpenCalendarInNewTab', async ({ newValue }) => {
setCalendarNewTab(newValue);
});
const l4 = OptionsStore.listen('allowMoreSchedules', async ({ newValue }) => {
setIncreaseScheduleLimit(newValue);
});
window.addEventListener('keydown', handleKeyPress);
initDS(); initDS();
fetchGitHubStats(); fetchGitHubStats();
initAndSetSettings(); initAndSetSettings();
const handleKeyPress = (event: KeyboardEvent) => {
if (event.key === 'S' || event.key === 's') {
setShowGitHubStats(prev => !prev);
}
};
window.addEventListener('keydown', handleKeyPress);
// Listen for changes in the settings
const l1 = OptionsStore.listen('enableCourseStatusChips', async ({ newValue }) => {
setEnableCourseStatusChips(newValue);
// console.log('enableCourseStatusChips', newValue);
});
// const l2 = OptionsStore.listen('enableTimeAndLocationInPopup', async ({ newValue }) => {
// setShowTimeLocation(newValue);
// // console.log('enableTimeAndLocationInPopup', newValue);
// });
const l2 = OptionsStore.listen('enableHighlightConflicts', async ({ newValue }) => {
setHighlightConflicts(newValue);
// console.log('enableHighlightConflicts', newValue);
});
const l3 = OptionsStore.listen('enableScrollToLoad', async ({ newValue }) => {
setLoadAllCourses(newValue);
// console.log('enableScrollToLoad', newValue);
});
const l4 = OptionsStore.listen('enableDataRefreshing', async ({ newValue }) => {
setEnableDataRefreshing(newValue);
// console.log('enableDataRefreshing', newValue);
});
const l5 = OptionsStore.listen('alwaysOpenCalendarInNewTab', async ({ newValue }) => {
setCalendarNewTab(newValue);
// console.log('alwaysOpenCalendarInNewTab', newValue);
});
// Remove listeners when the component is unmounted
return () => { return () => {
OptionsStore.removeListener(l1); OptionsStore.removeListener(l1);
OptionsStore.removeListener(l2); OptionsStore.removeListener(l2);
OptionsStore.removeListener(l3); OptionsStore.removeListener(l3);
OptionsStore.removeListener(l4); OptionsStore.removeListener(l4);
OptionsStore.removeListener(l5);
DevStore.removeListener(ds_l1); DevStore.removeListener(ds_l1);
window.removeEventListener('keydown', handleKeyPress); window.removeEventListener('keydown', handleKeyPress);
}; };
}, []); }, [gitHubStatsService]);
const handleEraseAll = () => { const handleEraseAll = useCallback(() => {
showDialog({ showDialog({
title: 'Erase All Course/Schedule Data', title: 'Erase All Course/Schedule Data',
description: ( description: (
@@ -230,46 +157,45 @@ export default function Settings(): JSX.Element {
</Button> </Button>
), ),
}); });
}; }, [showDialog]);
const handleExportClick = async (id: string) => { const handleImportClick = useCallback(async (event: React.ChangeEvent<HTMLInputElement>) => {
const jsonString = await exportSchedule(id);
if (jsonString) {
const schedules = await UserScheduleStore.get('schedules');
const schedule = schedules.find(s => s.id === id);
const fileName = `${schedule?.name ?? `schedule_${id}`}_${new Date().toISOString().replace(/[:.]/g, '-')}.json`;
await downloadBlob(jsonString, 'JSON', fileName);
} else {
console.error('Error exporting schedule: jsonString is undefined');
}
};
const handleImportClick = async (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0]; const file = event.target.files?.[0];
if (file) { if (!file) return;
const reader = new FileReader();
reader.onload = async e => { try {
try { const text = await file.text();
const result = e.target?.result as string; const data = JSON.parse(text);
const jsonObject = JSON.parse(result); await importSchedule(data);
await importSchedule(jsonObject); alert('Schedule imported successfully.');
} catch (error) { } catch (error) {
console.error('Invalid import file!'); console.error('Error importing schedule:', error);
} alert('Failed to import schedule. Make sure the file is a valid .json format.');
};
reader.readAsText(file);
} }
}; }, []);
// const handleAddCourseByLink = async () => { const sortedContributors = useMemo(() => {
// // todo: Use a proper modal instead of a prompt if (!githubStats) return LONGHORN_DEVELOPERS_SWE;
// const link: string | null = prompt('Enter course link'); return [...LONGHORN_DEVELOPERS_SWE].sort(
// // Exit if the user cancels the prompt (a, b) =>
// if (link === null) return; (githubStats.userGitHubStats[b.githubUsername]?.commits ?? 0) -
// await addCourseByUrl(link, activeSchedule); (githubStats.userGitHubStats[a.githubUsername]?.commits ?? 0)
// }; );
}, [githubStats]);
const [devMode, toggleDevMode] = useDevMode(10); const additionalContributors = useMemo(() => {
if (!githubStats) return [];
return Object.keys(githubStats.userGitHubStats)
.filter(
username =>
!LONGHORN_DEVELOPERS_ADMINS.some(admin => admin.githubUsername === username) &&
!LONGHORN_DEVELOPERS_SWE.some(swe => swe.githubUsername === username)
)
.sort(
(a, b) =>
(githubStats.userGitHubStats[b]?.commits ?? 0) - (githubStats.userGitHubStats[a]?.commits ?? 0)
);
}, [githubStats]);
if (devMode) { if (devMode) {
DevStore.set('isDeveloper', true); DevStore.set('isDeveloper', true);
@@ -277,13 +203,32 @@ export default function Settings(): JSX.Element {
} }
return ( return (
<div> <div className='relative'>
{particlesInit && showParticles && (
<Particles
id='birthday-particles'
options={particlesOptions}
className='pointer-events-none absolute inset-0 z-50'
/>
)}
<header className='flex items-center gap-5 overflow-x-auto overflow-y-hidden border-b border-ut-offwhite px-7 py-4 md:overflow-x-hidden'> <header className='flex items-center gap-5 overflow-x-auto overflow-y-hidden border-b border-ut-offwhite px-7 py-4 md:overflow-x-hidden'>
<LargeLogo /> <LargeLogo />
<Divider className='mx-2 self-center md:mx-4' size='2.5rem' orientation='vertical' /> <Divider className='mx-2 self-center md:mx-4' size='2.5rem' orientation='vertical' />
<Text variant='h1' className='flex-1 text-ut-burntorange normal-case!'> <div className='flex flex-1 items-center gap-2'>
Settings and Credits <Text variant='h1' className='text-ut-burntorange normal-case'>
</Text> Settings and Credits
</Text>
{isBirthday && (
<span
onClick={triggerCelebration}
className='cursor-pointer px-4 text-sm text-ut-burntorange transition-transform hover:scale-110'
title='Click to celebrate!'
>
🎉 Happy Birthday LHD! 🎉
</span>
)}
</div>
<div className='hidden flex-row items-center justify-end gap-6 screenshot:hidden lg:flex'> <div className='hidden flex-row items-center justify-end gap-6 screenshot:hidden lg:flex'>
<Button variant='minimal' color='theme-black' onClick={handleChangelogOnClick}> <Button variant='minimal' color='theme-black' onClick={handleChangelogOnClick}>
<IconoirGitFork className='h-6 w-6 text-ut-gray' /> <IconoirGitFork className='h-6 w-6 text-ut-gray' />
@@ -304,219 +249,19 @@ export default function Settings(): JSX.Element {
<div className='p-6 lg:flex'> <div className='p-6 lg:flex'>
<div className='mr-4 lg:w-1/2 xl:w-xl'> <div className='mr-4 lg:w-1/2 xl:w-xl'>
{/* <section className='mb-8'> <AdvancedSettings
<h2 className='mb-4 text-xl text-ut-black font-semibold'>CUSTOMIZATION OPTIONS</h2> highlightConflicts={highlightConflicts}
<div className='flex space-x-4'> setHighlightConflicts={setHighlightConflicts}
<div className='w-1/2 space-y-4'> loadAllCourses={loadAllCourses}
<div className='flex items-center justify-between'> setLoadAllCourses={setLoadAllCourses}
<div className='max-w-xs'> increaseScheduleLimit={increaseScheduleLimit}
<h3 className='text-ut-burntorange font-semibold'>Show Course Status</h3> setIncreaseScheduleLimit={setIncreaseScheduleLimit}
<p className='text-sm text-gray-600'> calendarNewTab={calendarNewTab}
Shows an indicator for waitlisted, cancelled, and closed courses. setCalendarNewTab={setCalendarNewTab}
</p> activeSchedule={activeSchedule}
</div> handleEraseAll={handleEraseAll}
<SwitchButton handleImportClick={handleImportClick}
isChecked={enableCourseStatusChips} />
onChange={() => {
setEnableCourseStatusChips(!enableCourseStatusChips);
OptionsStore.set('enableCourseStatusChips', !enableCourseStatusChips);
}}
/>
</div>
<Divider size='auto' orientation='horizontal' />
<div className='flex items-center justify-between'>
<div className='max-w-xs'>
<h3 className='text-ut-burntorange font-semibold'>
Show Time & Location in Popup
</h3>
<p className='text-sm text-gray-600'>
Shows the course&apos;s time and location in the extension&apos;s popup.
</p>
</div>
<SwitchButton
isChecked={showTimeLocation}
onChange={() => {
setShowTimeLocation(!showTimeLocation);
OptionsStore.set('enableTimeAndLocationInPopup', !showTimeLocation);
}}
/>
</div>
</div>
{DISPLAY_PREVIEWS && (
<Preview>
<CalendarCourseCell
colors={getCourseColors('orange')}
courseDeptAndInstr={ExampleCourse.department}
className={ExampleCourse.number}
status={ExampleCourse.status}
timeAndLocation={ExampleCourse.schedule.meetings[0]!.getTimeString({
separator: '-',
})}
/>
<PopupCourseBlock colors={getCourseColors('orange')} course={ExampleCourse} />
</Preview>
)}
</div>
</section>
<Divider size='auto' orientation='horizontal' /> */}
<section className='mb-8'>
<h2 className='mb-4 text-xl text-ut-black font-semibold'>ADVANCED SETTINGS</h2>
<div className='flex space-x-4'>
<div className={PREVIEW_SECTION_DIV_CLASSNAME}>
{/* <div className='flex items-center justify-between'>
<div className='max-w-xs'>
<h3 className='text-ut-burntorange font-semibold'>Refresh Data</h3>
<p className='text-sm text-gray-600'>
Refreshes waitlist, course status, and other info with the latest data from
UT&apos;s site.
</p>
</div>
<Button
variant='outline'
color='ut-black'
icon={RefreshIcon}
onClick={() => console.log('Refresh clicked')}
disabled={!enableDataRefreshing}
>
Refresh
</Button>
</div>
<Divider size='auto' orientation='horizontal' /> */}
<div className='flex items-center justify-between'>
<div className='max-w-xs'>
<Text variant='h4' className='text-ut-burntorange font-semibold'>
Export Current Schedule
</Text>
<p className='text-sm text-gray-600'>
Backup your active schedule to a portable file
</p>
</div>
<Button
variant='outline'
color='ut-burntorange'
onClick={() => handleExportClick(activeSchedule.id)}
>
Export
</Button>
</div>
<Divider size='auto' orientation='horizontal' />
<div className='flex items-center justify-between'>
<div className='max-w-xs'>
<Text variant='h4' className='text-ut-burntorange font-semibold'>
Import Schedule
</Text>
<p className='text-sm text-gray-600'>Import from a schedule file</p>
</div>
<FileUpload
variant='filled'
color='ut-burntorange'
onChange={handleImportClick}
accept={MIMEType.JSON}
>
Import Schedule
</FileUpload>
</div>
<Divider size='auto' orientation='horizontal' />
<div className='flex items-center justify-between'>
<div className='max-w-xs'>
<Text variant='h4' className='text-ut-burntorange font-semibold'>
Course Conflict Highlight
</Text>
<p className='text-sm text-gray-600'>
Adds a red strikethrough to courses that have conflicting times.
</p>
</div>
<SwitchButton
isChecked={highlightConflicts}
onChange={() => {
setHighlightConflicts(!highlightConflicts);
OptionsStore.set('enableHighlightConflicts', !highlightConflicts);
}}
/>
</div>
<Divider size='auto' orientation='horizontal' />
<div className='flex items-center justify-between'>
<div className='max-w-xs'>
<Text variant='h4' className='text-ut-burntorange font-semibold'>
Load All Courses in Course Schedule
</Text>
<p className='text-sm text-gray-600'>
Loads all courses in the Course Schedule site by scrolling, instead of using
next/prev page buttons.
</p>
</div>
<SwitchButton
isChecked={loadAllCourses}
onChange={() => {
setLoadAllCourses(!loadAllCourses);
OptionsStore.set('enableScrollToLoad', !loadAllCourses);
}}
/>
</div>
<Divider size='auto' orientation='horizontal' />
<div className='flex items-center justify-between'>
<div className='max-w-xs'>
<Text variant='h4' className='text-ut-burntorange font-semibold'>
Always Open Calendar in New Tab
</Text>
<p className='text-sm text-gray-600'>
Always opens the calendar view in a new tab when navigating to the calendar
page. May prevent issues where the calendar refuses to open.
</p>
</div>
<SwitchButton
isChecked={calendarNewTab}
onChange={() => {
setCalendarNewTab(!calendarNewTab);
OptionsStore.set('alwaysOpenCalendarInNewTab', !calendarNewTab);
}}
/>
</div>
<Divider size='auto' orientation='horizontal' />
<div className='flex items-center justify-between'>
<div className='max-w-xs'>
<Text variant='h4' className='text-ut-burntorange font-semibold'>
Reset All Data
</Text>
<p className='text-sm text-gray-600'>
Erases all schedules and courses you have.
</p>
</div>
<Button variant='outline' color='theme-red' icon={Trash} onClick={handleEraseAll}>
Erase All
</Button>
</div>
</div>
{DISPLAY_PREVIEWS && (
<Preview>
<Text
variant='h2-course'
className={clsx('text-center text-theme-red !font-normal', {
'line-through': highlightConflicts,
})}
>
01234 MWF 10:00 AM - 11:00 AM UTC 1.234
</Text>
</Preview>
)}
</div>
</section>
<Divider size='auto' orientation='horizontal' /> <Divider size='auto' orientation='horizontal' />
@@ -577,17 +322,21 @@ export default function Settings(): JSX.Element {
Open Debug Page Open Debug Page
</Button> </Button>
</div> </div>
<Divider size='auto' orientation='horizontal' />
<Button
variant='filled'
color='ut-black'
onClick={() => addCourseByURL(activeSchedule)}
>
Add course by link
</Button>
<Button variant='filled' color='ut-burntorange' onClick={showMigrationDialog}>
Show Migration Dialog
</Button>
</> </>
)} )}
<Divider size='auto' orientation='horizontal' />
<Button variant='filled' color='ut-black' onClick={() => addCourseByURL(activeSchedule)}>
Add course by link
</Button>
<Button variant='filled' color='ut-burntorange' onClick={showMigrationDialog}>
Show Migration Dialog
</Button>
</section> </section>
</div> </div>
@@ -600,144 +349,44 @@ export default function Settings(): JSX.Element {
</h2> </h2>
<div className='grid grid-cols-2 gap-4 2xl:grid-cols-4 md:grid-cols-3'> <div className='grid grid-cols-2 gap-4 2xl:grid-cols-4 md:grid-cols-3'>
{LONGHORN_DEVELOPERS_ADMINS.map(admin => ( {LONGHORN_DEVELOPERS_ADMINS.map(admin => (
<div <ContributorCard
key={admin.githubUsername} key={admin.githubUsername}
className='border border-gray-300 rounded bg-ut-gray/10 p-4' name={admin.name}
> githubUsername={admin.githubUsername}
<Text roles={admin.role}
variant='p' stats={githubStats?.adminGitHubStats[admin.githubUsername]}
className='text-ut-burntorange font-semibold hover:cursor-pointer' showStats={showGitHubStats}
onClick={() => includeMergedPRs={INCLUDE_MERGED_PRS}
window.open(`https://github.com/${admin.githubUsername}`, '_blank') />
}
>
{admin.name}
</Text>
{admin.role.map(role => (
<p key={admin.githubUsername} className='text-sm text-gray-600'>
{role}
</p>
))}
{showGitHubStats && githubStats && (
<div className='mt-2'>
<p className='text-xs text-gray-500'>GitHub Stats (UTRP repo):</p>
{includeMergedPRs && (
<p className='text-xs'>
Merged PRS:{' '}
{githubStats.adminGitHubStats[admin.githubUsername]?.mergedPRs}
</p>
)}
<p className='text-xs'>
Commits: {githubStats.adminGitHubStats[admin.githubUsername]?.commits}
</p>
<p className='text-xs text-ut-green'>
{githubStats.adminGitHubStats[admin.githubUsername]?.linesAdded} ++
</p>
<p className='text-xs text-theme-red'>
{githubStats.adminGitHubStats[admin.githubUsername]?.linesDeleted} --
</p>
</div>
)}
</div>
))} ))}
</div> </div>
</section> </section>
<section className='my-8'> <section className='my-8'>
<h2 className='mb-4 text-xl text-ut-black font-semibold'>UTRP CONTRIBUTORS</h2> <h2 className='mb-4 text-xl text-ut-black font-semibold'>UTRP CONTRIBUTORS</h2>
<div className='grid grid-cols-2 gap-4 2xl:grid-cols-4 md:grid-cols-3 xl:grid-cols-3'> <div className='grid grid-cols-2 gap-4 2xl:grid-cols-4 md:grid-cols-3 xl:grid-cols-3'>
{LONGHORN_DEVELOPERS_SWE.sort( {sortedContributors.map(swe => (
(a, b) => <ContributorCard
(githubStats?.userGitHubStats[b.githubUsername]?.commits ?? 0) -
(githubStats?.userGitHubStats[a.githubUsername]?.commits ?? 0)
).map(swe => (
<div
key={swe.githubUsername} key={swe.githubUsername}
className='border border-gray-300 rounded bg-ut-gray/10 p-4' name={swe.name}
> githubUsername={swe.githubUsername}
<Text roles={swe.role}
variant='p' stats={githubStats?.userGitHubStats[swe.githubUsername]}
className='text-ut-burntorange font-semibold hover:cursor-pointer' showStats={showGitHubStats}
onClick={() => includeMergedPRs={INCLUDE_MERGED_PRS}
window.open(`https://github.com/${swe.githubUsername}`, '_blank') />
} ))}
> {additionalContributors.map(username => (
{swe.name} <ContributorCard
</Text> key={username}
{swe.role.map(role => ( name={githubStats!.names[username] || username}
<p key={swe.githubUsername} className='text-sm text-gray-600'> githubUsername={username}
{role} roles={['Contributor']}
</p> stats={githubStats!.userGitHubStats[username]}
))} showStats={showGitHubStats}
{showGitHubStats && githubStats && ( includeMergedPRs={INCLUDE_MERGED_PRS}
<div className='mt-2'> />
<p className='text-xs text-gray-500'>GitHub Stats (UTRP repo):</p>
{includeMergedPRs && (
<p className='text-xs'>
Merged PRS:{' '}
{githubStats.userGitHubStats[swe.githubUsername]?.mergedPRs}
</p>
)}
<p className='text-xs'>
Commits: {githubStats.userGitHubStats[swe.githubUsername]?.commits}
</p>
<p className='text-xs text-ut-green'>
{githubStats.userGitHubStats[swe.githubUsername]?.linesAdded} ++
</p>
<p className='text-xs text-theme-red'>
{githubStats.userGitHubStats[swe.githubUsername]?.linesDeleted} --
</p>
</div>
)}
</div>
))} ))}
{githubStats &&
Object.keys(githubStats.userGitHubStats)
.filter(
username =>
!LONGHORN_DEVELOPERS_ADMINS.some(
admin => admin.githubUsername === username
) && !LONGHORN_DEVELOPERS_SWE.some(swe => swe.githubUsername === username)
)
.sort(
(a, b) =>
(githubStats.userGitHubStats[b]?.commits ?? 0) -
(githubStats.userGitHubStats[a]?.commits ?? 0)
)
.map(username => (
<div
key={username}
className='overflow-clip border border-gray-300 rounded bg-ut-gray/10 p-4'
>
<Text
variant='p'
className='text-ut-burntorange font-semibold hover:cursor-pointer'
onClick={() => window.open(`https://github.com/${username}`, '_blank')}
>
{githubStats.names[username]}
</Text>
<p className='text-sm text-gray-600'>Contributor</p>
{showGitHubStats && (
<div className='mt-2'>
<p className='text-xs text-gray-500'>GitHub Stats (UTRP repo):</p>
{includeMergedPRs && (
<p className='text-xs'>
Merged PRs:{' '}
{githubStats.userGitHubStats[username]?.mergedPRs}
</p>
)}
<p className='text-xs'>
Commits: {githubStats.userGitHubStats[username]?.commits}
</p>
<p className='text-xs text-ut-green'>
{githubStats.userGitHubStats[username]?.linesAdded} ++
</p>
<p className='text-xs text-theme-red'>
{githubStats.userGitHubStats[username]?.linesDeleted} --
</p>
</div>
)}
</div>
))}
</div> </div>
</section> </section>
</section> </section>

View File

@@ -0,0 +1,13 @@
export const DISPLAY_PREVIEWS = false;
export const PREVIEW_SECTION_DIV_CLASSNAME = DISPLAY_PREVIEWS ? 'w-1/2 space-y-4' : 'flex-grow space-y-4';
export const STATS_TOGGLE_KEY = 's';
export const INCLUDE_MERGED_PRS = false;
export const DEV_MODE_CLICK_TARGET = 5;
export const DEV_MODE_CLICK_TIMEOUT = 5000;
export const DEV_MODE_CLICK_INTERVAL = 500;
// LHD Birthday: January 9th, 2025
export const LHD_BIRTHDAY = { month: 0, day: 9 };
export const BIRTHDAY_CELEBRATION_DURATION = 5000;
export const BIRTHDAY_CELEBRATION_DEBOUNCE = 2000;

View File

@@ -0,0 +1,140 @@
import type { Engine, ISourceOptions } from '@tsparticles/engine';
import { initParticlesEngine } from '@tsparticles/react';
import { loadSlim } from '@tsparticles/slim';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { BIRTHDAY_CELEBRATION_DEBOUNCE, BIRTHDAY_CELEBRATION_DURATION, LHD_BIRTHDAY } from './constants';
/**
* Custom hook for birthday celebration particles
*/
export const useBirthdayCelebration = () => {
const [showParticles, setShowParticles] = useState(false);
const [particlesInit, setParticlesInit] = useState(false);
const [lastCelebration, setLastCelebration] = useState(0);
const isBirthday = useMemo(() => {
const today = new Date();
return today.getMonth() === LHD_BIRTHDAY.month && today.getDate() === LHD_BIRTHDAY.day;
}, []);
useEffect(() => {
initParticlesEngine(async (engine: Engine) => {
await loadSlim(engine);
}).then(() => {
setParticlesInit(true);
});
}, []);
const triggerCelebration = useCallback(() => {
if (!isBirthday) return;
const now = Date.now();
// Debounce: prevent triggering again within BIRTHDAY_CELEBRATION_DEBOUNCE ms
if (now - lastCelebration < BIRTHDAY_CELEBRATION_DEBOUNCE) return;
setLastCelebration(now);
setShowParticles(true);
setTimeout(() => setShowParticles(false), BIRTHDAY_CELEBRATION_DURATION);
}, [isBirthday, lastCelebration]);
const particlesOptions: ISourceOptions = useMemo(
() => ({
fullScreen: { enable: true, zIndex: 1 },
particles: {
color: { value: ['#BF5700', '#333F48', '#FFFFFF'] }, // UT colors
move: {
direction: 'bottom',
enable: true,
outModes: {
default: 'out',
},
size: true,
speed: {
min: 1,
max: 3,
},
},
number: {
value: 500,
density: {
enable: true,
area: 800,
},
},
opacity: {
value: 1,
animation: {
enable: false,
startValue: 'max',
destroy: 'min',
speed: 0.3,
sync: true,
},
},
rotate: {
value: {
min: 0,
max: 360,
},
direction: 'random',
move: true,
animation: {
enable: true,
speed: 60,
},
},
tilt: {
direction: 'random',
enable: true,
move: true,
value: {
min: 0,
max: 360,
},
animation: {
enable: true,
speed: 60,
},
},
shape: {
type: ['circle', 'square'],
options: {},
},
size: {
value: {
min: 2,
max: 4,
},
},
roll: {
darken: {
enable: true,
value: 30,
},
enlighten: {
enable: true,
value: 30,
},
enable: true,
speed: {
min: 15,
max: 25,
},
},
wobble: {
distance: 30,
enable: true,
move: true,
speed: {
min: -15,
max: 15,
},
},
},
}),
[]
);
return { showParticles, particlesInit, particlesOptions, triggerCelebration, isBirthday };
};

View File

@@ -0,0 +1,35 @@
import { useCallback, useEffect, useState } from 'react';
import { DEV_MODE_CLICK_INTERVAL, DEV_MODE_CLICK_TIMEOUT } from './constants';
/**
* Custom hook for enabling developer mode via rapid clicking
*/
export const useDevMode = (targetCount: number): [boolean, () => void] => {
const [count, setCount] = useState(0);
const [active, setActive] = useState(false);
const [lastClick, setLastClick] = useState(0);
const incrementCount = useCallback(() => {
const now = Date.now();
if (now - lastClick < DEV_MODE_CLICK_INTERVAL) {
setCount(prevCount => {
const newCount = prevCount + 1;
if (newCount === targetCount) {
setActive(true);
}
return newCount;
});
} else {
setCount(1);
}
setLastClick(now);
}, [lastClick, targetCount]);
useEffect(() => {
const timer = setTimeout(() => setCount(0), DEV_MODE_CLICK_TIMEOUT);
return () => clearTimeout(timer);
}, [count]);
return [active, incrementCount];
};

View File

@@ -1,5 +1,8 @@
import { background } from '@shared/messages';
import { OptionsStore } from '@shared/storage/OptionsStore';
import { CRX_PAGES } from '@shared/types/CRXPages';
import useSchedules from '@views/hooks/useSchedules'; import useSchedules from '@views/hooks/useSchedules';
import React, { useCallback } from 'react'; import React, { useCallback, useEffect, useState } from 'react';
import { Button } from '../components/common/Button'; import { Button } from '../components/common/Button';
import { usePrompt } from '../components/common/DialogProvider/DialogProvider'; import { usePrompt } from '../components/common/DialogProvider/DialogProvider';
@@ -17,8 +20,33 @@ const SCHEDULE_LIMIT = 10;
export function useEnforceScheduleLimit(): () => boolean { export function useEnforceScheduleLimit(): () => boolean {
const [, schedules] = useSchedules(); const [, schedules] = useSchedules();
const showDialog = usePrompt(); const showDialog = usePrompt();
const [allowMoreSchedules, setAllowMoreSchedules] = useState<boolean>(false);
useEffect(() => {
let mounted = true;
(async () => {
try {
const val = await OptionsStore.get('allowMoreSchedules');
if (mounted) setAllowMoreSchedules(val ?? false);
} catch (err) {
console.error('Failed to read allowMoreSchedules from OptionsStore:', err);
}
})();
const listener = OptionsStore.listen('allowMoreSchedules', async ({ newValue }) => {
setAllowMoreSchedules(newValue);
});
return () => {
mounted = false;
OptionsStore.removeListener(listener);
};
}, []);
return useCallback(() => { return useCallback(() => {
// If user has enabled bypass, allow creating more schedules
if (allowMoreSchedules) return true;
if (schedules.length >= SCHEDULE_LIMIT) { if (schedules.length >= SCHEDULE_LIMIT) {
showDialog({ showDialog({
title: `You have too many schedules!`, title: `You have too many schedules!`,
@@ -27,19 +55,33 @@ export function useEnforceScheduleLimit(): () => boolean {
<> <>
To encourage organization,{' '} To encourage organization,{' '}
<span className='text-ut-burntorange'>please consider deleting any unused schedules</span> you <span className='text-ut-burntorange'>please consider deleting any unused schedules</span> you
may have. may have. You can increase the limit in the settings if its really necessary.
</> </>
), ),
buttons: close => ( buttons: close => (
<Button variant='filled' color='ut-burntorange' onClick={close}> <>
I understand <Button
</Button> variant='outline'
color='ut-black'
onClick={() => {
close();
// open options/settings page so user can enable bypass if they are advising staff
const url = chrome.runtime.getURL(CRX_PAGES.OPTIONS);
background.openNewTab({ url });
}}
>
Open Settings
</Button>
<Button variant='filled' color='ut-burntorange' onClick={close}>
I understand
</Button>
</>
), ),
}); });
return false; return false;
} }
return true; return true;
}, [schedules, showDialog]); }, [schedules, showDialog, allowMoreSchedules]);
} }

View File

@@ -36,6 +36,7 @@ export interface CalendarGridCourse {
gridColumnStart?: number; gridColumnStart?: number;
gridColumnEnd?: number; gridColumnEnd?: number;
totalColumns?: number; totalColumns?: number;
concurrentCells?: CalendarGridCourse[];
} }
/** /**

View File

@@ -1,11 +1,13 @@
import { UT_DINING_APP_STORE_URL } from '@shared/util/appUrls';
import { Button } from '@views/components/common/Button'; import { Button } from '@views/components/common/Button';
import Text from '@views/components/common/Text/Text'; import Text from '@views/components/common/Text/Text';
import WhatsNewPopupContent from '@views/components/common/WhatsNewPopup'; import WhatsNewPopupContent from '@views/components/common/WhatsNewPopup';
import { useDialog } from '@views/contexts/DialogContext'; import { useDialog } from '@views/contexts/DialogContext';
import React from 'react'; import React from 'react';
import { LogoIcon } from '../components/common/LogoIcon'; // import useChangelog from './useChangelog';
import useChangelog from './useChangelog';
const LDIconURL = new URL('/src/assets/LD-icon-new.png', import.meta.url).href;
/** /**
* Custom hook that provides a function to display a what's new dialog. * Custom hook that provides a function to display a what's new dialog.
@@ -14,28 +16,34 @@ import useChangelog from './useChangelog';
*/ */
export default function useWhatsNewPopUp(): () => void { export default function useWhatsNewPopUp(): () => void {
const showDialog = useDialog(); const showDialog = useDialog();
const showChangeLog = useChangelog(); // const showChangeLog = useChangelog();
const { version } = chrome.runtime.getManifest(); // const { version } = chrome.runtime.getManifest();
const showPopUp = () => { const showPopUp = () => {
showDialog(close => ({ showDialog(close => ({
className: 'w-[830px] flex flex-col items-center gap-spacing-7 p-spacing-8', className: 'w-[830px] flex flex-col items-center gap-spacing-7 p-spacing-8',
title: ( title: (
<div className='flex items-center justify-between gap-4'> <div className='flex items-center justify-between gap-4'>
<LogoIcon width='48' height='48' /> <img src={LDIconURL} alt='LD Icon' className='h-12 w-12 rounded-lg' />
<Text variant='h1' className='text-theme-black'> <Text variant='h1' className='text-theme-black'>
What&apos;s New in UT Registration Plus Download our new UT Dining app!
</Text> </Text>
</div> </div>
), ),
description: <WhatsNewPopupContent />, description: <WhatsNewPopupContent />,
buttons: ( buttons: (
<div className='flex flex-row items-end gap-spacing-4'> <div className='flex flex-row items-end gap-spacing-4'>
<Button onClick={showChangeLog} variant='minimal' color='ut-black'> <Button
Read Changelog v{version} onClick={() => {
window.open(UT_DINING_APP_STORE_URL, '_blank');
}}
variant='minimal'
color='ut-black'
>
Download UT Dining on iOS
</Button> </Button>
<Button onClick={close} color='ut-burntorange'> <Button onClick={close} color='ut-burntorange'>
Get started Close
</Button> </Button>
</div> </div>
), ),

View File

@@ -0,0 +1,34 @@
import { describe, expect, it } from 'vitest';
import { CourseCatalogScraper } from './CourseCatalogScraper';
describe('CourseCatalogScraper::separateCourseName', () => {
it('should separate a simple course', () => {
// UT Formats strings weird... lots of meaningless spaces
const input = 'C S 314H DATA STRUCTURES: HONORS ';
const expected = ['DATA STRUCTURES: HONORS', 'C S', '314H'];
const result = CourseCatalogScraper.separateCourseName(input);
expect(result).toEqual(expected);
});
it('separate summer courses ', () => {
// UT Formats strings weird... lots of meaningless spaces
const inputs = [
'P R f378 PUBLIC RELATNS TECHNIQUES-IRL (First term) ',
'CRP s396 INDEPENDENT RESEARCH IN CRP (Second term) ',
'B A n284S 1-MANAGERIAL MICROECON-I-DAL (Nine week term) ',
'J w379 JOURNALISM INDEPENDENT STUDY (Whole term) ',
];
const expected = [
['PUBLIC RELATNS TECHNIQUES-IRL (First term)', 'P R', 'f378'],
['INDEPENDENT RESEARCH IN CRP (Second term)', 'CRP', 's396'],
['1-MANAGERIAL MICROECON-I-DAL (Nine week term)', 'B A', 'n284S'],
['JOURNALISM INDEPENDENT STUDY (Whole term)', 'J', 'w379'],
];
const results = inputs.map(input => CourseCatalogScraper.separateCourseName(input));
expect(results).toEqual(expected);
});
});

View File

@@ -75,7 +75,7 @@ export class CourseCatalogScraper {
fullName = fullName.replace(/\s\s+/g, ' ').trim(); fullName = fullName.replace(/\s\s+/g, ' ').trim();
const [courseName, department, number] = this.separateCourseName(fullName); const [courseName, department, number] = CourseCatalogScraper.separateCourseName(fullName);
const [status, isReserved] = this.getStatus(row); const [status, isReserved] = this.getStatus(row);
const newCourse = new Course({ const newCourse = new Course({
@@ -113,16 +113,31 @@ export class CourseCatalogScraper {
* *
* @example * @example
* ``` * ```
* separateCourseName("CS 314H - Honors Discrete Structures") => ["Honors Discrete Structures", "CS", "314H"] * separateCourseName("C S 314H DATA STRUCTURES: HONORS") => ["DATA STRUCTURES: HONORS", "C S", "314H"]
* ``` * ```
* @param courseFullName - the full name of the course (e.g. "CS 314H - Honors Discrete Structures") * @param courseFullName - the full name of the course (e.g. "C S 314H DATA STRUCTURES: HONORS")
* @returns an array of the course name , department, and number * @returns an array of the course name, department, and number
*/ */
separateCourseName(courseFullName: string): [courseName: string, department: string, number: string] { static separateCourseName(courseFullName: string): [courseName: string, department: string, number: string] {
let courseNumberIndex = courseFullName.search(/\d/); // C S 314H DATA STRUCTURES: HONORS
let department = courseFullName.substring(0, courseNumberIndex).trim(); // ^ Here for normal courses
let number = courseFullName.substring(courseNumberIndex, courseFullName.indexOf(' ', courseNumberIndex)).trim(); // B A n284S 1-MANAGERIAL MICROECON-I-DAL (Nine week term)
let courseName = courseFullName.substring(courseFullName.indexOf(' ', courseNumberIndex)).trim(); // ^ Also works for summer courses ([f]irst term, [s]econd term, [n]ine week term, [w]hole term)
const courseNumberIndex = courseFullName.search(/\w?\d/);
if (courseNumberIndex === -1) {
throw new Error("Course name doesn't have a course number");
}
// Everything before the course number
const department = courseFullName.substring(0, courseNumberIndex).trim();
const number = courseFullName
.substring(courseNumberIndex, courseFullName.indexOf(' ', courseNumberIndex))
.trim();
// Everything after the course number
const courseName = courseFullName.substring(courseFullName.indexOf(' ', courseNumberIndex)).trim();
return [courseName, department, number]; return [courseName, department, number];
} }

View File

@@ -109,16 +109,22 @@ function generateQuery(
includeInstructor: boolean includeInstructor: boolean
): [string, GradeDistributionParams] { ): [string, GradeDistributionParams] {
const query = ` const query = `
select * from grade_distributions SELECT * FROM grade_distributions
where Department_Code = :department_code WHERE Department_Code = :department_code
and Course_Number = :course_number AND Course_Number COLLATE NOCASE IN (
${includeInstructor ? `and Instructor_Last = :instructor_last collate nocase` : ''} :course_number,
${semester ? `and Semester = :semester` : ''} concat('F', :course_number), -- Check summer courses with prefix, too
concat('S', :course_number),
concat('N', :course_number),
concat('W', :course_number)
)
${includeInstructor ? `AND Instructor_Last = :instructor_last COLLATE NOCASE` : ''}
${semester ? `AND Semester = :semester` : ''}
`; `;
const params: GradeDistributionParams = { const params: GradeDistributionParams = {
':department_code': course.department, ':department_code': course.department,
':course_number': course.number, ':course_number': course.getNumberWithoutTerm(),
}; };
if (includeInstructor) { if (includeInstructor) {

View File

@@ -15,6 +15,7 @@ export const SiteSupport = {
MY_UT: 'MY_UT', MY_UT: 'MY_UT',
COURSE_CATALOG_SEARCH: 'COURSE_CATALOG_SEARCH', COURSE_CATALOG_SEARCH: 'COURSE_CATALOG_SEARCH',
CLASSLIST: 'CLASSLIST', CLASSLIST: 'CLASSLIST',
COURSE_CATALOG_KWS: 'COURSE_CATALOG_KWS',
} as const; } as const;
/** /**
@@ -40,6 +41,9 @@ export default function getSiteSupport(url: string): SiteSupportType | null {
return SiteSupport.UT_PLANNER; return SiteSupport.UT_PLANNER;
} }
if (url.includes('utdirect.utexas.edu/apps/registrar/course_schedule')) { if (url.includes('utdirect.utexas.edu/apps/registrar/course_schedule')) {
if (url.includes('kws_results')) {
return SiteSupport.COURSE_CATALOG_KWS;
}
if (url.includes('results')) { if (url.includes('results')) {
return SiteSupport.COURSE_CATALOG_LIST; return SiteSupport.COURSE_CATALOG_LIST;
} }

View File

@@ -24,16 +24,14 @@ const pagesDir = resolve(root, 'pages');
const assetsDir = resolve(root, 'assets'); const assetsDir = resolve(root, 'assets');
const publicDir = resolve(__dirname, 'public'); const publicDir = resolve(__dirname, 'public');
// Set default environment variables
process.env.PROD = process.env.NODE_ENV === 'production' ? 'true' : 'false';
const isBeta = !!process.env.BETA; const isBeta = !!process.env.BETA;
if (isBeta) { if (isBeta) {
process.env.VITE_BETA_BUILD = 'true'; process.env.VITE_BETA_BUILD = 'true';
} }
process.env.VITE_PACKAGE_VERSION = packageJson.version; process.env.VITE_PACKAGE_VERSION = packageJson.version;
// TODO: Debug this. If PROD is false, VITE_SENTRY_ENVIRONMENT is in production mode
if (process.env.PROD) { // special condition for production sentry instrumentation, as many of our devs like to use `pnpm build` directly. Production instrumentation is added and uploaded during `pnpm zip:to-publish`.
if (process.env.SENTRY_ENV === 'production') {
process.env.VITE_SENTRY_ENVIRONMENT = 'production'; process.env.VITE_SENTRY_ENVIRONMENT = 'production';
} else if (isBeta) { } else if (isBeta) {
process.env.VITE_SENTRY_ENVIRONMENT = 'beta'; process.env.VITE_SENTRY_ENVIRONMENT = 'beta';
@@ -90,6 +88,31 @@ const fixManifestOptionsPage = (): Plugin => ({
}, },
}); });
function getGitInfo() {
// Try environment variables first (for Nix builds)
if (process.env.VITE_GIT_BRANCH && process.env.VITE_GIT_COMMIT) {
return {
gitBranch: process.env.VITE_GIT_BRANCH,
gitCommit: process.env.VITE_GIT_COMMIT,
};
}
// Fall back to git commands (for local development)
try {
return {
gitBranch: execSync('git rev-parse --abbrev-ref HEAD').toString().trim(),
gitCommit: execSync('git rev-parse --short HEAD').toString().trim(),
};
} catch {
return {
gitBranch: 'unknown',
gitCommit: 'unknown',
};
}
}
const gitInfo = getGitInfo();
let config: ResolvedConfig; let config: ResolvedConfig;
let server: ViteDevServer; let server: ViteDevServer;
@@ -182,12 +205,14 @@ export default defineConfig({
'PROD', 'PROD',
'VITE_SENTRY_ENVIRONMENT', 'VITE_SENTRY_ENVIRONMENT',
'VITE_BETA_BUILD', 'VITE_BETA_BUILD',
'VITE_GIT_BRANCH',
'VITE_GIT_COMMIT',
], ],
includeTimestamp: true, includeTimestamp: true,
includeBuildTime: true, includeBuildTime: true,
customMetadata: { customMetadata: {
gitBranch: () => execSync('git rev-parse --abbrev-ref HEAD').toString().trim(), gitBranch: () => gitInfo.gitBranch,
gitCommit: () => execSync('git rev-parse --short HEAD').toString().trim(), gitCommit: () => gitInfo.gitCommit,
nodeVersion: () => process.version, nodeVersion: () => process.version,
}, },
}), }),