├── .dockerignore ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ └── ci.yml ├── .gitignore ├── .kamal ├── hooks │ ├── docker-setup.sample │ ├── post-app-boot.sample │ ├── post-deploy.sample │ ├── post-proxy-reboot.sample │ ├── pre-app-boot.sample │ ├── pre-build.sample │ ├── pre-connect.sample │ ├── pre-deploy.sample │ └── pre-proxy-reboot.sample └── secrets ├── .rubocop.yml ├── .ruby-version ├── Dockerfile ├── Gemfile ├── Gemfile.lock ├── LICENSE ├── Procfile.dev ├── README.md ├── Rakefile ├── app ├── assets │ ├── builds │ │ └── .keep │ ├── fonts │ │ └── dystopian.otf │ ├── images │ │ ├── .keep │ │ ├── landing │ │ │ ├── bg.png │ │ │ ├── box.png │ │ │ ├── hackpad.png │ │ │ ├── landing2.png │ │ │ ├── landing3.png │ │ │ ├── landing4.png │ │ │ ├── landingbg.png │ │ │ ├── landingbg2.png │ │ │ ├── landinglogo.png │ │ │ ├── racecar.png │ │ │ ├── racetrack.png │ │ │ ├── shards.png │ │ │ ├── sign1.png │ │ │ ├── sign2.png │ │ │ ├── sign3.png │ │ │ ├── speaker.png │ │ │ ├── stick1.png │ │ │ ├── stick2.png │ │ │ ├── stick3.png │ │ │ ├── stick4.png │ │ │ ├── stick5.png │ │ │ ├── stick6.png │ │ │ ├── tracks1.png │ │ │ └── tracks2.png │ │ ├── logo.png │ │ └── mystery.png │ ├── stylesheets │ │ ├── actiontext.css │ │ ├── application.css │ │ ├── landing.css │ │ └── markdown.css │ └── tailwind │ │ └── application.css ├── controllers │ ├── admin_controller.rb │ ├── advanced_controller.rb │ ├── application_controller.rb │ ├── concerns │ │ ├── .keep │ │ └── markdown_renderable.rb │ ├── events_controller.rb │ ├── guides_controller.rb │ ├── info_controller.rb │ ├── landing_controller.rb │ ├── launchpad_controller.rb │ ├── markdown_controller.rb │ ├── overview_controller.rb │ ├── projects_controller.rb │ ├── rsvps_controller.rb │ ├── sessions_controller.rb │ └── users_controller.rb ├── helpers │ ├── application_helper.rb │ ├── events_helper.rb │ ├── guides_helper.rb │ ├── info_helper.rb │ ├── launchpad_helper.rb │ ├── overview_helper.rb │ ├── posts_helper.rb │ └── sessions_helper.rb ├── javascript │ ├── application.js │ └── controllers │ │ ├── application.js │ │ ├── hello_controller.js │ │ └── index.js ├── jobs │ ├── application_job.rb │ ├── clone_projects_job.rb │ └── sync_rsvp_with_airtable_job.rb ├── mailers │ ├── application_mailer.rb │ └── session_mailer.rb ├── models │ ├── application_record.rb │ ├── concerns │ │ ├── .keep │ │ └── has_frontmatter.rb │ ├── post.rb │ ├── prize.rb │ ├── project.rb │ ├── rsvp.rb │ ├── user.rb │ └── user_prize.rb └── views │ ├── active_storage │ └── blobs │ │ └── _blob.html.erb │ ├── admin │ └── dashboard.html.erb │ ├── advanced │ ├── _sidebar.html.erb │ ├── communities.md │ ├── design-guide.md │ ├── example-journal.md │ ├── ideas.md │ ├── journaling.md │ ├── overview.md │ ├── part-sourcing.md │ ├── project-guidelines.md │ ├── resources.md │ ├── shipping.md │ ├── show.html.erb │ ├── submitting.md │ ├── tips.md │ └── troubleshooting.md │ ├── events │ └── index.html.erb │ ├── guides │ ├── _sidebar.html.erb │ ├── game-console.md │ ├── overview.md │ └── show.html.erb │ ├── info │ ├── info.md │ └── show.html.erb │ ├── landing │ ├── _card.html.erb │ ├── _emailform.html.erb │ ├── _kit.html.erb │ ├── _kitsoon.html.erb │ ├── _video.html.erb │ ├── dashboard.html.erb │ ├── index.html.erb │ └── leaderboards.html.erb │ ├── launchpad │ ├── _kit.html.erb │ ├── _kitsoon.html.erb │ └── show.html.erb │ ├── layouts │ ├── action_text │ │ └── contents │ │ │ └── _content.html.erb │ ├── advanced.html.erb │ ├── application.html.erb │ ├── guides.html.erb │ ├── mailer.html.erb │ ├── mailer.text.erb │ └── overview.html.erb │ ├── overview │ ├── _sidebar.html.erb │ ├── faq.md │ ├── overview.md │ ├── parents.md │ ├── point-system.md │ ├── show.html.erb │ ├── starter-projects.md │ ├── submit.md │ └── undercity.md │ ├── projects │ ├── _header.html.erb │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── pwa │ ├── manifest.json.erb │ └── service-worker.js │ ├── session_mailer │ ├── login_code.html.erb │ └── login_code.text.erb │ ├── shared │ ├── _audio.html.erb │ ├── _sidebar.html.erb │ └── _topbar.html.erb │ └── users │ ├── _form.html.erb │ ├── edit.html.erb │ ├── prize_box.html.erb │ └── show.html.erb ├── bin ├── brakeman ├── bundle ├── dev ├── docker-entrypoint ├── importmap ├── jobs ├── kamal ├── rails ├── rake ├── rubocop ├── setup └── thrust ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cable.yml ├── cache.yml ├── database.yml ├── deploy.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── highlighted_projects.yml ├── importmap.rb ├── initializers │ ├── assets.rb │ ├── content_security_policy.rb │ ├── filter_parameter_logging.rb │ ├── good_job.rb │ ├── inflections.rb │ ├── markdown.rb │ └── rails_live_reload.rb ├── locales │ └── en.yml ├── puma.rb ├── queue.yml ├── recurring.yml ├── routes.rb └── storage.yml ├── content └── projects │ ├── .keep │ └── hackclub │ └── awesome-project │ ├── journal.md │ └── logo2.png ├── db ├── cable_schema.rb ├── cache_schema.rb ├── migrate │ ├── 20250425185735_create_posts.rb │ ├── 20250426202058_create_active_storage_tables.active_storage.rb │ ├── 20250426202059_create_action_text_tables.action_text.rb │ ├── 20250427015515_add_hours_to_posts.rb │ ├── 20250429161341_create_users.rb │ ├── 20250504204551_add_details_to_users.rb │ ├── 20250505014600_create_projects.rb │ ├── 20250505195247_add_user_to_projects.rb │ ├── 20250505195715_add_project_to_posts.rb │ ├── 20250505200739_add_name_to_projects.rb │ ├── 20250505203646_add_admin_to_users.rb │ ├── 20250506160012_create_prizes.rb │ ├── 20250506165025_create_user_prizes.rb │ ├── 20250508022535_drop_posts_projects_and_prizes.rb │ ├── 20250508025519_create_rsvps.rb │ ├── 20250508184653_add_airtable_record_id_to_rsvps.rb │ ├── 20250508185907_add_url_params_to_rsvps.rb │ └── 20250513161944_create_good_jobs.rb ├── queue_schema.rb ├── schema.rb └── seeds.rb ├── lib └── tasks │ ├── .keep │ └── clone_projects.rake ├── log └── .keep ├── public ├── 1.png ├── 2.png ├── 3.png ├── 400.html ├── 404.html ├── 406-unsupported-browser.html ├── 422.html ├── 500.html ├── arrows.png ├── bg.png ├── bg2.png ├── bg3.png ├── cerblights.png ├── desc1.png ├── desc2.png ├── desc3.png ├── event1kickoff.svg ├── event1kickoff2.svg ├── eventkickoff2.png ├── getstickers.gif ├── getstickers.png ├── guardianoftheundercity.png ├── hackathons.png ├── hackclubgh.png ├── hcflag.svg ├── highwaymusic.mp3 ├── highwaystar.png ├── icon.png ├── icon.svg ├── keypeople.png ├── landingbg3.png ├── landingbg4.png ├── logo2.png ├── logobanner.svg ├── portal.png ├── projects ├── ref │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── arrows.png │ ├── bg.png │ ├── bg2.png │ ├── bg3.png │ ├── cerblights.png │ ├── getstickers.png │ ├── hackclubgh.png │ ├── highwaystar.png │ ├── icon.png │ ├── landingbg3.png │ ├── landingbg4.png │ ├── logo2.png │ ├── portal.png │ ├── stickerbomb.png │ ├── stickerbomb2.png │ ├── track1.png │ ├── track2.png │ ├── undercitylogo.png │ └── undercitylogo2.png ├── robots.txt ├── stickerbomb.png ├── stickerbomb2.png ├── strangeparts.png ├── strangeparts2.png ├── swagsystem.png ├── track1.png ├── track2.png ├── tracks1.svg ├── tracks2.svg ├── tracks3.svg ├── undercity3.svg ├── undercitygate.png ├── undercitylogo.png ├── undercitylogo.svg ├── undercitylogo2.png └── undercitylogo2.svg ├── script └── .keep ├── storage └── .keep ├── submissions.yml ├── test ├── application_system_test_case.rb ├── controllers │ ├── .keep │ ├── events_controller_test.rb │ ├── guides_controller_test.rb │ ├── info_controller_test.rb │ ├── launchpad_controller_test.rb │ ├── overview_controller_test.rb │ └── sessions_controller_test.rb ├── fixtures │ ├── action_text │ │ └── rich_texts.yml │ ├── files │ │ └── .keep │ ├── rsvps.yml │ └── users.yml ├── helpers │ └── .keep ├── integration │ └── .keep ├── mailers │ ├── .keep │ ├── previews │ │ └── session_mailer_preview.rb │ └── session_mailer_test.rb ├── models │ ├── .keep │ ├── rsvp_test.rb │ └── user_test.rb ├── system │ └── .keep └── test_helper.rb ├── tmp ├── .keep ├── pids │ └── .keep └── storage │ └── .keep └── vendor ├── .keep └── javascript └── .keep /.dockerignore: -------------------------------------------------------------------------------- 1 | # See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files. 2 | 3 | # Ignore git directory. 4 | /.git/ 5 | /.gitignore 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore all environment files. 11 | /.env* 12 | 13 | # Ignore all default key files. 14 | /config/master.key 15 | /config/credentials/*.key 16 | 17 | # Ignore all logfiles and tempfiles. 18 | /log/* 19 | /tmp/* 20 | !/log/.keep 21 | !/tmp/.keep 22 | 23 | # Ignore pidfiles, but keep the directory. 24 | /tmp/pids/* 25 | !/tmp/pids/.keep 26 | 27 | # Ignore storage (uploaded files in development and any SQLite databases). 28 | /storage/* 29 | !/storage/.keep 30 | /tmp/storage/* 31 | !/tmp/storage/.keep 32 | 33 | # Ignore assets. 34 | /node_modules/ 35 | /app/assets/builds/* 36 | !/app/assets/builds/.keep 37 | /public/assets 38 | 39 | # Ignore CI service files. 40 | /.github 41 | 42 | # Ignore Kamal files. 43 | /config/deploy*.yml 44 | /.kamal 45 | 46 | # Ignore development files 47 | /.devcontainer 48 | 49 | # Ignore Docker-related files 50 | /.dockerignore 51 | /Dockerfile* 52 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # See https://git-scm.com/docs/gitattributes for more about git attribute files. 2 | 3 | # Mark the database schema as having been generated. 4 | db/schema.rb linguist-generated 5 | 6 | # Mark any vendored files as having been vendored. 7 | vendor/* linguist-vendored 8 | config/credentials/*.yml.enc diff=rails_credentials 9 | config/credentials.yml.enc diff=rails_credentials 10 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: bundler 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | - package-ecosystem: github-actions 9 | directory: "/" 10 | schedule: 11 | interval: daily 12 | open-pull-requests-limit: 10 13 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: [ main ] 7 | 8 | jobs: 9 | lint_submissions: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/checkout@v4 13 | - name: yaml-lint 14 | uses: ibiqlik/action-yamllint@v3 15 | with: 16 | file_or_dir: submissions.yml 17 | 18 | scan_ruby: 19 | runs-on: ubuntu-latest 20 | 21 | steps: 22 | - name: Checkout code 23 | uses: actions/checkout@v4 24 | 25 | - name: Set up Ruby 26 | uses: ruby/setup-ruby@v1 27 | with: 28 | ruby-version: .ruby-version 29 | bundler-cache: true 30 | 31 | - name: Scan for common Rails security vulnerabilities using static analysis 32 | run: bin/brakeman --no-pager 33 | 34 | scan_js: 35 | runs-on: ubuntu-latest 36 | 37 | steps: 38 | - name: Checkout code 39 | uses: actions/checkout@v4 40 | 41 | - name: Set up Ruby 42 | uses: ruby/setup-ruby@v1 43 | with: 44 | ruby-version: .ruby-version 45 | bundler-cache: true 46 | 47 | - name: Scan for security vulnerabilities in JavaScript dependencies 48 | run: bin/importmap audit 49 | 50 | lint: 51 | runs-on: ubuntu-latest 52 | steps: 53 | - name: Checkout code 54 | uses: actions/checkout@v4 55 | 56 | - name: Set up Ruby 57 | uses: ruby/setup-ruby@v1 58 | with: 59 | ruby-version: .ruby-version 60 | bundler-cache: true 61 | 62 | - name: Lint code for consistent style 63 | run: bin/rubocop -f github 64 | 65 | test: 66 | runs-on: ubuntu-latest 67 | 68 | # services: 69 | # redis: 70 | # image: redis 71 | # ports: 72 | # - 6379:6379 73 | # options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 74 | steps: 75 | - name: Install packages 76 | run: sudo apt-get update && sudo apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config google-chrome-stable 77 | 78 | - name: Checkout code 79 | uses: actions/checkout@v4 80 | 81 | - name: Set up Ruby 82 | uses: ruby/setup-ruby@v1 83 | with: 84 | ruby-version: .ruby-version 85 | bundler-cache: true 86 | 87 | - name: Run tests 88 | env: 89 | RAILS_ENV: test 90 | # REDIS_URL: redis://localhost:6379/0 91 | run: bin/rails db:test:prepare test test:system 92 | 93 | - name: Keep screenshots from failed system tests 94 | uses: actions/upload-artifact@v4 95 | if: failure() 96 | with: 97 | name: screenshots 98 | path: ${{ github.workspace }}/tmp/screenshots 99 | if-no-files-found: ignore 100 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # Temporary files generated by your text editor or operating system 4 | # belong in git's global ignore instead: 5 | # `$XDG_CONFIG_HOME/git/ignore` or `~/.config/git/ignore` 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore all environment files. 11 | /.env* 12 | 13 | # Ignore all logfiles and tempfiles. 14 | /log/* 15 | /tmp/* 16 | !/log/.keep 17 | !/tmp/.keep 18 | 19 | # Ignore pidfiles, but keep the directory. 20 | /tmp/pids/* 21 | !/tmp/pids/ 22 | !/tmp/pids/.keep 23 | 24 | # Ignore storage (uploaded files in development and any SQLite databases). 25 | /storage/* 26 | !/storage/.keep 27 | /tmp/storage/* 28 | !/tmp/storage/ 29 | !/tmp/storage/.keep 30 | 31 | /public/assets 32 | 33 | # Ignore master key for decrypting credentials and more. 34 | /config/master.key 35 | 36 | /app/assets/builds/* 37 | !/app/assets/builds/.keep 38 | 39 | .DS_Store 40 | # Ignore Mac system files 41 | 42 | # Ignore all projects 43 | /content/projects/* 44 | 45 | # But do NOT ignore the dev example project 46 | !/content/projects/hackclub/ 47 | !/content/projects/hackclub/awesome-project/ 48 | !/content/projects/hackclub/awesome-project/** 49 | -------------------------------------------------------------------------------- /.kamal/hooks/docker-setup.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Docker set up on $KAMAL_HOSTS..." 4 | -------------------------------------------------------------------------------- /.kamal/hooks/post-app-boot.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Booted app version $KAMAL_VERSION on $KAMAL_HOSTS..." 4 | -------------------------------------------------------------------------------- /.kamal/hooks/post-deploy.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # A sample post-deploy hook 4 | # 5 | # These environment variables are available: 6 | # KAMAL_RECORDED_AT 7 | # KAMAL_PERFORMER 8 | # KAMAL_VERSION 9 | # KAMAL_HOSTS 10 | # KAMAL_ROLE (if set) 11 | # KAMAL_DESTINATION (if set) 12 | # KAMAL_RUNTIME 13 | 14 | echo "$KAMAL_PERFORMER deployed $KAMAL_VERSION to $KAMAL_DESTINATION in $KAMAL_RUNTIME seconds" 15 | -------------------------------------------------------------------------------- /.kamal/hooks/post-proxy-reboot.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Rebooted kamal-proxy on $KAMAL_HOSTS" 4 | -------------------------------------------------------------------------------- /.kamal/hooks/pre-app-boot.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Booting app version $KAMAL_VERSION on $KAMAL_HOSTS..." 4 | -------------------------------------------------------------------------------- /.kamal/hooks/pre-build.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # A sample pre-build hook 4 | # 5 | # Checks: 6 | # 1. We have a clean checkout 7 | # 2. A remote is configured 8 | # 3. The branch has been pushed to the remote 9 | # 4. The version we are deploying matches the remote 10 | # 11 | # These environment variables are available: 12 | # KAMAL_RECORDED_AT 13 | # KAMAL_PERFORMER 14 | # KAMAL_VERSION 15 | # KAMAL_HOSTS 16 | # KAMAL_ROLE (if set) 17 | # KAMAL_DESTINATION (if set) 18 | 19 | if [ -n "$(git status --porcelain)" ]; then 20 | echo "Git checkout is not clean, aborting..." >&2 21 | git status --porcelain >&2 22 | exit 1 23 | fi 24 | 25 | first_remote=$(git remote) 26 | 27 | if [ -z "$first_remote" ]; then 28 | echo "No git remote set, aborting..." >&2 29 | exit 1 30 | fi 31 | 32 | current_branch=$(git branch --show-current) 33 | 34 | if [ -z "$current_branch" ]; then 35 | echo "Not on a git branch, aborting..." >&2 36 | exit 1 37 | fi 38 | 39 | remote_head=$(git ls-remote $first_remote --tags $current_branch | cut -f1) 40 | 41 | if [ -z "$remote_head" ]; then 42 | echo "Branch not pushed to remote, aborting..." >&2 43 | exit 1 44 | fi 45 | 46 | if [ "$KAMAL_VERSION" != "$remote_head" ]; then 47 | echo "Version ($KAMAL_VERSION) does not match remote HEAD ($remote_head), aborting..." >&2 48 | exit 1 49 | fi 50 | 51 | exit 0 52 | -------------------------------------------------------------------------------- /.kamal/hooks/pre-connect.sample: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # A sample pre-connect check 4 | # 5 | # Warms DNS before connecting to hosts in parallel 6 | # 7 | # These environment variables are available: 8 | # KAMAL_RECORDED_AT 9 | # KAMAL_PERFORMER 10 | # KAMAL_VERSION 11 | # KAMAL_HOSTS 12 | # KAMAL_ROLE (if set) 13 | # KAMAL_DESTINATION (if set) 14 | # KAMAL_RUNTIME 15 | 16 | hosts = ENV["KAMAL_HOSTS"].split(",") 17 | results = nil 18 | max = 3 19 | 20 | elapsed = Benchmark.realtime do 21 | results = hosts.map do |host| 22 | Thread.new do 23 | tries = 1 24 | 25 | begin 26 | Socket.getaddrinfo(host, 0, Socket::AF_UNSPEC, Socket::SOCK_STREAM, nil, Socket::AI_CANONNAME) 27 | rescue SocketError 28 | if tries < max 29 | puts "Retrying DNS warmup: #{host}" 30 | tries += 1 31 | sleep rand 32 | retry 33 | else 34 | puts "DNS warmup failed: #{host}" 35 | host 36 | end 37 | end 38 | 39 | tries 40 | end 41 | end.map(&:value) 42 | end 43 | 44 | retries = results.sum - hosts.size 45 | nopes = results.count { |r| r == max } 46 | 47 | puts "Prewarmed %d DNS lookups in %.2f sec: %d retries, %d failures" % [ hosts.size, elapsed, retries, nopes ] 48 | -------------------------------------------------------------------------------- /.kamal/hooks/pre-deploy.sample: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # A sample pre-deploy hook 4 | # 5 | # Checks the Github status of the build, waiting for a pending build to complete for up to 720 seconds. 6 | # 7 | # Fails unless the combined status is "success" 8 | # 9 | # These environment variables are available: 10 | # KAMAL_RECORDED_AT 11 | # KAMAL_PERFORMER 12 | # KAMAL_VERSION 13 | # KAMAL_HOSTS 14 | # KAMAL_COMMAND 15 | # KAMAL_SUBCOMMAND 16 | # KAMAL_ROLE (if set) 17 | # KAMAL_DESTINATION (if set) 18 | 19 | # Only check the build status for production deployments 20 | if ENV["KAMAL_COMMAND"] == "rollback" || ENV["KAMAL_DESTINATION"] != "production" 21 | exit 0 22 | end 23 | 24 | require "bundler/inline" 25 | 26 | # true = install gems so this is fast on repeat invocations 27 | gemfile(true, quiet: true) do 28 | source "https://rubygems.org" 29 | 30 | gem "octokit" 31 | gem "faraday-retry" 32 | end 33 | 34 | MAX_ATTEMPTS = 72 35 | ATTEMPTS_GAP = 10 36 | 37 | def exit_with_error(message) 38 | $stderr.puts message 39 | exit 1 40 | end 41 | 42 | class GithubStatusChecks 43 | attr_reader :remote_url, :git_sha, :github_client, :combined_status 44 | 45 | def initialize 46 | @remote_url = `git config --get remote.origin.url`.strip.delete_prefix("https://github.com/") 47 | @git_sha = `git rev-parse HEAD`.strip 48 | @github_client = Octokit::Client.new(access_token: ENV["GITHUB_TOKEN"]) 49 | refresh! 50 | end 51 | 52 | def refresh! 53 | @combined_status = github_client.combined_status(remote_url, git_sha) 54 | end 55 | 56 | def state 57 | combined_status[:state] 58 | end 59 | 60 | def first_status_url 61 | first_status = combined_status[:statuses].find { |status| status[:state] == state } 62 | first_status && first_status[:target_url] 63 | end 64 | 65 | def complete_count 66 | combined_status[:statuses].count { |status| status[:state] != "pending"} 67 | end 68 | 69 | def total_count 70 | combined_status[:statuses].count 71 | end 72 | 73 | def current_status 74 | if total_count > 0 75 | "Completed #{complete_count}/#{total_count} checks, see #{first_status_url} ..." 76 | else 77 | "Build not started..." 78 | end 79 | end 80 | end 81 | 82 | 83 | $stdout.sync = true 84 | 85 | puts "Checking build status..." 86 | attempts = 0 87 | checks = GithubStatusChecks.new 88 | 89 | begin 90 | loop do 91 | case checks.state 92 | when "success" 93 | puts "Checks passed, see #{checks.first_status_url}" 94 | exit 0 95 | when "failure" 96 | exit_with_error "Checks failed, see #{checks.first_status_url}" 97 | when "pending" 98 | attempts += 1 99 | end 100 | 101 | exit_with_error "Checks are still pending, gave up after #{MAX_ATTEMPTS * ATTEMPTS_GAP} seconds" if attempts == MAX_ATTEMPTS 102 | 103 | puts checks.current_status 104 | sleep(ATTEMPTS_GAP) 105 | checks.refresh! 106 | end 107 | rescue Octokit::NotFound 108 | exit_with_error "Build status could not be found" 109 | end 110 | -------------------------------------------------------------------------------- /.kamal/hooks/pre-proxy-reboot.sample: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | echo "Rebooting kamal-proxy on $KAMAL_HOSTS..." 4 | -------------------------------------------------------------------------------- /.kamal/secrets: -------------------------------------------------------------------------------- 1 | # Secrets defined here are available for reference under registry/password, env/secret, builder/secrets, 2 | # and accessories/*/env/secret in config/deploy.yml. All secrets should be pulled from either 3 | # password manager, ENV, or a file. DO NOT ENTER RAW CREDENTIALS HERE! This file needs to be safe for git. 4 | 5 | # Example of extracting secrets from 1password (or another compatible pw manager) 6 | # SECRETS=$(kamal secrets fetch --adapter 1password --account your-account --from Vault/Item KAMAL_REGISTRY_PASSWORD RAILS_MASTER_KEY) 7 | # KAMAL_REGISTRY_PASSWORD=$(kamal secrets extract KAMAL_REGISTRY_PASSWORD ${SECRETS}) 8 | # RAILS_MASTER_KEY=$(kamal secrets extract RAILS_MASTER_KEY ${SECRETS}) 9 | 10 | # Use a GITHUB_TOKEN if private repositories are needed for the image 11 | # GITHUB_TOKEN=$(gh config get -h github.com oauth_token) 12 | 13 | # Grab the registry password from ENV 14 | KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD 15 | 16 | # Improve security by using a password manager. Never check config/master.key into git! 17 | RAILS_MASTER_KEY=$(cat config/master.key) 18 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | # Omakase Ruby styling for Rails 2 | inherit_gem: { rubocop-rails-omakase: rubocop.yml } 3 | 4 | # Overwrite or add rules to create your own house style 5 | # 6 | # # Use `[a, [b, c]]` not `[ a, [ b, c ] ]` 7 | # Layout/SpaceInsideArrayLiteralBrackets: 8 | # Enabled: false 9 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-3.4.3 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | # check=error=true 3 | 4 | # This Dockerfile is designed for production, not development. Use with Kamal or build'n'run by hand: 5 | # docker build -t site . 6 | # docker run -d -p 80:80 -e RAILS_MASTER_KEY= --name site site 7 | 8 | # For a containerized dev environment, see Dev Containers: https://guides.rubyonrails.org/getting_started_with_devcontainer.html 9 | 10 | # Make sure RUBY_VERSION matches the Ruby version in .ruby-version 11 | ARG RUBY_VERSION=3.4.3 12 | FROM docker.io/library/ruby:$RUBY_VERSION-slim AS base 13 | 14 | # Rails app lives here 15 | WORKDIR /rails 16 | 17 | # Install base packages 18 | RUN apt-get update -qq && \ 19 | apt-get install --no-install-recommends -y curl libjemalloc2 libvips sqlite3 && \ 20 | apt-get install --no-install-recommends -y \ 21 | curl \ 22 | libjemalloc2 \ 23 | libvips \ 24 | sqlite3 \ 25 | libpq5 \ 26 | vim \ 27 | wget && \ 28 | rm -rf /var/lib/apt/lists /var/cache/apt/archives 29 | 30 | # Set production environment 31 | ENV RAILS_ENV="production" \ 32 | BUNDLE_DEPLOYMENT="1" \ 33 | BUNDLE_PATH="/usr/local/bundle" \ 34 | BUNDLE_WITHOUT="development" 35 | 36 | # Throw-away build stage to reduce size of final image 37 | FROM base AS build 38 | 39 | # Install packages needed to build gems 40 | RUN apt-get update -qq && \ 41 | apt-get install --no-install-recommends -y build-essential git pkg-config libpq-dev libyaml-dev && \ 42 | rm -rf /var/lib/apt/lists /var/cache/apt/archives 43 | 44 | # Install application gems 45 | COPY Gemfile Gemfile.lock ./ 46 | RUN bundle install && \ 47 | rm -rf ~/.bundle/ "${BUNDLE_PATH}"/ruby/*/cache "${BUNDLE_PATH}"/ruby/*/bundler/gems/*/.git && \ 48 | bundle exec bootsnap precompile --gemfile 49 | 50 | # Copy application code 51 | COPY . . 52 | 53 | # Precompile bootsnap code for faster boot times 54 | RUN bundle exec bootsnap precompile app/ lib/ 55 | 56 | # Precompiling assets for production without requiring secret RAILS_MASTER_KEY 57 | RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile 58 | 59 | # Final stage for app image 60 | FROM base 61 | 62 | # Copy built artifacts: gems, application 63 | COPY --from=build "${BUNDLE_PATH}" "${BUNDLE_PATH}" 64 | COPY --from=build /rails /rails 65 | COPY --from=build /usr/bin/git /usr/bin/git 66 | COPY --from=build /usr/lib/git-core /usr/lib/git-core 67 | 68 | # Run and own only the runtime files as a non-root user for security 69 | RUN groupadd --system --gid 1000 rails && \ 70 | useradd rails --uid 1000 --gid 1000 --create-home --shell /bin/bash && \ 71 | chown -R rails:rails db log storage tmp && \ 72 | mkdir -p content/projects && chown -R rails:rails content 73 | USER 1000:1000 74 | 75 | # Entrypoint prepares the database. 76 | ENTRYPOINT ["/rails/bin/docker-entrypoint"] 77 | 78 | # Start server via Thruster by default, this can be overwritten at runtime 79 | EXPOSE 80 80 | CMD ["./bin/thrust", "./bin/rails", "server"] 81 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Bundle edge Rails instead: gem "rails", github: "rails/rails", branch: "main" 4 | gem "rails", "~> 8.0.2" 5 | # The modern asset pipeline for Rails [https://github.com/rails/propshaft] 6 | gem "propshaft" 7 | # Use sqlite3 as the database for Active Record 8 | gem "sqlite3", ">= 2.1" 9 | # Use the Puma web server [https://github.com/puma/puma] 10 | gem "puma", ">= 5.0" 11 | # Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails] 12 | gem "importmap-rails" 13 | # Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev] 14 | gem "turbo-rails" 15 | # Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev] 16 | gem "stimulus-rails" 17 | # Build JSON APIs with ease [https://github.com/rails/jbuilder] 18 | gem "jbuilder" 19 | 20 | # Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] 21 | # gem "bcrypt", "~> 3.1.7" 22 | 23 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem 24 | gem "tzinfo-data", platforms: %i[ windows jruby ] 25 | 26 | # Use the database-backed adapters for Rails.cache, Active Job, and Action Cable 27 | gem "solid_cache" 28 | gem "solid_queue" 29 | gem "solid_cable" 30 | 31 | # Reduces boot times through caching; required in config/boot.rb 32 | gem "bootsnap", require: false 33 | 34 | # Deploy this application anywhere as a Docker container [https://kamal-deploy.org] 35 | gem "kamal", require: false 36 | 37 | # Add HTTP asset caching/compression and X-Sendfile acceleration to Puma [https://github.com/basecamp/thruster/] 38 | gem "thruster", require: false 39 | 40 | # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] 41 | gem "image_processing", "~> 1.2" 42 | 43 | # Use postgresql as the database for Active Record 44 | group :production do 45 | gem "pg", "~> 1.1" 46 | end 47 | 48 | group :development, :test do 49 | # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem 50 | gem "debug", platforms: %i[ mri windows ], require: "debug/prelude" 51 | 52 | # Static analysis for security vulnerabilities [https://brakemanscanner.org/] 53 | gem "brakeman", require: false 54 | 55 | # Omakase Ruby styling [https://github.com/rails/rubocop-rails-omakase/] 56 | gem "rubocop-rails-omakase", require: false 57 | end 58 | 59 | group :development do 60 | # Use console on exceptions pages [https://github.com/rails/web-console] 61 | gem "web-console" 62 | end 63 | 64 | group :test do 65 | # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing] 66 | gem "capybara" 67 | gem "selenium-webdriver" 68 | end 69 | 70 | gem "tailwindcss-ruby", "~> 4.1" 71 | 72 | gem "tailwindcss-rails", "~> 4.2" 73 | 74 | gem "kramdown" 75 | 76 | gem "airrecord" 77 | gem "dotenv" 78 | gem "redcarpet", "~> 3.6" 79 | 80 | gem "letter_opener", group: :development 81 | gem "letter_opener_web", group: :development 82 | 83 | gem "rails_live_reload" 84 | gem "awesome_print", "~> 1.9" 85 | 86 | # Environment variables 87 | gem "dotenv-rails", groups: [ :development, :test ] 88 | 89 | gem "good_job", "~> 4.10" 90 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Hack Club 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Procfile.dev: -------------------------------------------------------------------------------- 1 | web: bin/rails server 2 | css: bin/rails tailwindcss:watch 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Highway to Undercity 2 | 3 | Highway is a hardware grant program where you can design any project, and we'll send you the parts & funding up to 350 USD *per project* you need to build it! 4 | 5 | Repeat to get invited to Undercity, a 4-day hardware hackathon, July 11-14 @ GitHub HQ. 6 | 7 | There's both beginner & advanced tracks, so everyone is included. There'll be new content, freebies, and other awesome stuff from now until July 31st. 8 | 9 | ## How to start 10 | 11 | If you're making a custom project, this is your place to start! 12 | 13 | *Remember to read through the [Project guidelines](https://highway.hackclub.com/advanced/project-guidelines).* 14 | 15 | Fork this repo and head over to the submissions.yml file - add the URL of your project there. 16 | 17 | It should look something like this: 18 | 19 | ``` 20 | projects: 21 | - "https://github.com/Dongathan-Jong/SpotifyDisplay" 22 | - "your_repo_link" 23 | ``` 24 | 25 | We'll check if you have a README.md and JOURNAL.md file, and merge it after that. You're free to start working on your project! 26 | 27 | If you're making an Advanced custom project (grant up to 350 USD, 10 points) - remember to pitch it in #highway-pitstop first. 28 | 29 | ## How to submit 30 | 31 | Done your project + want to submit it to get your grant? Submit it in the form here: [https://forms.hackclub.com/highway](https://forms.hackclub.com/highway) 32 | 33 | Remember to read through the [submission guidelines](https://highway.hackclub.com/advanced/submitting) before submitting! 34 | 35 | # Ready. Set. Build! 36 | 37 | --- 38 | 39 | # Website development 40 | 41 | Ooooh, you're in the README to figure out how the actual highway website works? Sure! 42 | 43 | It's a standard rails codebase, but when you first start up you might want to run `bin/rails projects:clone` to download all the submissions. -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative "config/application" 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app/assets/builds/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/builds/.keep -------------------------------------------------------------------------------- /app/assets/fonts/dystopian.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/fonts/dystopian.otf -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/.keep -------------------------------------------------------------------------------- /app/assets/images/landing/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/bg.png -------------------------------------------------------------------------------- /app/assets/images/landing/box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/box.png -------------------------------------------------------------------------------- /app/assets/images/landing/hackpad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/hackpad.png -------------------------------------------------------------------------------- /app/assets/images/landing/landing2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/landing2.png -------------------------------------------------------------------------------- /app/assets/images/landing/landing3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/landing3.png -------------------------------------------------------------------------------- /app/assets/images/landing/landing4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/landing4.png -------------------------------------------------------------------------------- /app/assets/images/landing/landingbg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/landingbg.png -------------------------------------------------------------------------------- /app/assets/images/landing/landingbg2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/landingbg2.png -------------------------------------------------------------------------------- /app/assets/images/landing/landinglogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/landinglogo.png -------------------------------------------------------------------------------- /app/assets/images/landing/racecar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/racecar.png -------------------------------------------------------------------------------- /app/assets/images/landing/racetrack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/racetrack.png -------------------------------------------------------------------------------- /app/assets/images/landing/shards.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/shards.png -------------------------------------------------------------------------------- /app/assets/images/landing/sign1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/sign1.png -------------------------------------------------------------------------------- /app/assets/images/landing/sign2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/sign2.png -------------------------------------------------------------------------------- /app/assets/images/landing/sign3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/sign3.png -------------------------------------------------------------------------------- /app/assets/images/landing/speaker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/speaker.png -------------------------------------------------------------------------------- /app/assets/images/landing/stick1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/stick1.png -------------------------------------------------------------------------------- /app/assets/images/landing/stick2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/stick2.png -------------------------------------------------------------------------------- /app/assets/images/landing/stick3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/stick3.png -------------------------------------------------------------------------------- /app/assets/images/landing/stick4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/stick4.png -------------------------------------------------------------------------------- /app/assets/images/landing/stick5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/stick5.png -------------------------------------------------------------------------------- /app/assets/images/landing/stick6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/stick6.png -------------------------------------------------------------------------------- /app/assets/images/landing/tracks1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/tracks1.png -------------------------------------------------------------------------------- /app/assets/images/landing/tracks2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/landing/tracks2.png -------------------------------------------------------------------------------- /app/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/logo.png -------------------------------------------------------------------------------- /app/assets/images/mystery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/assets/images/mystery.png -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css. 3 | * 4 | * With Propshaft, assets are served efficiently without preprocessing steps. You can still include 5 | * application-wide styles in this file, but keep in mind that CSS precedence will follow the standard 6 | * cascading order, meaning styles declared later in the document or manifest will override earlier ones, 7 | * depending on specificity. 8 | * 9 | * Consider organizing styles into separate files for maintainability. 10 | */ 11 | 12 | @import "landing"; 13 | 14 | body { 15 | font-family: "Poppins", sans-serif; 16 | } -------------------------------------------------------------------------------- /app/assets/stylesheets/landing.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | padding: 0; 4 | height: 100%; 5 | background-image: url('/assets/landing/bg.png'); 6 | background-repeat: repeat; 7 | image-rendering: pixelated; 8 | image-rendering: -moz-crisp-edges; 9 | image-rendering: crisp-edges; 10 | scroll-behavior: smooth; 11 | } 12 | 13 | html { 14 | background-color: #272239; 15 | color: white; 16 | } 17 | 18 | /* Ensure the image container takes full width */ 19 | img { 20 | display: block; 21 | width: 100%; 22 | height: auto; 23 | image-rendering: pixelated; 24 | image-rendering: -moz-crisp-edges; 25 | image-rendering: crisp-edges; 26 | } 27 | 28 | .pixelated-image { 29 | image-rendering: pixelated; 30 | image-rendering: -moz-crisp-edges; 31 | image-rendering: crisp-edges; 32 | } 33 | 34 | .landing-container { 35 | position: relative; 36 | text-align: center; 37 | } 38 | 39 | .landing-text { 40 | background-color: #2C2B2B; 41 | color: white; 42 | border: 10px solid #FFE6FF; 43 | border-radius: 17px; 44 | padding: 32px 48px; 45 | text-align: center; 46 | margin: 20px auto; 47 | display: inline-block; 48 | 49 | } 50 | 51 | 52 | .landing-text-container { 53 | position: absolute; 54 | top: 50%; 55 | left: 50%; 56 | transform: translate(-50%, -50%); 57 | } 58 | .landing-text.title { 59 | font-size: 120px; 60 | transform: rotate(-2deg) 61 | 62 | } 63 | 64 | .landing-text.subtitle { 65 | padding: 24px 32px; 66 | 67 | } 68 | 69 | @keyframes bobble { 70 | 0%, 100% { 71 | transform: translateY(0); 72 | } 73 | 50% { 74 | transform: translateY(-10px); 75 | } 76 | } 77 | 78 | .animate-bobble { 79 | animation: bobble 1.5s infinite; 80 | } 81 | 82 | -------------------------------------------------------------------------------- /app/assets/stylesheets/markdown.css: -------------------------------------------------------------------------------- 1 | .markdown-content { 2 | line-height: 1.65; 3 | font-size: 0.75rem; 4 | font-weight: 400; 5 | color: #ded9e5; 6 | } 7 | 8 | .markdown-content h1 { 9 | font-size: 2.5em; 10 | font-weight: bold; 11 | color: #FFFFFF; 12 | margin-bottom: 1.8rem; 13 | border-bottom: 2px solid #433d67; 14 | padding-bottom: 0.2rem; 15 | } 16 | 17 | .markdown-content h2 { 18 | font-size: 2em; 19 | font-weight: 600; 20 | color: #FFFFFF; 21 | margin-top: 1.75rem; 22 | margin-bottom: 1.25rem; 23 | } 24 | 25 | .markdown-content h3 { 26 | font-size: 1.5em; 27 | font-weight: 600; 28 | color: #FFFFFF; 29 | margin-top: 1.5rem; 30 | margin-bottom: 1rem; 31 | } 32 | 33 | .markdown-content h4 { 34 | font-size: 1.25em; 35 | font-weight: 550; 36 | color: #86e3a8; 37 | margin-bottom: 1rem; 38 | } 39 | 40 | .markdown-content p { 41 | font-size: 1rem; 42 | margin-bottom: 1rem; 43 | margin-top: 1rem; 44 | font-family: "Poppins", sans-serif; 45 | } 46 | 47 | .markdown-content ul { 48 | list-style-type: circle; 49 | margin-left: 1.5rem; 50 | line-height: 2; 51 | font-size: 1rem; 52 | } 53 | 54 | .markdown-content ul:not(.markdown-content ul ul) { 55 | /* padding-bottom: 1.5rem; */ 56 | list-style-type: disc; 57 | } 58 | 59 | .markdown-content ol { 60 | list-style-type: decimal; 61 | margin-left: 1.5rem; 62 | /* margin-bottom: 1rem; */ 63 | margin-top: 1rem; 64 | line-height: 2; 65 | font-size: 1.1rem; 66 | font-weight: 550; 67 | } 68 | 69 | .markdown-content hr { 70 | border: 0; 71 | height: 6px; 72 | background-color: #605989; 73 | margin: 2rem 0; 74 | } 75 | 76 | .markdown-content blockquote { 77 | border-left: 4px solid #ccc; 78 | padding-left: 1rem; 79 | color: #666; 80 | font-style: italic; 81 | } 82 | 83 | .markdown-content a { 84 | color: #f583e4; 85 | text-decoration: underline; 86 | font-weight: bold; 87 | word-break: break-word; 88 | } 89 | 90 | .markdown-content a:hover { 91 | color: #f1b6e8; 92 | text-decoration: underline; 93 | font-weight: extra-bold; 94 | } 95 | 96 | .markdown-content strong { 97 | font-weight: 600; 98 | color: #ffffff; 99 | } 100 | 101 | .markdown-content pre { 102 | background-color: #3c3672; 103 | border-color:#d1cadb; 104 | border-width: 1px; 105 | color: #d1cadb; 106 | padding: 1rem; 107 | border-radius: 0px; 108 | overflow-x: auto; 109 | } 110 | 111 | .markdown-content code { 112 | background-color: #3c3672; 113 | color: #ffffff; 114 | font-size: 0.9rem; 115 | padding: 0.2rem 0.4rem; 116 | } 117 | 118 | 119 | .project-img img { 120 | width: 800px; 121 | } 122 | 123 | /* 124 | 125 | div styling, probably don't need to touch this part. 126 | 127 | */ 128 | div.markdown li { 129 | display: list-item; 130 | } 131 | 132 | div.markdown ul { 133 | display: block; 134 | list-style-type: disc; 135 | margin-left: 0; 136 | margin-right: 0; 137 | padding-left: 40px; 138 | } 139 | 140 | div.markdown ol { 141 | display: block; 142 | list-style-type: decimal; 143 | margin-left: 0; 144 | margin-right: 0; 145 | padding-left: 40px; 146 | } 147 | 148 | div.markdown p:last-child { 149 | padding-bottom: 5rem; 150 | } 151 | 152 | -------------------------------------------------------------------------------- /app/assets/tailwind/application.css: -------------------------------------------------------------------------------- 1 | @import "tailwindcss"; 2 | 3 | @font-face { 4 | font-family: Dystopian; 5 | src: url('/dystopian.otf') format('opentype'); 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | @theme { 11 | --font-dystopian: "Dystopian", sans-serif; 12 | --font-poppins: "Poppins", sans-serif; 13 | } 14 | 15 | .glow { 16 | text-shadow: 0 0 10px #095f59, 0 0 20px #095f59, 0 0 30px #095f59; 17 | color: white; 18 | } -------------------------------------------------------------------------------- /app/controllers/admin_controller.rb: -------------------------------------------------------------------------------- 1 | class AdminController < ApplicationController 2 | before_action :require_authentication 3 | before_action :authenticate_user 4 | 5 | def dashboard 6 | @users = User.all 7 | @posts = Post.all 8 | @projects = Project.all 9 | end 10 | 11 | private 12 | 13 | def authenticate_user 14 | unless current_user && current_user.admin? 15 | redirect_to root_path 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /app/controllers/advanced_controller.rb: -------------------------------------------------------------------------------- 1 | class AdvancedController < MarkdownController 2 | end 3 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | # Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has. 3 | # allow_browser versions: :modern 4 | 5 | helper_method :current_user 6 | 7 | private 8 | def current_user 9 | @current_user ||= User.find_by(id: session[:user_id]) if session[:user_id] 10 | end 11 | 12 | def authenticated? 13 | current_user.present? 14 | end 15 | 16 | def require_authentication 17 | unless authenticated? 18 | redirect_to root_path, alert: "You must be signed in to access this page." 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/concerns/markdown_renderable.rb: -------------------------------------------------------------------------------- 1 | module MarkdownRenderable 2 | extend ActiveSupport::Concern 3 | 4 | class_methods do 5 | def render_markdown(text, user = nil, project_name = nil) 6 | return "" if text.blank? 7 | 8 | renderer = if user && project_name 9 | Class.new(Redcarpet::Render::HTML) do 10 | def initialize(user, project_name) 11 | @user = user 12 | @project_name = project_name 13 | super() 14 | end 15 | 16 | def image(link, title, alt_text) 17 | # If the link is a relative path, rewrite it 18 | unless link =~ %r{^https?://} 19 | link = "/projects/#{@user}/#{@project_name}/#{link}" 20 | end 21 | "\"#{alt_text}\"" 22 | end 23 | 24 | def postprocess(full_document) 25 | # Only rewrite src attributes in img tags that don't already have the project path 26 | full_document.gsub(/]+src="([^"]+)"[^>]*>/) do |match| 27 | src = $1 28 | unless src =~ %r{^https?://} || src.start_with?("/projects/#{@user}/#{@project_name}/") 29 | src = "/projects/#{@user}/#{@project_name}/#{src}" 30 | end 31 | match.gsub(/src="[^"]+"/, "src=\"#{src}\"") 32 | end 33 | end 34 | end.new(user, project_name) 35 | else 36 | Redcarpet::Render::HTML 37 | end 38 | 39 | markdown = Redcarpet::Markdown.new( 40 | renderer, 41 | autolink: true, 42 | tables: true, 43 | fenced_code_blocks: true, 44 | strikethrough: true, 45 | superscript: true, 46 | underline: true, 47 | highlight: true, 48 | quote: true, 49 | footnotes: true 50 | ) 51 | 52 | markdown.render(text).html_safe 53 | end 54 | end 55 | 56 | private 57 | 58 | def render_markdown(text, user = nil, project_name = nil) 59 | self.class.render_markdown(text, user, project_name) 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /app/controllers/events_controller.rb: -------------------------------------------------------------------------------- 1 | class EventsController < ApplicationController 2 | end 3 | -------------------------------------------------------------------------------- /app/controllers/guides_controller.rb: -------------------------------------------------------------------------------- 1 | class GuidesController < MarkdownController 2 | end 3 | -------------------------------------------------------------------------------- /app/controllers/info_controller.rb: -------------------------------------------------------------------------------- 1 | class InfoController < MarkdownController 2 | def show 3 | markdown_file_path = Rails.root.join("app", "views", "info", "index.md") 4 | if File.exist?(markdown_file_path) 5 | markdown_content = File.read(markdown_file_path) 6 | @content = render_markdown(markdown_content) 7 | else 8 | @content = "

