├── .github └── workflows │ ├── deploy-app.yml │ └── deploy-website.yml ├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── README.md ├── assets └── sc-timetable.png ├── biome.json ├── client ├── .env ├── .gitignore ├── README.md ├── app │ ├── components │ │ ├── anchor.tsx │ │ ├── audio-item.tsx │ │ ├── audio-recorder.tsx │ │ ├── avatar.tsx │ │ ├── button.tsx │ │ ├── common-head.tsx │ │ ├── community-info.tsx │ │ ├── community-mod.tsx │ │ ├── content.tsx │ │ ├── crowdsource-notice.tsx │ │ ├── days-header.tsx │ │ ├── discussions-empty.tsx │ │ ├── dropdown-menu.tsx │ │ ├── error-boundary.tsx │ │ ├── file-input.tsx │ │ ├── file-menu.tsx │ │ ├── file-select-item.tsx │ │ ├── footer.tsx │ │ ├── input.tsx │ │ ├── knust-login-direction.tsx │ │ ├── large-select.tsx │ │ ├── lesson-form.tsx │ │ ├── lesson-item.tsx │ │ ├── login-comment.tsx │ │ ├── logout-modal.tsx │ │ ├── media-item.tsx │ │ ├── media-preview.tsx │ │ ├── modal.tsx │ │ ├── navbar.tsx │ │ ├── nested-comments.tsx │ │ ├── non-image-thumb.tsx │ │ ├── parlon-logo.tsx │ │ ├── peer-video-panel.tsx │ │ ├── pending-ui.tsx │ │ ├── post-content.tsx │ │ ├── post-input.tsx │ │ ├── post-item.tsx │ │ ├── post-menu.tsx │ │ ├── post-people.tsx │ │ ├── post-time.tsx │ │ ├── product-form.tsx │ │ ├── product-item.tsx │ │ ├── select.tsx │ │ ├── self-video-panel.tsx │ │ ├── sym-outline.tsx │ │ ├── tag-input.tsx │ │ ├── tag-select.tsx │ │ ├── tags-filter.tsx │ │ ├── tags.tsx │ │ ├── textarea.tsx │ │ ├── timetable-filter.tsx │ │ ├── timetable-save-to-calendar.tsx │ │ ├── username.tsx │ │ └── votes.tsx │ ├── entry.client.tsx │ ├── entry.server.tsx │ ├── lib │ │ ├── boat-client.ts │ │ ├── boat-relay.server.ts │ │ ├── check-auth.ts │ │ ├── check-mod.ts │ │ ├── cookies.server.ts │ │ ├── create-post-notification.ts │ │ ├── create-post.ts │ │ ├── create-tags-query.ts │ │ ├── days.ts │ │ ├── ellipsize.ts │ │ ├── files.ts │ │ ├── get-moderators.ts │ │ ├── include-votes.ts │ │ ├── is-image.ts │ │ ├── jwt.server.ts │ │ ├── linkify-mentions.ts │ │ ├── logout.server.ts │ │ ├── mail.server.ts │ │ ├── parlon-context.tsx │ │ ├── password.server.ts │ │ ├── prisma.server.ts │ │ ├── random-str.ts │ │ ├── remove-code-trail.ts │ │ ├── render-bio.server.ts │ │ ├── render-stripped.server.ts │ │ ├── render-summary.server.ts │ │ ├── render.server.ts │ │ ├── request-state.ts │ │ ├── request-status.ts │ │ ├── responses.ts │ │ ├── restrict-usernames.ts │ │ ├── s3.server.ts │ │ ├── send-email-verification.ts │ │ ├── slugify.ts │ │ ├── tag-use-data.ts │ │ ├── time.ts │ │ ├── upload-media.ts │ │ ├── use-async-fetcher.ts │ │ ├── use-audio-recorder.ts │ │ ├── use-color-scheme.ts │ │ ├── use-comments.ts │ │ ├── use-countdown.ts │ │ ├── use-courses.ts │ │ ├── use-mounted.ts │ │ ├── use-post-people.ts │ │ ├── use-programmes.ts │ │ ├── use-tag-courses.ts │ │ ├── use-tag-programmes.ts │ │ ├── username-regex.tsx │ │ ├── values.server.ts │ │ └── with-user-prefs.ts │ ├── root.tsx │ ├── routes │ │ ├── _index.tsx │ │ ├── account-created.tsx │ │ ├── comments.ts │ │ ├── communities.tsx │ │ ├── communities_.$slug.members.tsx │ │ ├── communities_.$slug.mod.tsx │ │ ├── communities_.$slug.tsx │ │ ├── communities_.created.tsx │ │ ├── communities_.new.tsx │ │ ├── courses.tsx │ │ ├── create-account.tsx │ │ ├── discussions.tsx │ │ ├── discussions_.$id.tsx │ │ ├── discussions_.$id_.$.tsx │ │ ├── downloads.events.$id.tsx │ │ ├── downloads.timetable.$year.$programme.$level.$sem.tsx │ │ ├── events.tsx │ │ ├── events_.$id.tsx │ │ ├── events_.add.tsx │ │ ├── forgot-password.tsx │ │ ├── games.tsx │ │ ├── instructors.tsx │ │ ├── lessons.$id.tsx │ │ ├── library.tsx │ │ ├── library_.$id.tsx │ │ ├── login.tsx │ │ ├── logout.tsx │ │ ├── manifest[.]webmanifest.ts │ │ ├── market.tsx │ │ ├── market_.$id.tsx │ │ ├── market_.$id_.edit.tsx │ │ ├── market_.add.tsx │ │ ├── market_.profile.tsx │ │ ├── md.ts │ │ ├── media.tsx │ │ ├── notifications.tsx │ │ ├── notifications_.$id.tsx │ │ ├── p.$username.catalog.tsx │ │ ├── p.$username.communities.tsx │ │ ├── p.$username.tsx │ │ ├── parlon.call.tsx │ │ ├── parlon.tsx │ │ ├── people.ts │ │ ├── programmes.tsx │ │ ├── resend-verification.tsx │ │ ├── reset-password.tsx │ │ ├── timetable.tsx │ │ ├── timetable_.$year.$programme.$level.$sem.$day.add.tsx │ │ ├── timetable_.$year.$programme.$level.$sem.$day.tsx │ │ ├── verify-email.tsx │ │ └── vote.$post.ts │ └── style.css ├── env.d.ts ├── package.json ├── prisma │ ├── migrations │ │ ├── 20240121162725_init │ │ │ └── migration.sql │ │ ├── 20240123221212_rename_code_add_location │ │ │ └── migration.sql │ │ ├── 20240202080342_add_user │ │ │ └── migration.sql │ │ ├── 20240202080501_add_timestamp │ │ │ └── migration.sql │ │ ├── 20240202155452_add_verified_field │ │ │ └── migration.sql │ │ ├── 20240203071938_password_reset_email_verification │ │ │ └── migration.sql │ │ ├── 20240203081443_add_used │ │ │ └── migration.sql │ │ ├── 20240203202105_add_posts │ │ │ └── migration.sql │ │ ├── 20240203202520_add_counts │ │ │ └── migration.sql │ │ ├── 20240204090729_votes │ │ │ └── migration.sql │ │ ├── 20240204152813_vote_cascade │ │ │ └── migration.sql │ │ ├── 20240204153235_vote_delete_noaction │ │ │ └── migration.sql │ │ ├── 20240204155458_soft_delete │ │ │ └── migration.sql │ │ ├── 20240205144235_media │ │ │ └── migration.sql │ │ ├── 20240205144512_media_field │ │ │ └── migration.sql │ │ ├── 20240205145508_add_file_name │ │ │ └── migration.sql │ │ ├── 20240207103046_add_tags │ │ │ └── migration.sql │ │ ├── 20240304200456_events │ │ │ └── migration.sql │ │ ├── 20240304201721_event_date │ │ │ └── migration.sql │ │ ├── 20240304205118_event_poster │ │ │ └── migration.sql │ │ ├── 20240311163736_repository │ │ │ └── migration.sql │ │ ├── 20240311164350_repository_tags │ │ │ └── migration.sql │ │ ├── 20240404130325_post_path │ │ │ └── migration.sql │ │ ├── 20240406004831_notifications │ │ │ └── migration.sql │ │ ├── 20240413062208_use_singular │ │ │ └── migration.sql │ │ ├── 20240413063354_rename_typo_notification_subscriber │ │ │ └── migration.sql │ │ ├── 20240413233932_nocase_username │ │ │ └── migration.sql │ │ ├── 20240421170420_communities │ │ │ └── migration.sql │ │ ├── 20240421173802_communities_post │ │ │ └── migration.sql │ │ ├── 20240423165936_communities_unique_index │ │ │ └── migration.sql │ │ ├── 20240423192541_community_post │ │ │ └── migration.sql │ │ ├── 20240425224659_bio │ │ │ └── migration.sql │ │ ├── 20240505180831_market │ │ │ └── migration.sql │ │ ├── 20240505190217_category_title_unique │ │ │ └── migration.sql │ │ └── migration_lock.toml │ ├── schema.prisma │ └── seed.mjs ├── public │ ├── favicon.ico │ ├── favicon.png │ ├── icons │ │ ├── android-chrome-256x256.png │ │ ├── android-chrome-512x512.png │ │ ├── android-icon-36x36.png │ │ ├── android-icon-48x48.png │ │ ├── android-icon-72x72.png │ │ ├── android-icon-96x96.png │ │ └── apple-touch-icon.png │ ├── sym-outline.svg │ ├── sym.svg │ └── zasplat_connected_ding.mp3 ├── res │ ├── knust.json │ ├── ug.json │ └── umat.json ├── tsconfig.json ├── uno.config.ts └── vite.config.ts ├── launch.sh ├── package.json ├── website ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .vscode │ ├── extensions.json │ └── launch.json ├── README.md ├── astro.config.mjs ├── package.json ├── public │ ├── CNAME │ ├── compa-swag.svg │ ├── favicon.ico │ ├── favicon.svg │ ├── sym-outline.svg │ └── sym.svg ├── src │ ├── components │ │ ├── CompaSwag.astro │ │ ├── Footer.astro │ │ ├── LogoDuo.astro │ │ ├── Navbar.astro │ │ └── tmp.astro │ ├── env.d.ts │ ├── layouts │ │ └── Shell.astro │ ├── pages │ │ ├── index.astro │ │ └── schools.astro │ └── styles.css ├── tsconfig.json └── uno.config.ts └── yarn.lock /.github/workflows/deploy-app.yml: -------------------------------------------------------------------------------- 1 | name: Deploy App 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - 'client/**' 9 | workflow_dispatch: 10 | 11 | jobs: 12 | deploy: 13 | runs-on: ubuntu-latest 14 | strategy: 15 | max-parallel: 1 16 | matrix: 17 | instance: ['knust', 'ug', 'umat'] 18 | steps: 19 | - name: Cloning repo 20 | uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 0 23 | 24 | - name: Push to dokku 25 | uses: dokku/github-action@master 26 | # enable verbose ssh output 27 | env: 28 | GIT_SSH_COMMAND: 'ssh -vvv' 29 | with: 30 | # enable verbose git output 31 | git_push_flags: '-vvv' 32 | git_remote_url: 'ssh://dokku@85.159.211.246:22/${{ matrix.instance }}' 33 | ssh_private_key: ${{ secrets.SSH_PRIVATE_KEY }} 34 | # enable shell trace mode 35 | trace: '1' 36 | -------------------------------------------------------------------------------- /.github/workflows/deploy-website.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Website to GitHub Pages 2 | 3 | on: 4 | # Trigger the workflow every time you push to the `main` branch 5 | # Using a different branch name? Replace `main` with your branch’s name 6 | push: 7 | branches: [ master ] 8 | paths: 9 | - 'website/**' 10 | # Allows you to run this workflow manually from the Actions tab on GitHub. 11 | workflow_dispatch: 12 | 13 | # Allow this job to clone the repo and create a page deployment 14 | permissions: 15 | contents: read 16 | pages: write 17 | id-token: write 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Checkout code 24 | uses: actions/checkout@v3 25 | with: 26 | fetch-depth: 1 27 | 28 | - name: Print commit id, message and tag 29 | run: | 30 | git show -s --format='%h %s' 31 | echo "github.ref -> {{ github.ref }}" 32 | 33 | - name: Set up Node.js and Yarn 34 | uses: actions/setup-node@v3 35 | with: 36 | node-version: '20.10.0' 37 | registry-url: 'https://registry.yarnpkg.com' 38 | 39 | - name: Install dependencies 40 | run: yarn install --frozen-lockfile 41 | 42 | - name: Build 43 | run: yarn build:website 44 | 45 | - name: Upload artifact 46 | uses: actions/upload-pages-artifact@v1 47 | with: 48 | path: ./website/dist 49 | 50 | deploy: 51 | needs: build 52 | runs-on: ubuntu-latest 53 | environment: 54 | name: github-pages 55 | url: ${{ steps.deployment.outputs.page_url }} 56 | steps: 57 | - name: Deploy to GitHub Pages 58 | id: deployment 59 | uses: actions/deploy-pages@v1 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | yarn-error.log 3 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["biomejs.biome"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "biomejs.biome", 3 | "[prisma]": { 4 | "editor.defaultFormatter": "Prisma.prisma" 5 | }, 6 | "[typescriptreact]": { 7 | "editor.defaultFormatter": "biomejs.biome" 8 | } 9 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
9 | This is a crowdsourced effort to curate this data. Please make sure 10 | these details are correct before submitting them. 11 |
12 | 13 |14 | In case of any error, please create an issue here. 15 |
16 | 17 | 22 |7 | You must be{" "} 8 | 9 | logged in 10 | {" "} 11 | to comment. 12 |
13 |Are you sure you want to log out?
19 |You're muted
54 | )} 55 |
41 | You're about to download the calendar file which contains all the
42 | schedule for{" "}
43 |
44 | {programme?.name}
45 |
{" "}
46 |
47 | L{level}
48 |
{" "}
49 | Semester{" "}
50 |
51 | {sem}
52 |
{" "}
53 | for the year{" "}
54 |
55 | {year}
56 |
57 | .
58 |
61 | After download, open file to automically fill your calendar. 62 |
63 | 64 |65 | 🌶️ You may need to manually adjust your calendar when there are 66 | changes. 67 |
68 |23 | A verification link has been sent to this email:{" "} 24 | 25 | {email} 26 | 27 |
28 |29 | You may not be able to add or edit content on compa until you verify 30 | your account. 31 |
32 | 33 | {school === "knust" &&69 | {ellipsize(community.description, 60)} 70 |
71 |13 | Any higher education institution is allowed to get an instance of 14 | compa. However, we currently have the following schools hosted: 15 |
16 | 17 |18 | If you wish to get an instance hosted for your school, you can 21 | Request for it 22 | . You have the option to host one yourself. See 25 | repository 26 | 27 |
28 | 29 |Kwame Nkrumah University of Science and Technology | 33 |34 | 37 | knust.compa.so 38 | 39 | | 40 |
University of Ghana | 43 |44 | 47 | ug.compa.so 48 | 49 | | 50 |
University of Mines and Technology | 53 |54 | 57 | umat.compa.so 58 | 59 | | 60 |