Markdown file not found.

" 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /app/controllers/landing_controller.rb: -------------------------------------------------------------------------------- 1 | class LandingController < ApplicationController 2 | def index 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/controllers/launchpad_controller.rb: -------------------------------------------------------------------------------- 1 | class LaunchpadController < ApplicationController 2 | def show 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/controllers/markdown_controller.rb: -------------------------------------------------------------------------------- 1 | class MarkdownController < ApplicationController 2 | include MarkdownRenderable 3 | 4 | def show 5 | # Get the requested page from the URL 6 | page = params[:page] 7 | 8 | # Sanitize the page parameter to prevent directory traversal 9 | sanitized_page = sanitize_page(page) 10 | 11 | # Build the file path for the Markdown file 12 | file_path = Rails.root.join("app", "views", controller_name, "#{sanitized_page}.md") 13 | 14 | # Check if the file exists 15 | if File.exist?(file_path) 16 | # Read and render the Markdown file 17 | markdown = File.read(file_path) 18 | @content = render_markdown(markdown) 19 | render layout: controller_name 20 | else 21 | # Render a 404 page if the file doesn't exist 22 | render plain: "Page not found", status: :not_found 23 | end 24 | end 25 | 26 | private 27 | 28 | # Sanitize the page parameter to prevent directory traversal 29 | def sanitize_page(page) 30 | # Allow only alphanumeric characters, dashes, and underscores 31 | page.gsub(/[^a-zA-Z0-9_-]/, "") 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /app/controllers/overview_controller.rb: -------------------------------------------------------------------------------- 1 | class OverviewController < MarkdownController 2 | end 3 | -------------------------------------------------------------------------------- /app/controllers/projects_controller.rb: -------------------------------------------------------------------------------- 1 | class ProjectsController < ApplicationController 2 | include HasFrontmatter 3 | 4 | def index 5 | @projects = Project.all 6 | 7 | CloneProjectsJob.perform_later if @projects.empty? 8 | end 9 | 10 | def show 11 | @project = Project.find(params[:user], params[:project_name]) 12 | render_not_found unless @project.present? 13 | end 14 | 15 | def new 16 | end 17 | 18 | private 19 | 20 | def load_projects 21 | projects = [] 22 | Dir.glob(Rails.root.join("content/projects/*/*/journal.md")).each do |file| 23 | content = File.read(file) 24 | metadata, _ = parse_frontmatter(content) 25 | 26 | # Extract repo and project name from path 27 | path_parts = file.split("/") 28 | repo = path_parts[-3] 29 | project_name = path_parts[-2] 30 | 31 | projects << { 32 | repo: repo, 33 | project_name: project_name, 34 | title: metadata["title"], 35 | author: metadata["author"], 36 | description: metadata["description"], 37 | created_at: metadata["created_at"] 38 | } 39 | end 40 | projects.sort_by { |p| p[:created_at] }.reverse 41 | end 42 | 43 | def load_project(repo, project_name) 44 | file_path = Rails.root.join("content/projects", repo, project_name, "journal.md") 45 | return nil unless File.exist?(file_path) 46 | 47 | content = File.read(file_path) 48 | metadata, markdown_content = parse_frontmatter(content) 49 | 50 | { 51 | repo: repo, 52 | project_name: project_name, 53 | title: metadata["title"], 54 | author: metadata["author"], 55 | description: metadata["description"], 56 | created_at: metadata["created_at"], 57 | content: render_markdown(markdown_content) 58 | } 59 | end 60 | 61 | def render_not_found 62 | render file: "#{Rails.root}/public/404.html", status: :not_found 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /app/controllers/rsvps_controller.rb: -------------------------------------------------------------------------------- 1 | class RsvpsController < ApplicationController 2 | def create 3 | @rsvp = Rsvp.find_or_create_by_email!(rsvp_params[:email]) 4 | Rsvp.invite_to_slack(rsvp_params[:email]) 5 | if @rsvp.airtable_record_id.blank? 6 | @rsvp.update!(url_params: rsvp_params[:url_params]) 7 | end 8 | redirect_to root_path, flash: { notice: "Thanks for your interest; check your email for next steps!" } 9 | rescue ActiveRecord::RecordInvalid 10 | redirect_to root_path, flash: { alert: "Please enter a valid email address." } 11 | rescue => e 12 | redirect_to root_path, flash: { alert: "#{e.message}" } 13 | end 14 | 15 | private 16 | 17 | def rsvp_params 18 | params.permit(:email, :url_params, :authenticity_token, :commit) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /app/controllers/sessions_controller.rb: -------------------------------------------------------------------------------- 1 | class SessionsController < ApplicationController 2 | end 3 | -------------------------------------------------------------------------------- /app/controllers/users_controller.rb: -------------------------------------------------------------------------------- 1 | class UsersController < ApplicationController 2 | before_action :set_user, only: %i[ show edit update ] 3 | before_action :require_authentication, only: [ :show, :edit, :update, :prize_box ] 4 | 5 | 6 | # def index 7 | # @users = User.all 8 | # end 9 | 10 | def show 11 | end 12 | 13 | # def new 14 | # @user = User.new 15 | # end 16 | 17 | # def create 18 | # @user = user.new(user_params) 19 | # if @user.save 20 | # redirect_to @user 21 | # else 22 | # render :new, status: :unprocessable_entity 23 | # end 24 | # end 25 | 26 | def edit 27 | end 28 | 29 | def update 30 | if @user.update(user_params) 31 | redirect_to @user, notice: "User was successfully updated." 32 | else 33 | render :edit, status: :unprocessable_entity 34 | end 35 | end 36 | 37 | def prize_box 38 | # No need to set anything special - the view will use current_user 39 | end 40 | 41 | private 42 | 43 | def set_user 44 | @user = User.find(params[:id]) 45 | end 46 | 47 | def user_params 48 | params.expect(user: [ :email, :first_name, :last_name, :github, :username ]) 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | def show_sidebar? 3 | !current_page?(root_path) 4 | end 5 | 6 | def markdown_to_html(markdown) 7 | Kramdown::Document.new(markdown).to_html 8 | end 9 | 10 | def link_to(name = nil, options = nil, html_options = nil, &block) 11 | # warning might be jank. it's overriding the default link_to method lol. 12 | if block 13 | options ||= {} 14 | new_options = options 15 | else 16 | html_options ||= {} 17 | new_options = html_options 18 | end 19 | new_options[:class] ||= [] 20 | if new_options[:class].is_a? Array 21 | new_options[:class] << "btn" 22 | else 23 | new_options[:class] << " btn" 24 | end 25 | super(name, options, html_options, &block) 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /app/helpers/events_helper.rb: -------------------------------------------------------------------------------- 1 | module EventsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/guides_helper.rb: -------------------------------------------------------------------------------- 1 | module GuidesHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/info_helper.rb: -------------------------------------------------------------------------------- 1 | module InfoHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/launchpad_helper.rb: -------------------------------------------------------------------------------- 1 | module LaunchpadHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/overview_helper.rb: -------------------------------------------------------------------------------- 1 | module OverviewHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/posts_helper.rb: -------------------------------------------------------------------------------- 1 | module PostsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/sessions_helper.rb: -------------------------------------------------------------------------------- 1 | module SessionsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/javascript/application.js: -------------------------------------------------------------------------------- 1 | // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails 2 | import "@hotwired/turbo-rails" 3 | import "controllers" 4 | 5 | import "trix" 6 | import "@rails/actiontext" 7 | 8 | 9 | const audio = new Audio('https://hc-cdn.hel1.your-objectstorage.com/s/v3/98df9f1054b50821b1d2208a7d3386a2408134be_d3bd3f0972d62d58cdfce91bc042d32ee643aa94_ui_button_confirm_audio__mp3cut.net__audio.mp4'); 10 | audio.volume = 0.5 11 | document.addEventListener('click', (event) => { 12 | var myAudio = document.getElementById('background-audio'); 13 | let el = event.target.closest('a.btn'); 14 | if (el && ((myAudio && !myAudio.muted))) { 15 | audio.play(); 16 | } 17 | }); -------------------------------------------------------------------------------- /app/javascript/controllers/application.js: -------------------------------------------------------------------------------- 1 | import { Application } from "@hotwired/stimulus" 2 | 3 | const application = Application.start() 4 | 5 | // Configure Stimulus development experience 6 | application.debug = false 7 | window.Stimulus = application 8 | 9 | export { application } 10 | -------------------------------------------------------------------------------- /app/javascript/controllers/hello_controller.js: -------------------------------------------------------------------------------- 1 | import { Controller } from "@hotwired/stimulus" 2 | 3 | export default class extends Controller { 4 | connect() { 5 | this.element.textContent = "Hello World!" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/javascript/controllers/index.js: -------------------------------------------------------------------------------- 1 | // Import and register all your controllers from the importmap via controllers/**/*_controller 2 | import { application } from "controllers/application" 3 | import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading" 4 | eagerLoadControllersFrom("controllers", application) 5 | -------------------------------------------------------------------------------- /app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | # Automatically retry jobs that encountered a deadlock 3 | # retry_on ActiveRecord::Deadlocked 4 | 5 | # Most jobs are safe to ignore if the underlying records are no longer available 6 | # discard_on ActiveJob::DeserializationError 7 | end 8 | -------------------------------------------------------------------------------- /app/jobs/clone_projects_job.rb: -------------------------------------------------------------------------------- 1 | class CloneProjectsJob < ApplicationJob 2 | queue_as :default 3 | 4 | def perform 5 | submissions = YAML.load_file(Rails.root.join("submissions.yml")) 6 | urls = submissions["projects"].map do |url| 7 | url = url.chomp("/") 8 | url = "#{url}.git" unless url.end_with?(".git") 9 | url 10 | end 11 | 12 | queue = Queue.new 13 | urls.each { |url| queue << url } 14 | 15 | threads = 5.times.map do 16 | Thread.new do 17 | while url = queue.pop(true) rescue nil 18 | org, repo = url.gsub("https://github.com/", "").gsub(".git", "").split("/") 19 | org = org.downcase 20 | repo = repo.downcase 21 | target_dir = File.join(Rails.root, "content", "projects", org, repo) 22 | 23 | if Dir.exist?(target_dir) && Dir.exist?(File.join(target_dir, ".git")) 24 | Rails.logger.info "Pulling latest for #{org}/#{repo}..." 25 | system("cd '#{target_dir}' && git pull") 26 | else 27 | Rails.logger.info "Cloning #{org}/#{repo}..." 28 | system("git clone #{url} '#{target_dir}'") 29 | end 30 | end 31 | end 32 | end 33 | 34 | threads.each(&:join) 35 | 36 | Rails.logger.info "Done cloning and updating all projects!" 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /app/jobs/sync_rsvp_with_airtable_job.rb: -------------------------------------------------------------------------------- 1 | class SyncRsvpWithAirtableJob < ApplicationJob 2 | queue_as :default 3 | 4 | def perform(rsvp_id) 5 | rsvp = Rsvp.find(rsvp_id) 6 | rsvp.sync_with_airtable! 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: "from@example.com" 3 | layout "mailer" 4 | end 5 | -------------------------------------------------------------------------------- /app/mailers/session_mailer.rb: -------------------------------------------------------------------------------- 1 | class SessionMailer < ApplicationMailer 2 | # Subject can be set in your I18n file at config/locales/en.yml 3 | # with the following lookup: 4 | # 5 | include Rails.application.routes.url_helpers 6 | # en.session_mailer.login_token.subject 7 | def login_code(email:, login_code:) 8 | @greeting = "Hi" 9 | @login_code = login_code 10 | @signin_link = exchange_code_url(code: @login_code) 11 | # debugger 12 | 13 | mail to: email 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | primary_abstract_class 3 | end 4 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/models/concerns/has_frontmatter.rb: -------------------------------------------------------------------------------- 1 | module HasFrontmatter 2 | extend ActiveSupport::Concern 3 | 4 | class_methods do 5 | def parse_frontmatter(content) 6 | if content =~ /\A(---\s*\n.*?\n?)^(---\s*$\n?)(.*)/m 7 | begin 8 | metadata = YAML.safe_load($1) 9 | metadata = {} unless metadata.is_a?(Hash) 10 | rescue Psych::SyntaxError, StandardError => e 11 | Rails.logger.warn "Failed to parse frontmatter: #{e.message}" 12 | metadata = {} 13 | end 14 | content = $3 15 | [ safe_parse_metadata(metadata), content ] 16 | else 17 | [ {}, content ] 18 | end 19 | end 20 | 21 | private 22 | 23 | def safe_parse_metadata(metadata) 24 | { 25 | "title" => safe_parse_field(metadata, "title"), 26 | "author" => safe_parse_field(metadata, "author"), 27 | "description" => safe_parse_field(metadata, "description"), 28 | "created_at" => safe_parse_date(metadata, "created_at") 29 | } 30 | end 31 | 32 | def safe_parse_field(metadata, field) 33 | return nil unless metadata.is_a?(Hash) 34 | value = metadata[field] 35 | return nil if value.nil? 36 | value.to_s.strip 37 | end 38 | 39 | def safe_parse_date(metadata, field) 40 | return nil unless metadata.is_a?(Hash) 41 | value = metadata[field] 42 | return nil if value.nil? 43 | 44 | begin 45 | Date.parse(value.to_s) 46 | rescue Date::Error 47 | nil 48 | end 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /app/models/post.rb: -------------------------------------------------------------------------------- 1 | class Post < ApplicationRecord 2 | has_one_attached :featured_image 3 | has_rich_text :description 4 | belongs_to :user 5 | belongs_to :project 6 | validates :description, presence: true 7 | validates :name, presence: true 8 | validates :hours, presence: true, numericality: { less_than_or_equal_to: 5, greater_than_or_equal_to: 0 } 9 | validates :featured_image, presence: true 10 | end 11 | -------------------------------------------------------------------------------- /app/models/prize.rb: -------------------------------------------------------------------------------- 1 | class Prize < ApplicationRecord 2 | has_one_attached :image # Stores prize images 3 | has_many :user_prizes 4 | has_many :users, through: :user_prizes 5 | end 6 | -------------------------------------------------------------------------------- /app/models/rsvp.rb: -------------------------------------------------------------------------------- 1 | class Rsvp < ApplicationRecord 2 | validates :email, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP } 3 | 4 | after_create :enqueue_airtable_sync 5 | 6 | def self.find_or_create_by_email!(email) 7 | find_or_create_by!(email: email.downcase.strip) 8 | end 9 | 10 | def self.invite_to_slack(email) 11 | channels = [ 12 | "C75M7C0SY", # #welcome 13 | "C039PAG1AV7", # #slack-welcome-start 14 | "C08Q1H6D79B", # #highway 15 | "C08PJ6G88QN", # #highway-announcements 16 | "C08S22XRYMU" # #highway-pitstop 17 | ].join(",") 18 | 19 | uri = URI("https://slack.com/api/users.admin.inviteBulk") 20 | headers = { 21 | "Cookie" => "d=#{ENV.fetch('SLACK_COOKIE')}", 22 | "Content-Type" => "application/json", 23 | "Authorization" => "Bearer #{ENV.fetch('SLACK_BROWSER_TOKEN')}" 24 | } 25 | data = { 26 | token: ENV.fetch("SLACK_BROWSER_TOKEN"), 27 | invites: [ 28 | { 29 | email: email, 30 | type: "restricted", 31 | mode: "manual" 32 | } 33 | ], 34 | restricted: true, 35 | channels: channels 36 | } 37 | http = Net::HTTP.new(uri.hostname, uri.port) 38 | http.use_ssl = true 39 | request = Net::HTTP::Post.new(uri, headers) 40 | request.body = data.to_json 41 | response = http.request(request) 42 | j = JSON.parse(response.body) 43 | raise "Slack API general error: #{j['error']}" unless j["ok"] 44 | raise "Slack API error: successful but no invites" if !j["invites"] || j["invites"].empty? 45 | raise "Slack API error on invite: #{j["invites"][0]["error"]}" unless j["invites"][0]["ok"] 46 | { ok: true } 47 | end 48 | 49 | def sync_with_airtable! 50 | uri = URI("https://api.airtable.com/v0/appuDQSHCdCHyOrxw/tblhGTc3WX9nYzU18") 51 | 52 | request = Net::HTTP::Patch.new(uri) 53 | request["Authorization"] = "Bearer #{ENV.fetch("AIRTABLE_API_KEY")}" 54 | request["Content-Type"] = "application/json" 55 | request.body = { 56 | performUpsert: { 57 | fieldsToMergeOn: [ "email" ] 58 | }, 59 | records: [ 60 | { 61 | fields: { 62 | email: email, 63 | url_params: url_params 64 | } 65 | } 66 | ] 67 | }.to_json 68 | 69 | response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http| 70 | http.request(request) 71 | end 72 | 73 | puts response.body 74 | 75 | self.airtable_record_id = JSON.parse(response.body).dig("records", 0, "id") 76 | save! 77 | end 78 | 79 | private 80 | 81 | def enqueue_airtable_sync 82 | SyncRsvpWithAirtableJob.perform_later(id) 83 | end 84 | end 85 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ApplicationRecord 2 | validates :email, uniqueness: true, presence: true, allow_nil: false 3 | 4 | has_many :posts, dependent: :destroy 5 | has_many :projects, dependent: :destroy 6 | has_many :user_prizes, dependent: :destroy 7 | has_many :prizes, through: :user_prizes 8 | 9 | def name 10 | "#{first_name} #{last_name}" 11 | end 12 | 13 | def prize_box 14 | user_prizes.where(claimed: false) 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/models/user_prize.rb: -------------------------------------------------------------------------------- 1 | class UserPrize < ApplicationRecord 2 | belongs_to :user 3 | belongs_to :prize 4 | 5 | scope :unclaimed, -> { where(claimed: false) } 6 | scope :claimed, -> { where(claimed: true) } 7 | 8 | def claim! 9 | update!(claimed: true, claimed_at: Time.current, tracking_number: generate_tracking_number) 10 | end 11 | 12 | private 13 | def generate_tracking_number 14 | "TN-#{SecureRandom.alphanumeric(10).upcase}" 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /app/views/active_storage/blobs/_blob.html.erb: -------------------------------------------------------------------------------- 1 |
attachment--<%= blob.filename.extension %>"> 2 | <% if blob.representable? %> 3 | <%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %> 4 | <% end %> 5 | 6 |
7 | <% if caption = blob.try(:caption) %> 8 | <%= caption %> 9 | <% else %> 10 | <%= blob.filename %> 11 | <%= number_to_human_size blob.byte_size %> 12 | <% end %> 13 |
14 |
15 | -------------------------------------------------------------------------------- /app/views/admin/dashboard.html.erb: -------------------------------------------------------------------------------- 1 |

Admin Dashboard

2 | 3 |

Projects

4 | <%= (ap @projects).html_safe %> 5 | 6 |

Users

7 | <%= (ap @users).html_safe %> 8 | 9 |

Posts

10 | <%= (ap @posts).html_safe %> -------------------------------------------------------------------------------- /app/views/advanced/_sidebar.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | <%# link_to "Projects", projects_path, class: "#{current_page?(projects_path) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 rounded transition duration-100 block" %> 5 | <%= link_to "Overview", advanced_page_path("overview"), class: "#{current_page?(advanced_page_path("overview")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-6 rounded transition duration-100 block font-dystopian" %> 6 | <%= link_to "Project Guidelines", advanced_page_path("project-guidelines"), class: "#{current_page?(advanced_page_path("project-guidelines")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-6 rounded transition duration-100 block font-dystopian" %> 7 | <%= link_to "Submitting", advanced_page_path("submitting"), class: "#{current_page?(advanced_page_path("submitting")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-6 rounded transition duration-100 block font-dystopian" %> 8 | <%= link_to "Start your design", advanced_page_path("design-guide"), class: "#{current_page?(advanced_page_path("design-guide")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-6 rounded transition duration-100 block font-dystopian" %> 9 | 10 |

Extra info:

11 | <%= link_to "Part Sourcing", advanced_page_path("part-sourcing"), class: "#{current_page?(advanced_page_path("part-sourcing")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-6 rounded transition duration-100 block font-dystopian" %> 12 | <%= link_to "Resources & tips", advanced_page_path("resources"), class: "#{current_page?(advanced_page_path("resources")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-6 rounded transition duration-100 block font-dystopian" %> 13 | <%= link_to "What is shipping?", advanced_page_path("shipping"), class: "#{current_page?(advanced_page_path("shipping")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 rounded transition duration-100 block font-dystopian" %> 14 | <%= link_to "Project ideas", advanced_page_path("ideas"), class: "#{current_page?(advanced_page_path("ideas")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 rounded transition duration-100 block font-dystopian" %> 15 | <%= link_to "Troubleshooting", advanced_page_path("troubleshooting"), class: "#{current_page?(advanced_page_path("troubleshooting")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 rounded transition duration-100 block font-dystopian" %> 16 | <%# <%= link_to "Other communities", advanced_page_path("faq"), class: "#{current_page?(advanced_page_path("submit")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 rounded transition duration-100 block font-dystopian" %> 17 |
18 |
19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /app/views/advanced/communities.md: -------------------------------------------------------------------------------- 1 | # Other communities 2 | 3 | Hack Club is a *great* place, but the the truth is that we're really small too! One of the best ways to learn is to immerse yourself in other communities. Here's some of them: 4 | 5 | ### Discords 6 | - VORON Discord 7 | - QMK discord 8 | 9 | ### Subreddits 10 | - Keyboards 11 | - Mechanical 12 | 13 | # MORE COMING SOON. -------------------------------------------------------------------------------- /app/views/advanced/design-guide.md: -------------------------------------------------------------------------------- 1 | # Designing your own projects 2 | 3 | Designing your own projects is really, *really* hard. Here's my best explainer at what the process sort of looks like, but every person's process is different! You'll have to figure a lot of this stuff out on your own. 4 | 5 | ## Overview 6 | 7 | You can split this entire process up into approximately 4-5 different steps, depending on what the project is. 8 | 9 | During this entire process you're going to have to do a LOT of research on sourcing parts and what the pros and cons of getting each would be. During this time, PLEASE check out the [Part Sourcing](advanced/part-sourcing) guide to get a better idea of the options 10 | 11 | --- 12 | 13 | ### 1. Vision, ideas, and outline 14 | 15 | This is the first step of the process! During this time, you should figure out what you want your project should be, the constraints, and specific features you want. 16 | 17 | --- 18 | 19 | ### 1.1. Electrical component selection & sourcing 20 | 21 | Next up is to pick the components for that 22 | 23 | Try to avoid getting hung up passives. If there's multiple parts that are the same functionality 24 | 25 | For actual sourcing & finding links, please refer to the [Part Sourcing](advanced/part-sourcing) guide 26 | 27 | --- 28 | 29 | ### 2. CAD 30 | 31 | --- 32 | 33 | ### 4. PCB 34 | 35 | --- 36 | 37 | ### 5. Firmware 38 | 39 | --- 40 | 41 | 42 | ## Closing words 43 | 44 | Keep in mind that almost every step above will be connected with each other. That means edits in #5 will mean you have to change #2, which might change #4, and then #2, etc. Hardware projects are *hard*. There's a lot of iteration involved. Good luck! -------------------------------------------------------------------------------- /app/views/advanced/example-journal.md: -------------------------------------------------------------------------------- 1 | # Example journal entry 2 | Here's an example journal entry - it's a little long so I put it on a separate page. 3 | 4 | It's for a retro game console I'm building that runs on a Raspberry Pi Zero 2W! 5 | 6 | *I find that writing journals like this can be pretty tedious, so one thing I recommend is just recording a vlog of what you did and then summarizing that instead. To that end though, you still need to include images and fairly detailed descriptions!* 7 | 8 | --- 9 | 10 | #### June 8: Got the screen to work!! 11 | 12 | I got the raspberry pi to actualy display on the LCD! Can't believe it actually works 13 | 14 | I based the wiring off of the [pi-tin](https://github.com/jackw01/pi-tin) project originally, but they used an ili9341 display instead of the st7735r I was reusing from sprig. That meant that I had to figure out not only how they got it to display originally, but also how to modify that to use the ST7735R drivers instead 15 | 16 | 17 | 18 | Fortunately for us, the pi-tin project actually documented how the software was set up! They actually cross-reference an adafruit script, which is a derivative of one from pimoroni. 19 | 20 | In short, here's how the original method worked: 21 | 22 | - Install FBCP (framebuffer copy) drivers, which captures whatever would've been outputted to HDMI and allows you to redirect it somewhere else 23 | - Modify the dtoverlays (device tree overlay) in /boot/config.txt to use the built-in kernel drivers for the ILI9341 24 | - Reboot. The framebuffer should automatically redirect everything to the display. 25 | 26 | The main problem was then figuring out what parameters I needed to add to /boot/config.txt to make it work with the new display. I wasn't even sure if there were the right drivers built into the linux kernel! 27 | 28 | Here's how I figured that out: 29 | 30 | - the original [rpi-fbcp](https://github.com/tasanakorn/rpi-fbcp) repository mentions some sort of FBTFT driver 31 | - a quick search links to [this](https://github.com/notro/fbtft) repository, which then mentions that the drivers were now in staging on the [linux kernel](https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging.git/tree/drivers/staging/fbtft?h=staging-testing) 32 | - a bunch more digging eventually leads me to stumble to this file: [st7735r.c](https://github.com/torvalds/linux/blob/master/drivers/gpu/drm/tiny/st7735r.c) 33 | 34 | Bingo. The drivers exist. 35 | 36 | Anyhow, digging into the existing dtoverlays eventually led me to an st7735r generic overlay in the raspberrypi/linux repo! Using ChatGPT to then convert that to a dtparam, I eventually got video output: 37 | 38 | 39 | 40 | *The tl;dr* is that raspberry pi provides the dtoverlay files for the ST7735R built in, so it's a matter of installing a framebuffer and redirecting that to the display in the /boot/config.txt file 41 | 42 | **Time spent this session: 6 hours** 43 | -------------------------------------------------------------------------------- /app/views/advanced/ideas.md: -------------------------------------------------------------------------------- 1 | # Getting project ideas 2 | 3 | Brainstorming can be *really* hard - here's some help on coming up with ideas! 4 | 5 | *this document will be updated as the event runs* 6 | 7 | ### From Hack Club 8 | Here's a list of ideas that we personally think would be cool to make! 9 | 10 | ***Really* cool ideas** 11 | 12 | - Your own custom hacker badge to bring to the event! (reference [here](https://github.com/badger/home)) 13 | - Devboards! (ESP32, CHV32v307, NRF52840, etc) 14 | - Claw machine for prizes 15 | - PCB Mill 16 | - Protogen head 17 | - Feel free to add more suggestions! 18 | 19 | **Less cool** (but still cool!!) 20 | 21 | - 3D printer mods 22 | - 2D plotter 23 | - PCB Hotplate 24 | 25 | Doing these does *not* guarantee your project will be approved! There's still a minimum quality bar for each project 26 | 27 | ### General tips 28 | Here's some more general tips for coming up with ideas: 29 | 30 | - Adafruit has a ton of awesome projects - you can't copy them directly, but you're more than free to take inspo from them 31 | - Do a lot of sketching! Putting stuff down on paper helps a *lot* with thinking since you don't have to come up with it all in your head 32 | -------------------------------------------------------------------------------- /app/views/advanced/journaling.md: -------------------------------------------------------------------------------- 1 | asdf -------------------------------------------------------------------------------- /app/views/advanced/resources.md: -------------------------------------------------------------------------------- 1 | # Alex's tips n' resources 2 | Here's a quick braindump of useful stuff that I've found useful over the years. Will be continuously added to as highway goes on! 3 | 4 | ## Generally useful stuff 5 | - Search stuff up! Again and again and again. You'll have to do a *lot* of the learning yourself so its on you 6 | 7 | ## Software 8 | - For 3D modelling, use either Fusion360 or Onshape! 9 | - For PCB design, use KiCAD! It's free, open source, and works on any platform. 10 | - [Excalidraw](https://excalidraw.com/) is an awesome site for making really quick **sketches** that look good 11 | 12 | ## Project design 13 | - Adafruit projects give you a really good idea of how different hardware projects might fit together. 14 | 15 | ## Tips 16 | - If you're stuck picking between a bunch of passives that are all functionally the same (i.e 30 different types of capacitors), start with the CAD and work backwards - it'll help you get an idea of which one would physically look the best. 17 | - If you're building a 3D printer, [infill](https://infill.hackclub.com) was a 3D printer YSWS that ran recently. There's a TON of resources on the website! 18 | 19 | ## Technical resources 20 | - Adafruit projects are extremely good for looking at what's behind-the-scenes of hardware projects 21 | 22 | ## Software 23 | 24 | ## Other communities 25 | 26 | ### General 27 | 28 | - reddit! 29 | 30 | ### 3D printing 31 | 32 | - VORON discord 33 | - 34 | 35 | ### Battlebots 36 | - Botrumble 37 | 38 | ### Keyboards 39 | 40 | - QMK discord 41 | - r/mechanicalkeyboards 42 | 43 | ### Discords 44 | ### Subreddits 45 | - Keyboards 46 | - Mechanical 47 | -------------------------------------------------------------------------------- /app/views/advanced/shipping.md: -------------------------------------------------------------------------------- 1 | # What is shipping? 2 | 3 | Hi there! This page is my best attempt at explaining the age old question of, *"what on earth is shipping??"* 4 | 5 | In short, **shipping is process of actually making your project sharable**. It's *the* most important part of your project, almost as important as the entire project itself 6 | 7 | When you first make something, usually it just lives as a file on your computer. This is bad because only YOU can access it\! Nobody else can see it. Not only that, but when you look back at the project a few years from now it’ll be very, *very* difficult to remember anything about it\! *It’s not real* 8 | 9 | Shipping (at least in this context context) involves publishing your design out there for the world to see. Making it very real. This involves a couple steps: 10 | 11 | 12 | - **Documenting what your project actually is:** 13 | - A quick story/motivation on how the project came to be 14 | - A description of what the project does 15 | - A quick brief on how it all fits together 16 | - Some pictures of the design 17 | - **Making all files & resources easily accessible & organized** 18 | - **Putting it on a platform that's easily shareable (i.e github, printables, etc)** 19 | 20 | --- 21 | 22 | **Here are some great examples of shipped projects**. Notice how the files are organized using folders, and, more importantly, it’s well documented what the project is about and what you can do with it! 23 | 24 | **Keyboards & Macropads:** 25 | 26 | - [Seigaiha Keyboard](https://github.com/yiancar/Seigaiha) 27 | - [Ducky Pad](https://github.com/dekuNukem/duckyPad) 28 | 29 | **3D printers:** 30 | 31 | - [Voron 0](https://github.com/VoronDesign/Voron-0) 32 | - [Annex K3](https://github.com/Annex-Engineering/Gasherbrum-K3) 33 | 34 | **Misc projects:** 35 | 36 | - [PiGRRL](https://github.com/adafruit/Adafruit-PiGRRL-PCB) Game console 37 | - [Nevermore filters](https://github.com/nevermore3d/Nevermore_Micro) (I’ll admit \- this one is a little excessive) 38 | 39 | **When you make your repository nothing but a dump of files and 2 sentences for a README**, what happens is that it’s hard for other people to recognize your work, nor does it make it easy to learn from. *It’s not real*. It only lives on in your tiny corner of this earth. 40 | 41 | 42 | --- 43 | 44 | *Unfortunately we also can't accept non shipped projects since it'd be impossible to tell what you even made. Make sure to ship your projects!* 45 | 46 | 47 | 48 | Hopefully you got through this document. If there’s any questions let me know. 49 | -------------------------------------------------------------------------------- /app/views/advanced/show.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= raw @content %> 3 |
4 | 5 | -------------------------------------------------------------------------------- /app/views/advanced/submitting.md: -------------------------------------------------------------------------------- 1 | # Submitting your project! 2 | 3 | If you're done your project, here's how to submit! Please read carefuly. 4 | 5 | Before you submit anything, you should post your project in #highway for feedback! That way, you can make your project as good as it can be before submitting 6 | 7 | --- 8 | 9 | ## Requirements 10 | 11 | Before submitting, please *absolutely* make sure of the following: 12 | 13 | - **Your project has a journal in the [gallery](/projects)** 14 | - **Your GitHub repository has all of your project files:** 15 | - a BOM, in CSV format in the root directory 16 | - the source files for your PCB, if you have one 17 | - the source files for your CAD model, if you have one 18 | - ANY other files that are part of your project. 19 | - **In your GitHub README.md file:** 20 | - A description of what your project is 21 | - A couple sentences on *why* you made the project 22 | - **PICTURES OF YOUR PROJECT** 23 | - A screenshot of a full 3D model with your project 24 | - A screenshot of your PCB, if you have one 25 | - A wiring diagram, if you're doing any wiring that isn't on a PCB 26 | - A BOM in table format at the end of the README 27 | - **In your GitHub JOURNAL.md file:** 28 | - Journal entries with the following: 29 | - Date written 30 | - Time spent 31 | - Pictures/videos of what you're working on 32 | - Your total time spent at the top of the file 33 | 34 | **Not doing any of the above will automatically get your project rejected. DO NOT FORGET ANY OF THESE** 35 | 36 | --- 37 | 38 | ## Submitting 39 | 40 | Once you are absolutely sure you have met the above requirements, post your project in #highway-pistop! Here's what you should include: 41 | 42 | ``` 43 | **Name of project: ** 44 | *GitHub Repository Link: ** 45 | 46 | Description: 47 | 48 | (pictures of your project) 49 | ``` 50 | 51 | Once you're done that, fill out the following form: 52 | 53 | [https://forms.hackclub.com/highway](https://forms.hackclub.com/highway) 54 | 55 | It'll send over your project to our queue to be approved! When we review it, you'll get a reply on your message in #highway-pitstop! 56 | 57 | We'll try to get back to you within 3-4 weekdays. 58 | 59 | _**Please do *not* use #highway-pitstop for anything other than submitting**_ 60 | 61 | ## Next steps 62 | 63 | If you get approved, you'll get an HCB card grant in your email within 24 hours! 64 | 65 | **If it gets rejected, you'll have to wait 1 week before being re-reviewed. DO NOT FILL OUT A NEW FORM** -------------------------------------------------------------------------------- /app/views/advanced/tips.md: -------------------------------------------------------------------------------- 1 | # Alex's tips n' tricks 2 | Here's a quick braindump of useful stuff that I've found useful over the years. Will be continuously added to as the event goes on 3 | 4 | ## General 5 | 6 | - If you're stuck picking between a bunch of passives that are all functionally the same (i.e 30 different types of capacitors), start with the CAD and work backwards - it'll help you get an idea of which one would physically look the best. 7 | - If you're building a 3D printer, [infill](https://infill.hackclub.com) was a 3D printer YSWS that ran recently. There's a TON of resources on the website! 8 | 9 | ## Technical resources 10 | - Adafruit projects are extremely good for looking at what's behind-the-scenes of hardware projects 11 | 12 | ## Software 13 | - [Excalidraw](https://excalidraw.com/) is an awesome site for making really quick sketches that look good 14 | -------------------------------------------------------------------------------- /app/views/advanced/troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | You're going to run into a LOT of issues while working on your project! That's okay - here's some general troubleshooting tips! 4 | 5 | ## General tips 6 | 7 | - Before trying anything else, SEARCH. IT. UP. Google whatever issue you might have going on. 8 | 9 | ## Asking for help 10 | 11 | Sometimes a quick search will give you absolutely nothing, and you'll be stuck! Not to worry - that's what the community is here for! 12 | 13 | To make it as easy as possible to ask for help, **you should include the following:** 14 | 15 | - Context as to what you're building & what you're trying to do 16 | - Screenshots/pictures of your problem 17 | - A link to your GitHub repository 18 | 19 | 20 | ## Other communities 21 | 22 | Hack Club is a *great* place, but the the truth is that we're really small too! One of the best ways to learn is to immerse yourself in other communities. Here are some other great places to ask for help: 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/views/guides/_sidebar.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | <%# link_to "Projects", projects_path, class: "#{current_page?(projects_path) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 rounded transition duration-100 block" %> 5 | <%= link_to "Overview", guides_page_path("overview"), class: "#{current_page?(guides_page_path("overview")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-6 rounded transition duration-100 block font-dystopian" %> 6 | <%# <%= link_to "Project Guidelines", guides_page_path("project-guidelines"), class: "#{current_page?(guides_page_path("project-guidelines")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-6 rounded transition duration-100 block font-dystopian" %> 7 | <%# <%= link_to "Submitting", guides_page_path("submitting"), class: "#{current_page?(guides_page_path("submitting")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-6 rounded transition duration-100 block font-dystopian" %> 8 | 9 |

The guides!

10 | <%= link_to "Game Console", guides_page_path("game-console"), class: "#{current_page?(guides_page_path("game-console")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-6 rounded transition duration-100 block font-dystopian" %> 11 | <%# <%= link_to "Other communities", guides_page_path("faq"), class: "#{current_page?(guides_page_path("submit")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 rounded transition duration-100 block font-dystopian" %> 12 |
13 |
14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/views/guides/overview.md: -------------------------------------------------------------------------------- 1 | # Guides 2 | 3 | Welcome! This is a tab where Hack Clubbers (just like you!) can write tips n' tricks, guides, and pretty much any info on projects that they've previously built. 4 | 5 | The goal is to have a collection of resources that grows as highway goes on. 6 | 7 | The first one is on how to make a Game Console - check it out on the sidebar! 8 | 9 | #### Contributing 10 | 11 | To contribute, make a markdown file in the app/views/guides folder! Put your guide in there. Afterwards, make a PR with your changes! 12 | 13 | **In return, you'll get rewarded 1 free point for adding *finished* a guide** 14 | 15 | -------------------------------------------------------------------------------- /app/views/guides/show.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= raw @content %> 3 |
4 | 5 | -------------------------------------------------------------------------------- /app/views/info/info.md: -------------------------------------------------------------------------------- 1 | um add parent guide here or something 2 | 3 | fix markdown rendering because anything fancier than bold and italize isn't working -------------------------------------------------------------------------------- /app/views/info/show.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= @content.html_safe %> 3 |
-------------------------------------------------------------------------------- /app/views/landing/_card.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= title %>

3 |
4 |

<%= content %>

5 |
6 |
-------------------------------------------------------------------------------- /app/views/landing/_emailform.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= form_with url: rsvp_path, method: :post do |form| %> 3 |
4 | <%= form.text_field :email, placeholder: "Enter your email to join!", class: "landing-input bg-white text-black px-4 py-2 w-3/4 md:w-[300px] flex-grow outline-none" %> 5 | <%= form.hidden_field :url_params, value: request.query_string %> 6 | <%= form.submit "→", class: "landing-button bg-[#544FFF] text-white px-4 py-2 font-bold" %> 7 |
8 | <% end %> 9 | <% if flash[:notice] %> 10 | 13 | <% end %> 14 | 15 | <% if flash[:alert] %> 16 | 19 | <% end %> 20 | 21 |
22 | 23 | -------------------------------------------------------------------------------- /app/views/landing/_kit.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 | <% if badge.present? %> 7 |

<%= badge %>

8 | <% end %> 9 |
10 | <%= image_tag image, class: "w-32 h-32 mx-auto p-2" %> 11 |

<%= title %>

12 |

<%= description %>

13 |
14 |
15 |
16 |

More info ->

17 |
18 |
19 | 20 | 21 |
22 |
23 |

<%= title %>

24 |

<%= back_description %>

25 |

Learn how to:

26 |
    27 | <% learnings.each do |learning| %> 28 |
  • <%= learning %>
  • 29 | <% end %> 30 |
31 | Check it out! 32 |
33 |
34 |
35 |
-------------------------------------------------------------------------------- /app/views/landing/_kitsoon.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 | <% if badge.present? %> 7 |

<%= badge %>

8 | <% end %> 9 |
10 | <%= image_tag image, class: "w-32 h-32 mx-auto p-2" %> 11 |

<%= title %>

12 |

<%= description %>

13 |
14 |
15 |
16 |

COMING SOON

17 |
18 |
19 | 20 |
21 |
-------------------------------------------------------------------------------- /app/views/landing/_video.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= image_tag "landing/landing4.png", style: "width: 100%;" %> 3 |
4 |
5 | insert video here 6 |
7 |
8 |
-------------------------------------------------------------------------------- /app/views/landing/dashboard.html.erb: -------------------------------------------------------------------------------- 1 |

Dashboard

-------------------------------------------------------------------------------- /app/views/landing/leaderboards.html.erb: -------------------------------------------------------------------------------- 1 |

Leaderboard

-------------------------------------------------------------------------------- /app/views/launchpad/_kit.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 | <% if badge.present? %> 7 |

<%= badge %>

8 | <% end %> 9 |
10 | <%= image_tag image, class: "w-32 h-32 mx-auto p-2" %> 11 |

<%= title %>

12 |

<%= description %>

13 |
14 |
15 |
16 |

HOVER FOR MORE

17 |
18 |
19 | 20 | 21 |
22 |
23 |

<%= title %>

24 |

<%= back_description %>

25 |

You'll learn how to:

26 |
    27 | <% learnings.each do |learning| %> 28 |
  • <%= learning %>
  • 29 | <% end %> 30 |
31 | Check it out! 32 |
33 |
34 |
35 |
-------------------------------------------------------------------------------- /app/views/launchpad/_kitsoon.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 |
6 | <% if badge.present? %> 7 |

<%= badge %>

8 | <% end %> 9 |
10 | <%= image_tag image, class: "w-32 h-32 mx-auto p-2" %> 11 |

<%= title %>

12 |

<%= description %>

13 |
14 |
15 |
16 |

COMING SOON

17 |
18 |
19 | 20 |
21 |
-------------------------------------------------------------------------------- /app/views/launchpad/show.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

Starter projects

3 | 4 |

No clue what to make? Not a problem! Start here.

5 | 6 |

All of these include resources, guides, and a dedicated slack channel for them.

7 | 8 |

If you're a multichannel guest, you'll need to verify yourself in order to join new slack channels. If you need help, message in #highway!

9 | 10 |

No need to worry about sourcing parts either! Submitting these will have the parts shipped straight from Hack Club as one package.

11 | 12 |
13 | 14 |
15 | 16 | <%= render partial: "kit", locals: { 17 | badge: "recommended", 18 | image: "landing/hackpad.png", 19 | title: "Hackpad", 20 | description: "Make your very own macropad - completely from scratch! - Join #hackpad in the Slack", 21 | back_description: "A macropad is a device used for keyboard shortcuts! Want to turn your mic on/off using a key, change video streaming settings, or open a specific configuration in an app? A macropad can do it all!", 22 | learnings: ["How to make a full PCB", "How to design a 3D printed case"], 23 | link: "https://hackpad.hackclub.com/" 24 | } %> 25 | <%= render partial: "kitsoon", locals: { 26 | badge: "", 27 | image: "mystery.png", 28 | title: "??????", 29 | description: "You'll be able to play Sonic Adventures on it...", 30 | } %> 31 | <%= render partial: "kitsoon", locals: { 32 | badge: "", 33 | image: "mystery.png", 34 | title: "??????", 35 | description: "Hey Jarvis, tell me a joke!", 36 | } %> 37 | 38 |
39 |
40 | 41 |

More coming soon!

42 | 43 |

When you're done, submit your project here: https://forms.hackclub.com/highway

44 |
-------------------------------------------------------------------------------- /app/views/layouts/action_text/contents/_content.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= yield -%> 3 |
4 | -------------------------------------------------------------------------------- /app/views/layouts/advanced.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= content_for(:title) || "Highway: Custom Projects" %> 5 | 6 | 7 | 8 | <%= csrf_meta_tags %> 9 | <%= csp_meta_tag %> 10 | 11 | <%= yield :head %> 12 | 13 | <%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %> 14 | <%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %> 15 | 16 | 17 | 18 | 19 | <%# Includes all stylesheet files in app/assets/stylesheets %> 20 | <%= stylesheet_link_tag :app, "data-turbo-track": "reload" %> 21 | <%= javascript_importmap_tags %> 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |
31 |
32 | <%= render partial: "advanced/sidebar" %> 33 |
34 |
35 |
36 |
<%= render "shared/topbar", class: "sticky top-0" %>
37 |
38 | <%= yield %> 39 |
40 |
41 |
42 |
43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= content_for(:title) || "Highway to Undercity" %> 5 | 6 | 7 | 8 | 9 | <%= csrf_meta_tags %> 10 | <%= csp_meta_tag %> 11 | 12 | <%= yield :head %> 13 | 14 | <%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %> 15 | <%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %> 16 | 17 | 18 | <%# %> 19 | 20 | 21 | <%# Includes all stylesheet files in app/assets/stylesheets %> 22 | <%= stylesheet_link_tag :app, "data-turbo-track": "reload" %> 23 | <%= javascript_importmap_tags %> 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | <%= render partial: "shared/audio" %> 33 |
34 | <%= render "shared/topbar" %> 35 | <% if show_sidebar? %> 36 | <%# render "shared/sidebar" %> 37 | <%= yield %> 38 | <% else %> 39 |
40 | <%= yield %> 41 |
42 | <% end %> 43 | 44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /app/views/layouts/guides.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= content_for(:title) || "Highway: Custom Projects" %> 5 | 6 | 7 | 8 | <%= csrf_meta_tags %> 9 | <%= csp_meta_tag %> 10 | 11 | <%= yield :head %> 12 | 13 | <%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %> 14 | <%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %> 15 | 16 | 17 | 18 | 19 | <%# Includes all stylesheet files in app/assets/stylesheets %> 20 | <%= stylesheet_link_tag :app, "data-turbo-track": "reload" %> 21 | <%= javascript_importmap_tags %> 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 |
31 |
32 | <%= render partial: "guides/sidebar" %> 33 |
34 |
35 |
36 |
<%= render "shared/topbar", class: "sticky top-0" %>
37 |
38 | <%= yield %> 39 |
40 |
41 |
42 |
43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | <%= yield %> 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /app/views/layouts/overview.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= content_for(:title) || "Highway: Getting Started" %> 5 | 6 | 7 | 8 | <%= csrf_meta_tags %> 9 | <%= csp_meta_tag %> 10 | 11 | <%= yield :head %> 12 | 13 | <%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %> 14 | <%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %> 15 | 16 | 17 | 18 | 19 | <%# Includes all stylesheet files in app/assets/stylesheets %> 20 | <%= stylesheet_link_tag :app, "data-turbo-track": "reload" %> 21 | <%= javascript_importmap_tags %> 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | <%= render partial: "shared/audio" %> 30 | 31 |
32 |
33 |
34 | <%= render partial: "overview/sidebar" %> 35 |
36 |
37 |
38 |
<%= render "shared/topbar", class: "sticky top-0" %>
39 |
40 | <%= yield %> 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /app/views/overview/_sidebar.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | <%= link_to "Overview", overview_page_path("overview"), class: "#{current_page?(overview_page_path("overview")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-6 rounded transition duration-100 block" %> 5 | <%= link_to "The Point System", overview_page_path("point-system"), class: "#{current_page?(overview_page_path("point-system")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-6 rounded transition duration-100 block" %> 6 | <%= link_to "Starter Projects", overview_page_path("starter-projects"), class: "#{current_page?(overview_page_path("starter-projects")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] text-[#AFEFCB] p-2 px-6 rounded transition duration-100 block" %> 7 | <%= link_to "Undercity", overview_page_path("undercity"), class: "#{current_page?(overview_page_path("undercity")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-6 rounded transition duration-100 block" %> 8 | <%= link_to "Parent's Guide", overview_page_path("parents"), class: "#{current_page?(overview_page_path("parents")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-6 rounded transition duration-100 block" %> 9 | <%= link_to "FAQ", overview_page_path("faq"), class: "#{current_page?(overview_page_path("faq")) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 px-4 rounded transition duration-100 block" %> 10 |
11 | 12 | 13 |
14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/views/overview/overview.md: -------------------------------------------------------------------------------- 1 | # Overview 2 | 3 | ### Welcome to the **Highway** to **Undercity**, an unforgettable summer of hardware running from now through July 31st. 4 | 5 | 6 | 7 | If you've *never* done hardware before, this is *your* opportunity to get started. That one project you saw on YouTube but had no idea how to build? *That ends now.* 8 | 9 | **Earn points with each project you build.** Collect prizes along the way. Join your friends at Undercity, a 4 day hackathon in San Francisco at GitHub HQ. 10 | 11 | *Don't forget to join the Hack Club Slack, our community. Need an invite? Enter your email on the [landing](/)!* 12 | 13 | ## Here's how it works: 14 | --- 15 | ### 1. Build hardware projects 16 | 17 | Design custom projects. [Submit](/advanced/submitting) them. Get approved. Receive a credit card of up to $350 USD. Buy the parts and build it. Repeat 18 | 19 | There's three tiers: 20 | 21 | - **Tier 3:** get 4 points, up to $50 USD 22 | - **Tier 2:** get 6 points, up to $150 USD 23 | - **Tier 1:** get 10 points, up to $350 USD 24 | 25 | Each tier has progressively harder guidelines. Check out the [Custom projects](/advanced) tab for all the info you need - including project guidelines! 26 | 27 | 28 | Head on over to the [custom projects](/advanced) are fully self-directed! You'll be responsible for all the research, and in return, you'll get a debit card of up to $350* USD to spend on your project! *You must journal your progress while working on custom projects* 29 | 30 | *You can make an unlimited amount of projects, so get building!* 31 | 32 | **If you're a complete beginner, head on over to check out our [starter projects](/getting-started/starter-projects)! They're designed to help you get jumpstarted** 33 | 34 | --- 35 | 36 | ### 2. Join weekly events 37 | 38 | Every week, we'll host events like Speedruns, Game Nights, AMAs, and Showcases! 39 | 40 | See the [Events](/events) tab for an up-to-date list. 41 | 42 | --- 43 | 44 | ### 3. Get invited to Undercity 45 | 46 | Once you collect 12 points, AND you've physically built 1 project, you'll get invited to [Undercity](/getting-started/undercity), a 4 day hardware hackathon at GitHub HQ from July 11-14. 47 | 48 | It'll be filled to the *brim* with hardware - hundreds of microcontrollers, kilometers of cabling, and more 3D printing than you could ever need. (Did someone mention a PCB mill?) 49 | 50 | ## Ready. Set. Build! 51 | 52 | 53 | -------------------------------------------------------------------------------- /app/views/overview/point-system.md: -------------------------------------------------------------------------------- 1 | # The point system 2 | 3 | Points are the currency of Highway! Here's everything you need to know about them. 4 | 5 | As always, if you have any questions, ask in #highway! 6 | 7 | *This page will be updated as more questions get asked.* 8 | 9 | **Points correlate to *complexity*, not cost.** 10 | 11 | --- 12 | 13 | ## Getting points 14 | 15 | - Get a design **approved** 16 | - *Note that not all submitted designs will be approved; they will get checked by a human first* 17 | - **Starter projects**: 2 points 18 | - **Custom projects**: 2-5 points 19 | - Physically build one of your projects 20 | - **Starter projects**: 2 points 21 | - **Custom projects**: 2-5 points 22 | 23 | - Attend a Highway event 24 | - Sometimes 1 point (dependent on type of event) 25 | - Check the [Events](/events) tab for more! 26 | 27 | 28 | 29 |
30 | 31 | ## FAQ 32 | 33 | **Can I transfer points between friends?** 34 | no! 35 | 36 | **Can I do the same starter project multiple times?** 37 | no! -------------------------------------------------------------------------------- /app/views/overview/show.html.erb: -------------------------------------------------------------------------------- 1 |
2 | <%= raw @content %> 3 |
4 | 5 | -------------------------------------------------------------------------------- /app/views/overview/starter-projects.md: -------------------------------------------------------------------------------- 1 | # Starter projects! 2 | 3 | **Starter projects** are existing Hack Club programs that are designed to help guide you along your hardware journey! 4 | 5 | They're called YSWSes, short for You Ship, We Ships. You ship a design, we'll ship you the parts! 6 | 7 | **All of the parts will come straight from Hack Club HQ**, so you don't need to worry about sourcing or logistics. Just design & learn. 8 | 9 | *Starter projects will automatically count for points once approved. Submission instructions are on their relative websites* 10 | 11 | You can only do a starter project once, sorry! 12 | 13 | --- 14 | 15 | ## Hackpad - 4 points 16 | 17 | **Hackpad** is a beginner YSWS that teaches you how to make your very first *macropad* from scratch! It'll help you create your own PCB, design your own 3D printed case, and setup the firmware for it from scratch. 18 | 19 | In return, you'll get all the parts to make your macropad! This includes up to 16 switches, diodes, OLED screens, and more! 20 | 21 | 22 | 23 | [hackpad.hackclub.com](https://hackpad.hackclub.com) 24 | 25 | 26 | 27 | *This is the most popular running hardware YSWS, with over 400 submissions to date* 28 | 29 | --- 30 | 31 | ## Solder - 1 point 32 | Solder is a beginner YSWS that teaches you how to make your very first PCB from scratch! 33 | 34 | It'll walk you through the process step-by-step of setting up the software, placing down all the components, and getting it ready for fabrication! 35 | 36 | 37 | 38 | [solder.hackclub.com](https://solder.hackclub.com) 39 | 40 | In return, you'll get a $5 grant to buy your PCB and a kit of hardware components to play around with. 41 | 42 | *If you're doing Solder, please follow the flow in [solder.hackclub.com](https://solder.hackclub.com) when submitting the design (ie: submit in #solder-ships). When you're finished assembling the PCB, you'll get the 1 point when you demo it!* 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /app/views/overview/submit.md: -------------------------------------------------------------------------------- 1 | # Submitting projects 2 | 3 | Submitting your project is SUPER easy! Once you have everything ready, **fill out the following form**: 4 | 5 | https://forms.hackclub.com/highway 6 | 7 | Please double check that you have everything necessary! This will depend on your project, but generally check for: 8 | 9 | - if doing a starter, the requirements on the project's website 10 | - if doing a custom project, read [here](/advanced/submitting) 11 | - a proper README.md file in your repository (includes images, a description, etc) 12 | - a full BOM with links 13 | - all project source files 14 | 15 | **USING AI TO GENERATE A README.md FILE OR A JOURNAL IS STRICTLY DISALLOWED** 16 | 17 | If your project is rejected for any reason, you will have to wait 1 week before it gets re-reviewed 18 | 19 | Approval **does not** guarantee that your project will be functional - that is on you to check. Please ask in #highway and get help from other people to make sure it works before submitting! 20 | 21 | # Collecting your points 22 | 23 | When you get approved, you'll get an email! Your points will automatically get added to the system. 24 | 25 | -------------------------------------------------------------------------------- /app/views/overview/undercity.md: -------------------------------------------------------------------------------- 1 | # Undercity 2 | 3 | **Undercity** is a 4 day hardware hackathon hosted at GitHub HQ in San Francisco, California, USA from July 11-14th. 4 | 5 | To qualify for Undercity, you need at least 12 points and 1 *physically built*, working hardware project. 6 | 7 | 8 | 9 | ## What's a hackathon? 10 | 11 | A social making marathon! Team up with other teenagers around the world and try to make the goofiest, coolest project in 72 hours - from start to finish. At the end, you'll demo your project to others, and there will be prizes! 12 | 13 | Throughout the hackathon, there'll be plenty of activities and workshops you can go to. Ever want to compete in a macropad speedrun or play smash with custom characters at 2am? There will be tons of things you can do here! 14 | 15 | All meals (from dinner on Friday, to breakfast on Monday) will be provided during Undercity. You'll stay in GitHub HQ for the duration of the event - bring a sleeping bag! 16 | 17 | **Check out some previous Hack Club flagship hackathons:** 18 | 19 | - [Juice](https://www.youtube.com/watch?v=fuTlToZ1SX8): make a game, spend a week in Shanghai! 20 | - [Scrapyard](https://www.youtube.com/watch?v=8iM1W8kXrQA&t=1s): a 24h hackathon to build your scrappiest ideas 21 | - [Apocalypse](https://www.youtube.com/watch?v=QvCoISXfcE8): a 44h hackathon where you build to survive a zombie apocalypse 22 | - [The Boreal Express](https://www.youtube.com/watch?v=hiG3fYq3xUU): a 7-day hackathon on a train across Canada 23 | 24 | 25 | 26 | ## Travel 27 | 28 | Undercity opening ceremony will start around 7pm on Friday. Plan to arrive a few hours before - check-in will start in the afternoon! It'll end Monday at noon. 29 | 30 | Once you reach 8 points, we'll send you the Travel Form to fill out! 31 | 32 | #### Visa information 33 | 34 | If you’re traveling internationally, you may need either an [ESTA](https://www.cbp.gov/travel/international-visitors/esta) or a visa based on your country of citizenship. Meeting the requirements to enter the United States is the responsibility of the attendee, and you are encouraged to do your own research. 35 | 36 | If you require a visa: 37 | 38 | - Start applying soon; wait times can get very long 39 | - If you need a Letter of Invitation from Hack Club, let us know in the Travel form 40 | 41 | Visa expenses will not be paid by Hack Club under any circumstances. 42 | 43 | #### Travel Stipends 44 | 45 | You'll qualify for a reimbursment once you have **finished building the projects you submitted for Undercity + reached 12 points**. 46 | 47 | Base stipends: 48 | 49 | - If you're in North America, we will reimburse you 200 USD 50 | - If you're international, we will reimburse you 500 USD 51 | 52 | You can also earn additional stipends for points above 12. 53 | A needs-based stipend application will also be available. 54 | 55 | Travelling by car, bus, or train? The [Hack Club Gas Fund](https://gas.hackclub.com/) can reimburse your costs! However, you'll still need an invite to come. 56 | 57 |
58 | 59 | -------------------------------------------------------------------------------- /app/views/projects/_header.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | <%= link_to "← Back to Gallery", projects_path, class: "bg-[#403A88] font-bold text-white px-4 py-2 rounded hover:opacity-80 transition duration-200" %> 6 | <%= link_to "View on GitHub", 7 | project.github_repo, 8 | class: "bg-[#544FFF] font-bold text-white px-4 py-2 rounded hover:opacity-80 transition duration-200" %> 9 |
10 | 11 |
12 | 13 |

<%= project.name %>

14 | 15 |
16 | Created by 17 | <% if project.author.present? %> 18 | <%= link_to project.user_link, target: "_blank", class: "text-[#96ABF9] inline-block" do %> 19 | [<%= project.author %>] 20 | <% end %> 21 | <% else %> 22 | <%= project.author_display %> 23 | <% end %> 24 | <% if project.has_creation_date? %> 25 | • Started on <%= project.formatted_created_at %> 26 | <% end %> 27 |
28 | 29 | <% if project.description.present? %> 30 |

31 | <%= project.description %> 32 |

33 | <% end %> 34 | 35 |
36 | 37 |
-------------------------------------------------------------------------------- /app/views/projects/edit.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 |
<%= link_to "← back", projects_path %>
4 | 5 |

Edit your project!

6 | 7 | <%= form_with model: @project do |form|%> 8 |
9 | 10 |
11 | <%= form.label :name %> 12 |
13 | <%= form.text_field :name, class: "bg-[#B8DCFC] text-black border border-gray-300 p-2 rounded w-[400px]" %> 14 |
15 |
16 | 17 |
18 | <%= form.label :github_repo %> 19 |
20 | <%= form.url_field :github_repo, class: "bg-[#B8DCFC] text-black border border-gray-300 p-2 rounded w-[400px]" %> 21 |
22 |
23 | 24 |
25 | <%= form.label :proposed_tier %> 26 |
27 | <%= form.select :proposed_tier, [["Tier 1", "Tier 1"], ["Tier 2", "Tier 2"], ["Tier 3", "Tier 3"]], {}, class: "bg-[#B8DCFC] text-black border border-gray-300 p-2 rounded w-[400px]" %> 28 |
29 |
30 | 31 | 32 |
33 | <%= form.label :proposed_tier_explanation, class: "block" %> 34 | <%= form.rich_text_area :proposed_tier_explanation, class: "bg-[#B8DCFC] text-black border border-gray-300 p-2 rounded" %> 35 |
36 | 37 |
38 |
39 | <%= form.check_box :group_project, { style: "width: 26px; height: 26px; flex-shrink: 0;" }, "true", "false" %> 40 | <%= form.label :group_project, "Is this a group project? You’re allowed to work with 1 other person! Both people must do technical work.", class: "block" %> 41 | 42 |
43 |
44 | 45 | <% if @project.errors.any? %> 46 |
47 |

<%= pluralize(@project.errors.count, "thing") %> you need to fix before projecting!

48 |
    49 | <% @project.errors.full_messages.each do |message| %> 50 |
  • <%= message %>
  • 51 | <% end %> 52 |
53 |
54 | <% end %> 55 | 56 | 57 |
58 | <%= form.submit "Submit", class: "bg-[#62D5C3] text-[#3A5CE1] px-4 py-2 rounded cursor-pointer hover:opacity-100 opacity-80" %> 59 |
60 |
61 | <% end %> 62 |
-------------------------------------------------------------------------------- /app/views/projects/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Project Gallery

4 | 5 | <% if @projects.any? %> 6 |
7 |

Check out what others are building!

8 |

Highlighted projects with blue borders are handpicked cool projects with good journals.

9 |

<%= pluralize(@projects.count, "project") %> <%= @projects.count == 1 ? "has" : "have" %> been started:

10 |
11 | <% else %> 12 |

Projects are loading!

13 |

Hang tight and try again in 30 seconds.

14 | <% unless Rails.env.production? %> 15 |

Did you forget to run bin/rails projects:clone? ;-P

16 | <% end %> 17 | <% end %> 18 | 19 |
20 | <% @projects.each do |project| %> 21 |
hover:border-[#544FFF] rounded-lg text-white hover:bg-[#3A3A6D] transition duration-100 transition-transform hover:scale-102 p-8 h-full flex flex-col"> 22 | <% if project.has_journal? %> 23 | <%= link_to project_path(user: project.user, project_name: project.project_name), class: "block mb-2" do %> 24 |

<%= project.name.truncate(25) %>

25 | <% end %> 26 | <% else %> 27 |

28 | <%= project.name.truncate(25) %> 29 |

30 |

⚠️ This project lacks a journal.md file.

31 | <% end %> 32 | <%= link_to project.github_repo, target: "_blank", class: "text-base text-[#96ABF9] text-sm rounded py-1 inline-block break-words" do %> 33 | [<%= project.github_slug %>] 34 | <% end %> 35 |
36 | Created by 37 | <% if project.author.present? %> 38 | <%= link_to project.user_link, target: "_blank", class: "text-[#96ABF9] inline-block" do %> 39 | [<%= project.author %>] 40 | <% end %> 41 | <% else %> 42 | <%= project.author_display %> 43 | <% end %> 44 | <% if project.has_creation_date? %> 45 | • Started on <%= project.formatted_created_at %> 46 | <% end %> 47 |
48 | <% if project.description.present? %> 49 |

<%= project.description.truncate(120) %>

50 | <% end %> 51 | <% if Rails.env.development? %> 52 | 53 |
54 | <%= project.inspect %> 55 |
56 |
57 | <% end %> 58 |
59 | <% end %> 60 |
61 | 62 |
-------------------------------------------------------------------------------- /app/views/projects/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 |
<%= link_to "← back", projects_path %>
4 | 5 |

Make a new project!

6 | 7 | <%= form_with model: @project do |form|%> 8 |
9 | 10 |
11 | <%= form.label :name %> 12 |
13 | <%= form.text_field :name, class: "bg-[#B8DCFC] text-black border border-gray-300 p-2 rounded w-[400px]" %> 14 |
15 |
16 | 17 |
18 | <%= form.label :github_repo %> 19 |
20 | <%= form.url_field :github_repo, class: "bg-[#B8DCFC] text-black border border-gray-300 p-2 rounded w-[400px]" %> 21 |
22 |
23 | 24 |
25 | <%= form.label :proposed_tier %> 26 |
27 | <%= form.select :proposed_tier, [["Tier 1", "Tier 1"], ["Tier 2", "Tier 2"], ["Tier 3", "Tier 3"]], {}, class: "bg-[#B8DCFC] text-black border border-gray-300 p-2 rounded w-[400px]" %> 28 |
29 |
30 | 31 | 32 |
33 | <%= form.label :proposed_tier_explanation, class: "block" %> 34 | <%= form.rich_text_area :proposed_tier_explanation, class: "bg-[#B8DCFC] text-black border border-gray-300 p-2 rounded" %> 35 |
36 | 37 |
38 |
39 | <%= form.check_box :group_project, { style: "width: 26px; height: 26px; flex-shrink: 0;" }, "true", "false" %> 40 | <%= form.label :group_project, "Is this a group project? You’re allowed to work with 1 other person! Both people must do technical work.", class: "block" %> 41 | 42 |
43 |
44 | 45 | <% if @project.errors.any? %> 46 |
47 |

<%= pluralize(@project.errors.count, "thing") %> you need to fix before projecting!

48 |
    49 | <% @project.errors.full_messages.each do |message| %> 50 |
  • <%= message %>
  • 51 | <% end %> 52 |
53 |
54 | <% end %> 55 | 56 | 57 |
58 | <%= form.submit "Submit", class: "bg-[#62D5C3] text-[#3A5CE1] px-4 py-2 rounded cursor-pointer hover:opacity-100 opacity-80" %> 59 |
60 |
61 | <% end %> 62 |
-------------------------------------------------------------------------------- /app/views/projects/show.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | <%= render partial: "header", locals: { project: @project } %> 5 |
6 | 7 |
8 | <%= @project.content.html_safe %> 9 |
10 |
11 | 12 | 13 | -------------------------------------------------------------------------------- /app/views/pwa/manifest.json.erb: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Highway to Undercity", 3 | "icons": [ 4 | { 5 | "src": "/highwaylogo.png", 6 | "type": "image/png", 7 | "sizes": "512x512" 8 | }, 9 | { 10 | "src": "/highwaylogo.png", 11 | "type": "image/png", 12 | "sizes": "512x512", 13 | "purpose": "maskable" 14 | } 15 | ], 16 | "start_url": "/", 17 | "display": "standalone", 18 | "scope": "/", 19 | "description": "Site.", 20 | "theme_color": "red", 21 | "background_color": "red" 22 | } 23 | -------------------------------------------------------------------------------- /app/views/pwa/service-worker.js: -------------------------------------------------------------------------------- 1 | // Add a service worker for processing Web Push notifications: 2 | // 3 | // self.addEventListener("push", async (event) => { 4 | // const { title, options } = await event.data.json() 5 | // event.waitUntil(self.registration.showNotification(title, options)) 6 | // }) 7 | // 8 | // self.addEventListener("notificationclick", function(event) { 9 | // event.notification.close() 10 | // event.waitUntil( 11 | // clients.matchAll({ type: "window" }).then((clientList) => { 12 | // for (let i = 0; i < clientList.length; i++) { 13 | // let client = clientList[i] 14 | // let clientPath = (new URL(client.url)).pathname 15 | // 16 | // if (clientPath == event.notification.data.path && "focus" in client) { 17 | // return client.focus() 18 | // } 19 | // } 20 | // 21 | // if (clients.openWindow) { 22 | // return clients.openWindow(event.notification.data.path) 23 | // } 24 | // }) 25 | // ) 26 | // }) 27 | -------------------------------------------------------------------------------- /app/views/session_mailer/login_code.html.erb: -------------------------------------------------------------------------------- 1 |

welcome to highway

2 | 3 |

4 | <%= @greeting %>, here's your login CODE: mrow! 5 |

-------------------------------------------------------------------------------- /app/views/session_mailer/login_code.text.erb: -------------------------------------------------------------------------------- 1 | Session#login_token 2 | 3 | <%= @greeting %>, find me in app/views/session_mailer/login_token.text.erb -------------------------------------------------------------------------------- /app/views/shared/_audio.html.erb: -------------------------------------------------------------------------------- 1 | 9 | 10 |
11 | 15 | 16 | 19 |
-------------------------------------------------------------------------------- /app/views/shared/_sidebar.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 |
5 | <%= link_to "Projects", projects_path, class: "#{current_page?(projects_path) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 rounded transition duration-100 block" %> 6 |
7 | 8 |
9 | 10 | <% if current_user %> 11 | <%= link_to "@#{current_user.username}", user_path(current_user), class: "#{current_page?(user_path(current_user)) || current_page?(edit_user_path(current_user)) ? 'bg-[#564CAD]' : 'hover:bg-[#564CAD]'} bg-[#2E2A54] p-2 transition duration-100 block" %> 12 | <% end %> 13 |
-------------------------------------------------------------------------------- /app/views/shared/_topbar.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 | <%= link_to root_path do %> 7 | <%= image_tag "/logo2.png", alt: "Logo", class: "max-h-[70px]" %> 8 | <% end %> 9 |
10 | 11 | 12 | 24 | 25 | 26 | 34 | 35 | 38 |
39 | 40 | 41 |
51 | <%= link_to "Getting started", "/getting-started" %> 52 | <%= link_to "Starter projects", "/starter-projects" %> 53 | <%= link_to "Custom projects", "/advanced" %> 54 | <%= link_to "Gallery", projects_path %> 55 | <%= link_to "Events", events_path %> 56 | <%= link_to "Faq", "/getting-started/faq" %> 57 |
58 |
-------------------------------------------------------------------------------- /app/views/users/_form.html.erb: -------------------------------------------------------------------------------- 1 | 2 | <%= form_with model: @user do |form|%> 3 |
4 | <%= @user.email %> 5 | 6 |
7 | <%= form.label :first_name %> 8 |
9 | <%= form.text_field :first_name, class: "bg-[#B8DCFC] text-black border border-gray-300 p-2 rounded w-[400px]" %> 10 |
11 |
12 | 13 |
14 | <%= form.label :last_name %> 15 |
16 | <%= form.text_field :last_name, class: "bg-[#B8DCFC] text-black border border-gray-300 p-2 rounded w-[400px]" %> 17 |
18 |
19 | 20 |
21 | <%= form.label :username %> 22 |
23 | <%= form.text_field :username, class: "bg-[#B8DCFC] text-black border border-gray-300 p-2 rounded w-[400px]" %> 24 |
25 |
26 | 27 |
28 | <%= form.label :github %> 29 |
30 | <%= form.text_field :github, class: "bg-[#B8DCFC] text-black border border-gray-300 p-2 rounded w-[400px]" %> 31 |
32 |
33 | 34 | <% if @user.errors.any? %> 35 |
36 |

<%= pluralize(@user.errors.count, "thing") %> you need to fix!

37 |
    38 | <% @user.errors.full_messages.each do |message| %> 39 |
  • <%= message %>
  • 40 | <% end %> 41 |
42 |
43 | <% end %> 44 | 45 | 46 |
47 | <%= form.submit "Submit", class: "bg-[#62D5C3] text-[#3A5CE1] px-4 py-2 rounded cursor-pointer hover:opacity-100 opacity-80" %> 48 |
49 |
50 | <% end %> -------------------------------------------------------------------------------- /app/views/users/edit.html.erb: -------------------------------------------------------------------------------- 1 |

Edit user

2 | 3 | <%= render "form", user: @user %> 4 | <%= link_to "Cancel", @user %> -------------------------------------------------------------------------------- /app/views/users/prize_box.html.erb: -------------------------------------------------------------------------------- 1 | <%# app/views/users/prize_box.html.erb %> 2 |

Your Prize Box

3 | 4 | <% current_user.prize_box.each do |user_prize| %> 5 |
6 | <%= image_tag user_prize.prize.image %> 7 | <%= button_to "Claim", claim_prize_path(user_prize), method: :patch %> 8 |
9 | <% end %> 10 | -------------------------------------------------------------------------------- /app/views/users/show.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= @user.name %>

3 |

@<%= @user.username %>

4 |

5 | <%= pluralize(@user.posts.count, "post") %> created 6 | // <%= pluralize(9, "hour") %> spent on 7 |

8 | 9 | <% if current_user == @user %> 10 | <%= link_to "Edit", edit_user_path(@user), class: "opacity-70 hover:opacity-100"%> 11 | <% end %> 12 | 13 |

14 |

welcome, <%= current_user.email %>!

15 |

[insert log out button here]

16 |
17 |
18 | 19 | 20 |
21 | <% @user.posts.each do |post| %> 22 | <%= link_to post_path(post), class: "block bg-[#2E2A54] max-w-4xl p-4 px-8 rounded-lg text-white hover:bg-[#3A3A6D] transition duration-100 w-full" do %> 23 |

posted by [name] // <%= time_ago_in_words(post.created_at) %> ago // <%= pluralize(post.hours, "hour") %> spent on [project]

24 |

<%= post.name %>

25 | 26 |
<%= post.description %>
27 | <% end %> 28 | <% end %> 29 |
-------------------------------------------------------------------------------- /bin/brakeman: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "rubygems" 3 | require "bundler/setup" 4 | 5 | ARGV.unshift("--ensure-latest") 6 | 7 | load Gem.bin_path("brakeman", "brakeman") 8 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'bundle' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "rubygems" 12 | 13 | m = Module.new do 14 | module_function 15 | 16 | def invoked_as_script? 17 | File.expand_path($0) == File.expand_path(__FILE__) 18 | end 19 | 20 | def env_var_version 21 | ENV["BUNDLER_VERSION"] 22 | end 23 | 24 | def cli_arg_version 25 | return unless invoked_as_script? # don't want to hijack other binstubs 26 | return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` 27 | bundler_version = nil 28 | update_index = nil 29 | ARGV.each_with_index do |a, i| 30 | if update_index && update_index.succ == i && a.match?(Gem::Version::ANCHORED_VERSION_PATTERN) 31 | bundler_version = a 32 | end 33 | next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ 34 | bundler_version = $1 35 | update_index = i 36 | end 37 | bundler_version 38 | end 39 | 40 | def gemfile 41 | gemfile = ENV["BUNDLE_GEMFILE"] 42 | return gemfile if gemfile && !gemfile.empty? 43 | 44 | File.expand_path("../Gemfile", __dir__) 45 | end 46 | 47 | def lockfile 48 | lockfile = 49 | case File.basename(gemfile) 50 | when "gems.rb" then gemfile.sub(/\.rb$/, ".locked") 51 | else "#{gemfile}.lock" 52 | end 53 | File.expand_path(lockfile) 54 | end 55 | 56 | def lockfile_version 57 | return unless File.file?(lockfile) 58 | lockfile_contents = File.read(lockfile) 59 | return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ 60 | Regexp.last_match(1) 61 | end 62 | 63 | def bundler_requirement 64 | @bundler_requirement ||= 65 | env_var_version || 66 | cli_arg_version || 67 | bundler_requirement_for(lockfile_version) 68 | end 69 | 70 | def bundler_requirement_for(version) 71 | return "#{Gem::Requirement.default}.a" unless version 72 | 73 | bundler_gem_version = Gem::Version.new(version) 74 | 75 | bundler_gem_version.approximate_recommendation 76 | end 77 | 78 | def load_bundler! 79 | ENV["BUNDLE_GEMFILE"] ||= gemfile 80 | 81 | activate_bundler 82 | end 83 | 84 | def activate_bundler 85 | gem_error = activation_error_handling do 86 | gem "bundler", bundler_requirement 87 | end 88 | return if gem_error.nil? 89 | require_error = activation_error_handling do 90 | require "bundler/version" 91 | end 92 | return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) 93 | warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" 94 | exit 42 95 | end 96 | 97 | def activation_error_handling 98 | yield 99 | nil 100 | rescue StandardError, LoadError => e 101 | e 102 | end 103 | end 104 | 105 | m.load_bundler! 106 | 107 | if m.invoked_as_script? 108 | load Gem.bin_path("bundler", "bundle") 109 | end 110 | -------------------------------------------------------------------------------- /bin/dev: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | if ! gem list foreman -i --silent; then 4 | echo "Installing foreman..." 5 | gem install foreman 6 | fi 7 | 8 | # Default to port 3000 if not specified 9 | export PORT="${PORT:-3000}" 10 | 11 | # Let the debug gem allow remote connections, 12 | # but avoid loading until `debugger` is called 13 | export RUBY_DEBUG_OPEN="true" 14 | export RUBY_DEBUG_LAZY="true" 15 | 16 | exec foreman start -f Procfile.dev "$@" 17 | -------------------------------------------------------------------------------- /bin/docker-entrypoint: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | 3 | # Enable jemalloc for reduced memory usage and latency. 4 | if [ -z "${LD_PRELOAD+x}" ]; then 5 | LD_PRELOAD=$(find /usr/lib -name libjemalloc.so.2 -print -quit) 6 | export LD_PRELOAD 7 | fi 8 | 9 | # If running the rails server then create or migrate existing database 10 | if [ "${@: -2:1}" == "./bin/rails" ] && [ "${@: -1:1}" == "server" ]; then 11 | ./bin/rails db:prepare 12 | fi 13 | 14 | exec "${@}" 15 | -------------------------------------------------------------------------------- /bin/importmap: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require_relative "../config/application" 4 | require "importmap/commands" 5 | -------------------------------------------------------------------------------- /bin/jobs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require_relative "../config/environment" 4 | require "solid_queue/cli" 5 | 6 | SolidQueue::Cli.start(ARGV) 7 | -------------------------------------------------------------------------------- /bin/kamal: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'kamal' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 12 | 13 | bundle_binstub = File.expand_path("bundle", __dir__) 14 | 15 | if File.file?(bundle_binstub) 16 | if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") 17 | load(bundle_binstub) 18 | else 19 | abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. 20 | Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") 21 | end 22 | end 23 | 24 | require "rubygems" 25 | require "bundler/setup" 26 | 27 | load Gem.bin_path("kamal", "kamal") 28 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path("../config/application", __dir__) 3 | require_relative "../config/boot" 4 | require "rails/commands" 5 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative "../config/boot" 3 | require "rake" 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /bin/rubocop: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "rubygems" 3 | require "bundler/setup" 4 | 5 | # explicit rubocop config increases performance slightly while avoiding config confusion. 6 | ARGV.unshift("--config", File.expand_path("../.rubocop.yml", __dir__)) 7 | 8 | load Gem.bin_path("rubocop", "rubocop") 9 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "fileutils" 3 | 4 | APP_ROOT = File.expand_path("..", __dir__) 5 | 6 | def system!(*args) 7 | system(*args, exception: true) 8 | end 9 | 10 | FileUtils.chdir APP_ROOT do 11 | # This script is a way to set up or update your development environment automatically. 12 | # This script is idempotent, so that you can run it at any time and get an expectable outcome. 13 | # Add necessary setup steps to this file. 14 | 15 | puts "== Installing dependencies ==" 16 | system("bundle check") || system!("bundle install") 17 | 18 | # puts "\n== Copying sample files ==" 19 | # unless File.exist?("config/database.yml") 20 | # FileUtils.cp "config/database.yml.sample", "config/database.yml" 21 | # end 22 | 23 | puts "\n== Preparing database ==" 24 | system! "bin/rails db:prepare" 25 | 26 | puts "\n== Removing old logs and tempfiles ==" 27 | system! "bin/rails log:clear tmp:clear" 28 | 29 | unless ARGV.include?("--skip-server") 30 | puts "\n== Starting development server ==" 31 | STDOUT.flush # flush the output before exec(2) so that it displays 32 | exec "bin/dev" 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /bin/thrust: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "rubygems" 3 | require "bundler/setup" 4 | 5 | load Gem.bin_path("thruster", "thrust") 6 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative "config/environment" 4 | 5 | run Rails.application 6 | Rails.application.load_server 7 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative "boot" 2 | 3 | require "rails/all" 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module Highway 10 | class Application < Rails::Application 11 | # Initialize configuration defaults for originally generated Rails version. 12 | config.load_defaults 7.1 13 | 14 | # Please, add to the `ignore` list any other `lib` subdirectories that do 15 | # not contain `.rb` files, or that should not be reloaded or eager loaded. 16 | # Common ones are `templates`, `generators`, or `middleware`, for example. 17 | config.autoload_lib(ignore: %w[assets tasks]) 18 | 19 | # Configuration for the application, engines, and railties goes here. 20 | # 21 | # These settings can be overridden in specific environments using the files 22 | # in config/environments, which are processed later. 23 | # 24 | # config.time_zone = "Central Time (US & Canada)" 25 | # config.eager_load_paths << Rails.root.join("extras") 26 | 27 | # Don't require master key 28 | config.require_master_key = false 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 2 | 3 | require "bundler/setup" # Set up gems listed in the Gemfile. 4 | require "bootsnap/setup" # Speed up boot time by caching expensive operations. 5 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | # Async adapter only works within the same process, so for manually triggering cable updates from a console, 2 | # and seeing results in the browser, you must do so from the web console (running inside the dev process), 3 | # not a terminal started via bin/rails console! Add "console" to any action or any ERB template view 4 | # to make the web console appear. 5 | development: 6 | adapter: async 7 | 8 | test: 9 | adapter: test 10 | 11 | production: 12 | adapter: solid_cable 13 | connects_to: 14 | database: 15 | writing: cable 16 | polling_interval: 0.1.seconds 17 | message_retention: 1.day 18 | -------------------------------------------------------------------------------- /config/cache.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | store_options: 3 | # Cap age of oldest cache entry to fulfill retention policies 4 | # max_age: <%= 60.days.to_i %> 5 | max_size: <%= 256.megabytes %> 6 | namespace: <%= Rails.env %> 7 | 8 | development: 9 | <<: *default 10 | 11 | test: 12 | <<: *default 13 | 14 | production: 15 | database: cache 16 | <<: *default 17 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | adapter: postgresql 3 | encoding: unicode 4 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 5 | username: <%= ENV.fetch("DB_USERNAME", "") %> 6 | password: <%= ENV.fetch("DB_PASSWORD", "") %> 7 | host: localhost 8 | 9 | development: 10 | <<: *default 11 | database: highway_dev 12 | 13 | test: 14 | <<: *default 15 | database: highway_test 16 | 17 | production: 18 | primary: 19 | url: <%= ENV['DATABASE_URL'] %> 20 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 21 | timeout: 5000 22 | cache: 23 | url: <%= ENV['CACHE_DATABASE_URL'] || ENV['DATABASE_URL'] %> 24 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 25 | timeout: 5000 26 | migrations_paths: db/cache_migrate 27 | queue: 28 | url: <%= ENV['QUEUE_DATABASE_URL'] || ENV['DATABASE_URL'] %> 29 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 30 | timeout: 5000 31 | migrations_paths: db/queue_migrate 32 | cable: 33 | url: <%= ENV['CABLE_DATABASE_URL'] || ENV['DATABASE_URL'] %> 34 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 35 | timeout: 5000 36 | migrations_paths: db/cable_migrate 37 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative "application" 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # Make code changes take effect immediately without server restart. 7 | config.enable_reloading = true 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports. 13 | config.consider_all_requests_local = true 14 | 15 | # Enable server timing. 16 | config.server_timing = true 17 | 18 | # Enable/disable Action Controller caching. By default Action Controller caching is disabled. 19 | # Run rails dev:cache to toggle Action Controller caching. 20 | if Rails.root.join("tmp/caching-dev.txt").exist? 21 | config.action_controller.perform_caching = true 22 | config.action_controller.enable_fragment_cache_logging = true 23 | config.public_file_server.headers = { "cache-control" => "public, max-age=#{2.days.to_i}" } 24 | else 25 | config.action_controller.perform_caching = false 26 | end 27 | 28 | # Change to :null_store to avoid any caching. 29 | config.cache_store = :memory_store 30 | 31 | # Store uploaded files on the local file system (see config/storage.yml for options). 32 | config.active_storage.service = :local 33 | 34 | # Don't care if the mailer can't send. 35 | config.action_mailer.raise_delivery_errors = false 36 | 37 | # Make template changes take effect immediately. 38 | config.action_mailer.perform_caching = false 39 | 40 | # Set localhost to be used by links generated in mailer templates. 41 | config.action_mailer.default_url_options = { host: "localhost", port: 3000 } 42 | 43 | config.action_mailer.delivery_method = :letter_opener 44 | config.action_mailer.perform_deliveries = true 45 | 46 | # Print deprecation notices to the Rails logger. 47 | config.active_support.deprecation = :log 48 | 49 | # Raise an error on page load if there are pending migrations. 50 | config.active_record.migration_error = :page_load 51 | 52 | # Highlight code that triggered database queries in logs. 53 | config.active_record.verbose_query_logs = true 54 | 55 | # Append comments with runtime information tags to SQL queries in logs. 56 | config.active_record.query_log_tags_enabled = true 57 | 58 | # Highlight code that enqueued background job in logs. 59 | config.active_job.verbose_enqueue_logs = true 60 | 61 | # Raises error for missing translations. 62 | # config.i18n.raise_on_missing_translations = true 63 | 64 | # Annotate rendered view with file names. 65 | config.action_view.annotate_rendered_view_with_filenames = true 66 | 67 | # Uncomment if you wish to allow Action Cable access from any origin. 68 | # config.action_cable.disable_request_forgery_protection = true 69 | 70 | # Raise error when a before_action's only/except options reference missing actions. 71 | config.action_controller.raise_on_missing_callback_actions = true 72 | 73 | # Apply autocorrection by RuboCop to files generated by `bin/rails generate`. 74 | # config.generators.apply_rubocop_autocorrect_after_generate! 75 | end 76 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | # The test environment is used exclusively to run your application's 2 | # test suite. You never need to work with it otherwise. Remember that 3 | # your test database is "scratch space" for the test suite and is wiped 4 | # and recreated between test runs. Don't rely on the data there! 5 | 6 | Rails.application.configure do 7 | # Settings specified here will take precedence over those in config/application.rb. 8 | 9 | # While tests run files are not watched, reloading is not necessary. 10 | config.enable_reloading = false 11 | 12 | # Eager loading loads your entire application. When running a single test locally, 13 | # this is usually not necessary, and can slow down your test suite. However, it's 14 | # recommended that you enable it in continuous integration systems to ensure eager 15 | # loading is working properly before deploying your code. 16 | config.eager_load = ENV["CI"].present? 17 | 18 | # Configure public file server for tests with cache-control for performance. 19 | config.public_file_server.headers = { "cache-control" => "public, max-age=3600" } 20 | 21 | # Show full error reports. 22 | config.consider_all_requests_local = true 23 | config.cache_store = :null_store 24 | 25 | # Render exception templates for rescuable exceptions and raise for other exceptions. 26 | config.action_dispatch.show_exceptions = :rescuable 27 | 28 | # Disable request forgery protection in test environment. 29 | config.action_controller.allow_forgery_protection = false 30 | 31 | # Store uploaded files on the local file system in a temporary directory. 32 | config.active_storage.service = :test 33 | 34 | # Tell Action Mailer not to deliver emails to the real world. 35 | # The :test delivery method accumulates sent emails in the 36 | # ActionMailer::Base.deliveries array. 37 | config.action_mailer.delivery_method = :test 38 | 39 | # Set host to be used by links generated in mailer templates. 40 | config.action_mailer.default_url_options = { host: "example.com" } 41 | 42 | # Print deprecation notices to the stderr. 43 | config.active_support.deprecation = :stderr 44 | 45 | # Raises error for missing translations. 46 | # config.i18n.raise_on_missing_translations = true 47 | 48 | # Annotate rendered view with file names. 49 | # config.action_view.annotate_rendered_view_with_filenames = true 50 | 51 | # Raise error when a before_action's only/except options reference missing actions. 52 | config.action_controller.raise_on_missing_callback_actions = true 53 | end 54 | -------------------------------------------------------------------------------- /config/highlighted_projects.yml: -------------------------------------------------------------------------------- 1 | - hackclub/awesome-project 2 | - AGB556/hydra 3 | - programmerturtle/donotdelta -------------------------------------------------------------------------------- /config/importmap.rb: -------------------------------------------------------------------------------- 1 | # Pin npm packages by running ./bin/importmap 2 | 3 | pin "application" 4 | pin "@hotwired/turbo-rails", to: "turbo.min.js" 5 | pin "@hotwired/stimulus", to: "stimulus.min.js" 6 | pin "@hotwired/stimulus-loading", to: "stimulus-loading.js" 7 | pin_all_from "app/javascript/controllers", under: "controllers" 8 | pin "trix" 9 | pin "@rails/actiontext", to: "actiontext.esm.js" 10 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = "1.0" 5 | 6 | Rails.application.config.assets.precompile += %w[ *.otf *.ttf *.woff *.woff2 ] 7 | 8 | Rails.application.config.assets.paths << Rails.root.join("app", "assets", "fonts") 9 | 10 | # Add additional assets to the asset load path. 11 | # Rails.application.config.assets.paths << Emoji.images_path 12 | -------------------------------------------------------------------------------- /config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy. 4 | # See the Securing Rails Applications Guide for more information: 5 | # https://guides.rubyonrails.org/security.html#content-security-policy-header 6 | 7 | # Rails.application.configure do 8 | # config.content_security_policy do |policy| 9 | # policy.default_src :self, :https 10 | # policy.font_src :self, :https, :data 11 | # policy.img_src :self, :https, :data 12 | # policy.object_src :none 13 | # policy.script_src :self, :https 14 | # policy.style_src :self, :https 15 | # # Specify URI for violation reports 16 | # # policy.report_uri "/csp-violation-report-endpoint" 17 | # end 18 | # 19 | # # Generate session nonces for permitted importmap, inline scripts, and inline styles. 20 | # config.content_security_policy_nonce_generator = ->(request) { request.session.id.to_s } 21 | # config.content_security_policy_nonce_directives = %w(script-src style-src) 22 | # 23 | # # Report violations without enforcing the policy. 24 | # # config.content_security_policy_report_only = true 25 | # end 26 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. 4 | # Use this to limit dissemination of sensitive information. 5 | # See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. 6 | Rails.application.config.filter_parameters += [ 7 | :passw, :email, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn, :cvv, :cvc 8 | ] 9 | -------------------------------------------------------------------------------- /config/initializers/good_job.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | config.active_job.queue_adapter = :good_job 3 | config.good_job.preserve_job_records = true 4 | config.good_job.cleanup_preserved_jobs_before_seconds_ago = 60 * 60 * 24 * 7 5 | config.good_job.cleanup_interval_jobs = 1000 6 | config.good_job.cleanup_interval_seconds = 3600 7 | 8 | config.good_job.execution_mode = :async 9 | 10 | config.good_job.enable_cron = Rails.env.production? 11 | config.good_job.cron_graceful_restart_period = 1.minute 12 | config.good_job.cron = { 13 | clone_projects: { 14 | cron: "*/10 * * * *", 15 | class: "CloneProjectsJob" 16 | } 17 | } 18 | end 19 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, "\\1en" 8 | # inflect.singular /^(ox)en/i, "\\1" 9 | # inflect.irregular "person", "people" 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym "RESTful" 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/markdown.rb: -------------------------------------------------------------------------------- 1 | module MarkdownHandler 2 | def self.erb 3 | @erb ||= ActionView::Template.registered_template_handler(:erb) 4 | end 5 | 6 | def self.call(template, source) 7 | compiled_source = erb.call(template, source) 8 | "Redcarpet::Markdown.new(Redcarpet::Render::HTML.new).render(begin;#{compiled_source};end.to_s).html_safe" 9 | end 10 | end 11 | 12 | ActionView::Template.register_template_handler :md, MarkdownHandler 13 | -------------------------------------------------------------------------------- /config/initializers/rails_live_reload.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | RailsLiveReload.configure do |config| 4 | # config.url = "/rails/live/reload" 5 | 6 | # Default watched folders & files 7 | # config.watch %r{app/views/.+\.(erb|haml|slim)$} 8 | # config.watch %r{(app|vendor)/(assets|javascript)/\w+/(.+\.(css|js|html|png|jpg|ts|jsx)).*}, reload: :always 9 | 10 | # More examples: 11 | # config.watch %r{app/helpers/.+\.rb}, reload: :always 12 | # config.watch %r{config/locales/.+\.yml}, reload: :always 13 | 14 | # config.enabled = Rails.env.development? 15 | end if defined?(RailsLiveReload) 16 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization and 2 | # are automatically loaded by Rails. If you want to use locales other than 3 | # English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t "hello" 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t("hello") %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more about the API, please read the Rails Internationalization guide 20 | # at https://guides.rubyonrails.org/i18n.html. 21 | # 22 | # Be aware that YAML interprets the following case-insensitive strings as 23 | # booleans: `true`, `false`, `on`, `off`, `yes`, `no`. Therefore, these strings 24 | # must be quoted to be interpreted as strings. For example: 25 | # 26 | # en: 27 | # "yes": yup 28 | # enabled: "ON" 29 | 30 | en: 31 | hello: "Hello world" 32 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | # This configuration file will be evaluated by Puma. The top-level methods that 2 | # are invoked here are part of Puma's configuration DSL. For more information 3 | # about methods provided by the DSL, see https://puma.io/puma/Puma/DSL.html. 4 | # 5 | # Puma starts a configurable number of processes (workers) and each process 6 | # serves each request in a thread from an internal thread pool. 7 | # 8 | # You can control the number of workers using ENV["WEB_CONCURRENCY"]. You 9 | # should only set this value when you want to run 2 or more workers. The 10 | # default is already 1. 11 | # 12 | # The ideal number of threads per worker depends both on how much time the 13 | # application spends waiting for IO operations and on how much you wish to 14 | # prioritize throughput over latency. 15 | # 16 | # As a rule of thumb, increasing the number of threads will increase how much 17 | # traffic a given process can handle (throughput), but due to CRuby's 18 | # Global VM Lock (GVL) it has diminishing returns and will degrade the 19 | # response time (latency) of the application. 20 | # 21 | # The default is set to 3 threads as it's deemed a decent compromise between 22 | # throughput and latency for the average Rails application. 23 | # 24 | # Any libraries that use a connection pool or another resource pool should 25 | # be configured to provide at least as many connections as the number of 26 | # threads. This includes Active Record's `pool` parameter in `database.yml`. 27 | threads_count = ENV.fetch("RAILS_MAX_THREADS", 3) 28 | threads threads_count, threads_count 29 | 30 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 31 | port ENV.fetch("PORT", 3000) 32 | 33 | # Allow puma to be restarted by `bin/rails restart` command. 34 | plugin :tmp_restart 35 | 36 | # Run the Solid Queue supervisor inside of Puma for single-server deployments 37 | plugin :solid_queue if ENV["SOLID_QUEUE_IN_PUMA"] 38 | 39 | # Specify the PID file. Defaults to tmp/pids/server.pid in development. 40 | # In other environments, only set the PID file if requested. 41 | pidfile ENV["PIDFILE"] if ENV["PIDFILE"] 42 | -------------------------------------------------------------------------------- /config/queue.yml: -------------------------------------------------------------------------------- 1 | default: &default 2 | dispatchers: 3 | - polling_interval: 1 4 | batch_size: 500 5 | workers: 6 | - queues: "*" 7 | threads: 3 8 | processes: <%= ENV.fetch("JOB_CONCURRENCY", 1) %> 9 | polling_interval: 0.1 10 | 11 | development: 12 | <<: *default 13 | 14 | test: 15 | <<: *default 16 | 17 | production: 18 | <<: *default 19 | -------------------------------------------------------------------------------- /config/recurring.yml: -------------------------------------------------------------------------------- 1 | # production: 2 | # periodic_cleanup: 3 | # class: CleanSoftDeletedRecordsJob 4 | # queue: background 5 | # args: [ 1000, { batch_size: 500 } ] 6 | # schedule: every hour 7 | # periodic_command: 8 | # command: "SoftDeletedRecord.due.delete_all" 9 | # priority: 2 10 | # schedule: at 5am every day 11 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html 3 | 4 | # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. 5 | # Can be used by load balancers and uptime monitors to verify that the app is live. 6 | get "up" => "rails/health#show", as: :rails_health_check 7 | 8 | # Render dynamic PWA files from app/views/pwa/* (remember to link manifest in application.html.erb) 9 | # get "manifest" => "rails/pwa#manifest", as: :pwa_manifest 10 | # get "service-worker" => "rails/pwa#service_worker", as: :pwa_service_worker 11 | 12 | # Defines the root path route ("/") 13 | root "landing#index" 14 | resources :users 15 | get "/projects", to: "projects#index" 16 | get "/projects/:user/:project_name", to: "projects#show", as: :project 17 | 18 | get "/info", to: "info#show" 19 | 20 | get "/dashboard", to: "landing#dashboard", as: :dashboard 21 | get "/leaderboards", to: "landing#leaderboards", as: :leaderboards 22 | 23 | resources :admin, only: [] do 24 | collection do 25 | get "/dashboard", to: "admin#dashboard", as: :dashboard 26 | end 27 | end 28 | 29 | # otp auth + session 30 | # resources :sessions 31 | 32 | post "/signin", to: "sessions#create", as: :signin 33 | get "/auth/code/:code", to: "sessions#exchange_code", as: :exchange_code 34 | post "/rsvp", to: "rsvps#create", as: :rsvp 35 | 36 | if Rails.env.development? 37 | mount LetterOpenerWeb::Engine, at: "/letter_opener" 38 | end 39 | 40 | ## prize shit 41 | resources :prizes do 42 | member do 43 | post :add_to_box 44 | end 45 | end 46 | 47 | resources :user_prizes, only: [] do 48 | member do 49 | patch :claim 50 | end 51 | end 52 | 53 | get "/prize_box", to: "users#prize_box", as: :prize_box 54 | 55 | get "/starter-projects", to: "launchpad#show" 56 | get "/getting-started", to: redirect("/getting-started/overview") 57 | get "/getting-started/:page", to: "overview#show", as: "overview_page" 58 | 59 | get "/advanced/:page", to: "advanced#show", as: "advanced_page" 60 | get "/advanced/", to: redirect("/advanced/overview") 61 | 62 | get "/guides/:page", to: "guides#show", as: "guides_page" 63 | get "/guides/", to: redirect("/guides/overview") 64 | 65 | get "/events", to: "events#index" 66 | end 67 | -------------------------------------------------------------------------------- /config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | 9 | # Use bin/rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) 10 | # amazon: 11 | # service: S3 12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> 13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> 14 | # region: us-east-1 15 | # bucket: your_own_bucket-<%= Rails.env %> 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket-<%= Rails.env %> 23 | 24 | # Use bin/rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name-<%= Rails.env %> 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /content/projects/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/content/projects/.keep -------------------------------------------------------------------------------- /content/projects/hackclub/awesome-project/journal.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Highway - A Modern Web Development Framework" 3 | author: "Max Wofford" 4 | description: "A framework for building modern web applications with a focus on developer experience and performance" 5 | created_at: "2024-03-20" 6 | --- 7 | 8 | 9 | 10 | Highway is a framework designed to make web development more accessible and enjoyable. Built with modern best practices in mind, it provides a streamlined development experience while maintaining flexibility and power. 11 | 12 | ![](./logo2.png) 13 | 14 | ## Key Features 15 | 16 | - **Modern Architecture**: Built on top of Rails 8, leveraging the latest web technologies 17 | - **Developer Experience**: Hot reloading, intuitive APIs, and comprehensive documentation 18 | - **Performance First**: Optimized for speed and efficiency out of the box 19 | - **Extensible**: Easy to customize and extend with plugins and middleware 20 | 21 | ## Getting Started 22 | 23 | 1. Clone the repository: 24 | ```bash 25 | git clone https://github.com/hackclub/highway.git 26 | cd highway 27 | ``` 28 | 29 | 2. Install dependencies: 30 | ```bash 31 | bundle install 32 | ``` 33 | 34 | 3. Start the development server: 35 | ```bash 36 | bin/dev 37 | ``` 38 | 39 | ## Project Structure 40 | 41 | ``` 42 | highway/ 43 | ├── app/ 44 | │ ├── controllers/ 45 | │ ├── models/ 46 | │ └── views/ 47 | ├── config/ 48 | ├── content/ 49 | │ └── projects/ 50 | └── public/ 51 | ``` 52 | 53 | ## Development Progress 54 | 55 | ### Week 1 56 | - Set up basic project structure 57 | - Implemented core routing system 58 | - Added basic authentication 59 | 60 | ### Week 2 61 | - Built project documentation system 62 | - Implemented markdown rendering 63 | - Added project submission workflow 64 | 65 | ## Next Steps 66 | 67 | - [ ] Add more comprehensive testing 68 | - [ ] Improve documentation 69 | - [ ] Add more example projects 70 | - [ ] Implement CI/CD pipeline 71 | 72 | ## Contributing 73 | 74 | We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for more details. 75 | 76 | ## License 77 | 78 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. -------------------------------------------------------------------------------- /content/projects/hackclub/awesome-project/logo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/content/projects/hackclub/awesome-project/logo2.png -------------------------------------------------------------------------------- /db/cable_schema.rb: -------------------------------------------------------------------------------- 1 | ActiveRecord::Schema[7.1].define(version: 1) do 2 | create_table "solid_cable_messages", force: :cascade do |t| 3 | t.binary "channel", limit: 1024, null: false 4 | t.binary "payload", limit: 536870912, null: false 5 | t.datetime "created_at", null: false 6 | t.integer "channel_hash", limit: 8, null: false 7 | t.index ["channel"], name: "index_solid_cable_messages_on_channel" 8 | t.index ["channel_hash"], name: "index_solid_cable_messages_on_channel_hash" 9 | t.index ["created_at"], name: "index_solid_cable_messages_on_created_at" 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/cache_schema.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | ActiveRecord::Schema[7.2].define(version: 1) do 4 | create_table "solid_cache_entries", force: :cascade do |t| 5 | t.binary "key", limit: 1024, null: false 6 | t.binary "value", limit: 536870912, null: false 7 | t.datetime "created_at", null: false 8 | t.integer "key_hash", limit: 8, null: false 9 | t.integer "byte_size", limit: 4, null: false 10 | t.index ["byte_size"], name: "index_solid_cache_entries_on_byte_size" 11 | t.index ["key_hash", "byte_size"], name: "index_solid_cache_entries_on_key_hash_and_byte_size" 12 | t.index ["key_hash"], name: "index_solid_cache_entries_on_key_hash", unique: true 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20250425185735_create_posts.rb: -------------------------------------------------------------------------------- 1 | class CreatePosts < ActiveRecord::Migration[8.0] 2 | def change 3 | create_table :posts do |t| 4 | t.string :name 5 | 6 | t.timestamps 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /db/migrate/20250426202058_create_active_storage_tables.active_storage.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from active_storage (originally 20170806125915) 2 | class CreateActiveStorageTables < ActiveRecord::Migration[7.0] 3 | def change 4 | # Use Active Record's configured type for primary and foreign keys 5 | primary_key_type, foreign_key_type = primary_and_foreign_key_types 6 | 7 | create_table :active_storage_blobs, id: primary_key_type do |t| 8 | t.string :key, null: false 9 | t.string :filename, null: false 10 | t.string :content_type 11 | t.text :metadata 12 | t.string :service_name, null: false 13 | t.bigint :byte_size, null: false 14 | t.string :checksum 15 | 16 | if connection.supports_datetime_with_precision? 17 | t.datetime :created_at, precision: 6, null: false 18 | else 19 | t.datetime :created_at, null: false 20 | end 21 | 22 | t.index [ :key ], unique: true 23 | end 24 | 25 | create_table :active_storage_attachments, id: primary_key_type do |t| 26 | t.string :name, null: false 27 | t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type 28 | t.references :blob, null: false, type: foreign_key_type 29 | 30 | if connection.supports_datetime_with_precision? 31 | t.datetime :created_at, precision: 6, null: false 32 | else 33 | t.datetime :created_at, null: false 34 | end 35 | 36 | t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true 37 | t.foreign_key :active_storage_blobs, column: :blob_id 38 | end 39 | 40 | create_table :active_storage_variant_records, id: primary_key_type do |t| 41 | t.belongs_to :blob, null: false, index: false, type: foreign_key_type 42 | t.string :variation_digest, null: false 43 | 44 | t.index [ :blob_id, :variation_digest ], name: :index_active_storage_variant_records_uniqueness, unique: true 45 | t.foreign_key :active_storage_blobs, column: :blob_id 46 | end 47 | end 48 | 49 | private 50 | def primary_and_foreign_key_types 51 | config = Rails.configuration.generators 52 | setting = config.options[config.orm][:primary_key_type] 53 | primary_key_type = setting || :primary_key 54 | foreign_key_type = setting || :bigint 55 | [ primary_key_type, foreign_key_type ] 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /db/migrate/20250426202059_create_action_text_tables.action_text.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from action_text (originally 20180528164100) 2 | class CreateActionTextTables < ActiveRecord::Migration[6.0] 3 | def change 4 | # Use Active Record's configured type for primary and foreign keys 5 | primary_key_type, foreign_key_type = primary_and_foreign_key_types 6 | 7 | create_table :action_text_rich_texts, id: primary_key_type do |t| 8 | t.string :name, null: false 9 | t.text :body, size: :long 10 | t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type 11 | 12 | t.timestamps 13 | 14 | t.index [ :record_type, :record_id, :name ], name: "index_action_text_rich_texts_uniqueness", unique: true 15 | end 16 | end 17 | 18 | private 19 | def primary_and_foreign_key_types 20 | config = Rails.configuration.generators 21 | setting = config.options[config.orm][:primary_key_type] 22 | primary_key_type = setting || :primary_key 23 | foreign_key_type = setting || :bigint 24 | [ primary_key_type, foreign_key_type ] 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /db/migrate/20250427015515_add_hours_to_posts.rb: -------------------------------------------------------------------------------- 1 | class AddHoursToPosts < ActiveRecord::Migration[8.0] 2 | def change 3 | add_column :posts, :hours, :integer 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20250429161341_create_users.rb: -------------------------------------------------------------------------------- 1 | class CreateUsers < ActiveRecord::Migration[8.0] 2 | def change 3 | create_table :users do |t| 4 | t.string :email 5 | t.string :login_code 6 | t.datetime :login_code_expires_at 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20250504204551_add_details_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddDetailsToUsers < ActiveRecord::Migration[8.0] 2 | def change 3 | add_column :users, :first_name, :string 4 | add_column :users, :last_name, :string 5 | add_column :users, :username, :string 6 | add_column :users, :github, :string 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /db/migrate/20250505014600_create_projects.rb: -------------------------------------------------------------------------------- 1 | class CreateProjects < ActiveRecord::Migration[8.0] 2 | def change 3 | create_table :projects do |t| 4 | t.string :kitted_guide 5 | t.string :github_repo 6 | t.string :proposed_tier 7 | t.string :proposed_tier_explanation 8 | t.boolean :group_project 9 | 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20250505195247_add_user_to_projects.rb: -------------------------------------------------------------------------------- 1 | class AddUserToProjects < ActiveRecord::Migration[8.0] 2 | def change 3 | add_reference :projects, :user, null: false, foreign_key: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20250505195715_add_project_to_posts.rb: -------------------------------------------------------------------------------- 1 | class AddProjectToPosts < ActiveRecord::Migration[8.0] 2 | def change 3 | add_reference :posts, :project, null: false, foreign_key: true 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20250505200739_add_name_to_projects.rb: -------------------------------------------------------------------------------- 1 | class AddNameToProjects < ActiveRecord::Migration[8.0] 2 | def change 3 | add_column :projects, :name, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20250505203646_add_admin_to_users.rb: -------------------------------------------------------------------------------- 1 | class AddAdminToUsers < ActiveRecord::Migration[8.0] 2 | def change 3 | add_column :users, :admin, :boolean 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20250506160012_create_prizes.rb: -------------------------------------------------------------------------------- 1 | class CreatePrizes < ActiveRecord::Migration[8.0] 2 | def change 3 | create_table :prizes do |t| 4 | t.string :name 5 | t.string :sku 6 | t.boolean :claimable 7 | 8 | t.timestamps 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /db/migrate/20250506165025_create_user_prizes.rb: -------------------------------------------------------------------------------- 1 | class CreateUserPrizes < ActiveRecord::Migration[8.0] 2 | def change 3 | create_table :user_prizes do |t| 4 | t.references :user, null: false, foreign_key: true 5 | t.references :prize, null: false, foreign_key: true 6 | t.boolean :claimed 7 | t.datetime :claimed_at 8 | t.string :tracking_number 9 | 10 | t.timestamps 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /db/migrate/20250508022535_drop_posts_projects_and_prizes.rb: -------------------------------------------------------------------------------- 1 | class DropPostsProjectsAndPrizes < ActiveRecord::Migration[8.0] 2 | def up 3 | drop_table :posts if table_exists?(:posts) 4 | drop_table :projects if table_exists?(:projects) 5 | drop_table :prizes if table_exists?(:prizes) 6 | drop_table :user_prizes if table_exists?(:user_prizes) 7 | end 8 | 9 | def down 10 | raise ActiveRecord::IrreversibleMigration 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/migrate/20250508025519_create_rsvps.rb: -------------------------------------------------------------------------------- 1 | class CreateRsvps < ActiveRecord::Migration[8.0] 2 | def change 3 | create_table :rsvps do |t| 4 | t.string :email 5 | 6 | t.timestamps 7 | end 8 | add_index :rsvps, :email, unique: true 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20250508184653_add_airtable_record_id_to_rsvps.rb: -------------------------------------------------------------------------------- 1 | class AddAirtableRecordIdToRsvps < ActiveRecord::Migration[8.0] 2 | def change 3 | add_column :rsvps, :airtable_record_id, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20250508185907_add_url_params_to_rsvps.rb: -------------------------------------------------------------------------------- 1 | class AddUrlParamsToRsvps < ActiveRecord::Migration[8.0] 2 | def change 3 | add_column :rsvps, :url_params, :string 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should ensure the existence of records required to run the application in every environment (production, 2 | # development, test). The code here should be idempotent so that it can be executed at any point in every environment. 3 | # The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). 4 | # 5 | # Example: 6 | # 7 | # ["Action", "Comedy", "Drama", "Horror"].each do |genre_name| 8 | # MovieGenre.find_or_create_by!(name: genre_name) 9 | # end 10 | -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/lib/tasks/.keep -------------------------------------------------------------------------------- /lib/tasks/clone_projects.rake: -------------------------------------------------------------------------------- 1 | namespace :projects do 2 | desc "Clone or update all projects from submissions.yml" 3 | task clone: :environment do 4 | CloneProjectsJob.perform_now 5 | end 6 | 7 | desc "Remove all repos in content/projects except for hackclub/awesome-project" 8 | task drop: :environment do 9 | base_dir = Rails.root.join("content/projects") 10 | Dir.glob(base_dir.join("*/*")).each do |dir| 11 | next unless File.directory?(dir) 12 | # Keep hackclub/awesome-project 13 | if dir == base_dir.join("hackclub/awesome-project").to_s 14 | next 15 | end 16 | FileUtils.rm_rf(dir) 17 | puts "Removed #{dir}" 18 | end 19 | puts "Done removing all projects except hackclub/awesome-project." 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/log/.keep -------------------------------------------------------------------------------- /public/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/1.png -------------------------------------------------------------------------------- /public/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/2.png -------------------------------------------------------------------------------- /public/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/3.png -------------------------------------------------------------------------------- /public/arrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/arrows.png -------------------------------------------------------------------------------- /public/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/bg.png -------------------------------------------------------------------------------- /public/bg2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/bg2.png -------------------------------------------------------------------------------- /public/bg3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/bg3.png -------------------------------------------------------------------------------- /public/cerblights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/cerblights.png -------------------------------------------------------------------------------- /public/desc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/desc1.png -------------------------------------------------------------------------------- /public/desc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/desc2.png -------------------------------------------------------------------------------- /public/desc3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/desc3.png -------------------------------------------------------------------------------- /public/eventkickoff2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/eventkickoff2.png -------------------------------------------------------------------------------- /public/getstickers.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/getstickers.gif -------------------------------------------------------------------------------- /public/getstickers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/getstickers.png -------------------------------------------------------------------------------- /public/guardianoftheundercity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/guardianoftheundercity.png -------------------------------------------------------------------------------- /public/hackathons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/hackathons.png -------------------------------------------------------------------------------- /public/hackclubgh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/hackclubgh.png -------------------------------------------------------------------------------- /public/highwaymusic.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/highwaymusic.mp3 -------------------------------------------------------------------------------- /public/highwaystar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/highwaystar.png -------------------------------------------------------------------------------- /public/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/icon.png -------------------------------------------------------------------------------- /public/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/keypeople.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/keypeople.png -------------------------------------------------------------------------------- /public/landingbg3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/landingbg3.png -------------------------------------------------------------------------------- /public/landingbg4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/landingbg4.png -------------------------------------------------------------------------------- /public/logo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/logo2.png -------------------------------------------------------------------------------- /public/portal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/portal.png -------------------------------------------------------------------------------- /public/projects: -------------------------------------------------------------------------------- 1 | ../content/projects -------------------------------------------------------------------------------- /public/ref/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/1.png -------------------------------------------------------------------------------- /public/ref/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/2.png -------------------------------------------------------------------------------- /public/ref/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/3.png -------------------------------------------------------------------------------- /public/ref/arrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/arrows.png -------------------------------------------------------------------------------- /public/ref/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/bg.png -------------------------------------------------------------------------------- /public/ref/bg2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/bg2.png -------------------------------------------------------------------------------- /public/ref/bg3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/bg3.png -------------------------------------------------------------------------------- /public/ref/cerblights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/cerblights.png -------------------------------------------------------------------------------- /public/ref/getstickers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/getstickers.png -------------------------------------------------------------------------------- /public/ref/hackclubgh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/hackclubgh.png -------------------------------------------------------------------------------- /public/ref/highwaystar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/highwaystar.png -------------------------------------------------------------------------------- /public/ref/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/icon.png -------------------------------------------------------------------------------- /public/ref/landingbg3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/landingbg3.png -------------------------------------------------------------------------------- /public/ref/landingbg4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/landingbg4.png -------------------------------------------------------------------------------- /public/ref/logo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/logo2.png -------------------------------------------------------------------------------- /public/ref/portal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/portal.png -------------------------------------------------------------------------------- /public/ref/stickerbomb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/stickerbomb.png -------------------------------------------------------------------------------- /public/ref/stickerbomb2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/stickerbomb2.png -------------------------------------------------------------------------------- /public/ref/track1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/track1.png -------------------------------------------------------------------------------- /public/ref/track2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/track2.png -------------------------------------------------------------------------------- /public/ref/undercitylogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/undercitylogo.png -------------------------------------------------------------------------------- /public/ref/undercitylogo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/ref/undercitylogo2.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | -------------------------------------------------------------------------------- /public/stickerbomb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/stickerbomb.png -------------------------------------------------------------------------------- /public/stickerbomb2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/stickerbomb2.png -------------------------------------------------------------------------------- /public/strangeparts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/strangeparts.png -------------------------------------------------------------------------------- /public/strangeparts2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/strangeparts2.png -------------------------------------------------------------------------------- /public/swagsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/swagsystem.png -------------------------------------------------------------------------------- /public/track1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/track1.png -------------------------------------------------------------------------------- /public/track2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/track2.png -------------------------------------------------------------------------------- /public/undercitygate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/undercitygate.png -------------------------------------------------------------------------------- /public/undercitylogo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/undercitylogo.png -------------------------------------------------------------------------------- /public/undercitylogo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/public/undercitylogo2.png -------------------------------------------------------------------------------- /script/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/script/.keep -------------------------------------------------------------------------------- /storage/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/storage/.keep -------------------------------------------------------------------------------- /test/application_system_test_case.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ApplicationSystemTestCase < ActionDispatch::SystemTestCase 4 | driven_by :selenium, using: :headless_chrome, screen_size: [ 1400, 1400 ] 5 | end 6 | -------------------------------------------------------------------------------- /test/controllers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/test/controllers/.keep -------------------------------------------------------------------------------- /test/controllers/events_controller_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class EventsControllerTest < ActionDispatch::IntegrationTest 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/controllers/guides_controller_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class GuidesControllerTest < ActionDispatch::IntegrationTest 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/controllers/info_controller_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class InfoControllerTest < ActionDispatch::IntegrationTest 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/controllers/launchpad_controller_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class LaunchpadControllerTest < ActionDispatch::IntegrationTest 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/controllers/overview_controller_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class OverviewControllerTest < ActionDispatch::IntegrationTest 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/controllers/sessions_controller_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class SessionsControllerTest < ActionDispatch::IntegrationTest 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/fixtures/action_text/rich_texts.yml: -------------------------------------------------------------------------------- 1 | # one: 2 | # record: name_of_fixture (ClassOfFixture) 3 | # name: content 4 | # body:

In a million stars!

5 | -------------------------------------------------------------------------------- /test/fixtures/files/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/test/fixtures/files/.keep -------------------------------------------------------------------------------- /test/fixtures/rsvps.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | one: 4 | email: MyString 5 | 6 | two: 7 | email: MyString 8 | -------------------------------------------------------------------------------- /test/fixtures/users.yml: -------------------------------------------------------------------------------- 1 | # Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html 2 | 3 | one: 4 | email: MyString 5 | login_code: MyString 6 | login_code_expires_at: 2025-04-29 12:13:41 7 | 8 | two: 9 | email: MyString 10 | login_code: MyString 11 | login_code_expires_at: 2025-04-29 12:13:41 12 | -------------------------------------------------------------------------------- /test/helpers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/test/helpers/.keep -------------------------------------------------------------------------------- /test/integration/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/test/integration/.keep -------------------------------------------------------------------------------- /test/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/test/mailers/.keep -------------------------------------------------------------------------------- /test/mailers/previews/session_mailer_preview.rb: -------------------------------------------------------------------------------- 1 | # Preview all emails at http://localhost:3000/rails/mailers/session_mailer 2 | class SessionMailerPreview < ActionMailer::Preview 3 | # Preview this email at http://localhost:3000/rails/mailers/session_mailer/login_token 4 | def login_token 5 | SessionMailer.login_token 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/mailers/session_mailer_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class SessionMailerTest < ActionMailer::TestCase 4 | test "login_code" do 5 | mail = SessionMailer.login_code(email: "to@example.org", login_code: "123456") 6 | assert_equal "Login code", mail.subject 7 | assert_equal [ "to@example.org" ], mail.to 8 | assert_equal [ "from@example.com" ], mail.from 9 | assert_match "Hi", mail.body.encoded 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /test/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/test/models/.keep -------------------------------------------------------------------------------- /test/models/rsvp_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class RsvpTest < ActiveSupport::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/models/user_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class UserTest < ActiveSupport::TestCase 4 | # test "the truth" do 5 | # assert true 6 | # end 7 | end 8 | -------------------------------------------------------------------------------- /test/system/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/test/system/.keep -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV["RAILS_ENV"] ||= "test" 2 | require_relative "../config/environment" 3 | require "rails/test_help" 4 | 5 | module ActiveSupport 6 | class TestCase 7 | # Run tests in parallel with specified workers 8 | parallelize(workers: :number_of_processors) 9 | 10 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 11 | fixtures :all 12 | 13 | # Add more helper methods to be used by all tests here... 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/tmp/.keep -------------------------------------------------------------------------------- /tmp/pids/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/tmp/pids/.keep -------------------------------------------------------------------------------- /tmp/storage/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/tmp/storage/.keep -------------------------------------------------------------------------------- /vendor/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/vendor/.keep -------------------------------------------------------------------------------- /vendor/javascript/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hackclub/highway/f796ccb7456d4cb9684619bf3798508e5c856ae3/vendor/javascript/.keep --------------------------------------------------------------------------------