├── .gitignore ├── Gemfile ├── Gemfile.lock ├── README.md ├── app.rb ├── config.ru ├── github_wrapper.rb ├── public ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── card.css ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── index.css ├── masonry.css └── site.webmanifest └── views ├── _error.erb ├── _footer.erb ├── _head.erb ├── _navbar.erb ├── _searchbar.erb ├── card.erb ├── index.erb └── masonry.erb /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | /.config 4 | /coverage/ 5 | /InstalledFiles 6 | /pkg/ 7 | /spec/reports/ 8 | /spec/examples.txt 9 | /test/tmp/ 10 | /test/version_tmp/ 11 | /tmp/ 12 | 13 | # Used by dotenv library to load environment variables. 14 | # .env 15 | 16 | # Ignore Byebug command history file. 17 | .byebug_history 18 | 19 | ## Specific to RubyMotion: 20 | .dat* 21 | .repl_history 22 | build/ 23 | *.bridgesupport 24 | build-iPhoneOS/ 25 | build-iPhoneSimulator/ 26 | 27 | ## Specific to RubyMotion (use of CocoaPods): 28 | # 29 | # We recommend against adding the Pods directory to your .gitignore. However 30 | # you should judge for yourself, the pros and cons are mentioned at: 31 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 32 | # 33 | # vendor/Pods/ 34 | 35 | ## Documentation cache and generated files: 36 | /.yardoc/ 37 | /_yardoc/ 38 | /doc/ 39 | /rdoc/ 40 | 41 | ## Environment normalization: 42 | /.bundle/ 43 | /vendor/bundle 44 | /lib/bundler/man/ 45 | 46 | # for a library or gem, you might want to ignore these files since the code is 47 | # intended to run in multiple environments; otherwise, check them in: 48 | # Gemfile.lock 49 | # .ruby-version 50 | # .ruby-gemset 51 | 52 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 53 | .rvmrc 54 | 55 | # Used by RuboCop. Remote config files pulled in from inherit_from directive. 56 | # .rubocop-https?--* 57 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Gemfile 4 | 5 | source 'https://rubygems.org' 6 | 7 | git_source(:github) { |repo_name| "https://github.com/#{repo_name}" } 8 | 9 | gem 'better_errors' 10 | gem 'binding_of_caller' 11 | gem 'github_api' 12 | gem 'language_colors' 13 | gem 'octicons' 14 | gem 'sass' 15 | gem 'sinatra' 16 | gem 'sinatra-contrib' 17 | 18 | gem "rackup", "~> 2.1" 19 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | addressable (2.8.7) 5 | public_suffix (>= 2.0.2, < 7.0) 6 | base64 (0.2.0) 7 | better_errors (2.10.1) 8 | erubi (>= 1.0.0) 9 | rack (>= 0.9.0) 10 | rouge (>= 1.0.0) 11 | bigdecimal (3.1.8) 12 | binding_of_caller (1.0.1) 13 | debug_inspector (>= 1.2.0) 14 | debug_inspector (1.2.0) 15 | descendants_tracker (0.0.4) 16 | thread_safe (~> 0.3, >= 0.3.1) 17 | erubi (1.13.0) 18 | faraday (1.10.4) 19 | faraday-em_http (~> 1.0) 20 | faraday-em_synchrony (~> 1.0) 21 | faraday-excon (~> 1.1) 22 | faraday-httpclient (~> 1.0) 23 | faraday-multipart (~> 1.0) 24 | faraday-net_http (~> 1.0) 25 | faraday-net_http_persistent (~> 1.0) 26 | faraday-patron (~> 1.0) 27 | faraday-rack (~> 1.0) 28 | faraday-retry (~> 1.0) 29 | ruby2_keywords (>= 0.0.4) 30 | faraday-em_http (1.0.0) 31 | faraday-em_synchrony (1.0.0) 32 | faraday-excon (1.1.0) 33 | faraday-httpclient (1.0.1) 34 | faraday-multipart (1.0.4) 35 | multipart-post (~> 2) 36 | faraday-net_http (1.0.2) 37 | faraday-net_http_persistent (1.2.0) 38 | faraday-patron (1.0.0) 39 | faraday-rack (1.0.0) 40 | faraday-retry (1.0.3) 41 | ffi (1.17.0) 42 | github_api (0.19.0) 43 | addressable (~> 2.4) 44 | descendants_tracker (~> 0.0.4) 45 | faraday (>= 0.8, < 2) 46 | hashie (~> 3.5, >= 3.5.2) 47 | oauth2 (~> 1.0) 48 | hashie (3.6.0) 49 | jwt (2.9.3) 50 | base64 51 | language_colors (0.1.3) 52 | multi_json (1.15.0) 53 | multi_xml (0.7.1) 54 | bigdecimal (~> 3.1) 55 | multipart-post (2.4.1) 56 | mustermann (3.0.3) 57 | ruby2_keywords (~> 0.0.1) 58 | oauth2 (1.4.11) 59 | faraday (>= 0.17.3, < 3.0) 60 | jwt (>= 1.0, < 3.0) 61 | multi_json (~> 1.3) 62 | multi_xml (~> 0.5) 63 | rack (>= 1.2, < 4) 64 | octicons (19.11.0) 65 | public_suffix (6.0.1) 66 | rack (3.1.7) 67 | rack-protection (4.0.0) 68 | base64 (>= 0.1.0) 69 | rack (>= 3.0.0, < 4) 70 | rack-session (2.0.0) 71 | rack (>= 3.0.0) 72 | rackup (2.1.0) 73 | rack (>= 3) 74 | webrick (~> 1.8) 75 | rb-fsevent (0.11.2) 76 | rb-inotify (0.11.1) 77 | ffi (~> 1.0) 78 | rouge (4.4.0) 79 | ruby2_keywords (0.0.5) 80 | sass (3.7.4) 81 | sass-listen (~> 4.0.0) 82 | sass-listen (4.0.0) 83 | rb-fsevent (~> 0.9, >= 0.9.4) 84 | rb-inotify (~> 0.9, >= 0.9.7) 85 | sinatra (4.0.0) 86 | mustermann (~> 3.0) 87 | rack (>= 3.0.0, < 4) 88 | rack-protection (= 4.0.0) 89 | rack-session (>= 2.0.0, < 3) 90 | tilt (~> 2.0) 91 | sinatra-contrib (4.0.0) 92 | multi_json (>= 0.0.2) 93 | mustermann (~> 3.0) 94 | rack-protection (= 4.0.0) 95 | sinatra (= 4.0.0) 96 | tilt (~> 2.0) 97 | thread_safe (0.3.6) 98 | tilt (2.4.0) 99 | webrick (1.8.2) 100 | 101 | PLATFORMS 102 | ruby 103 | 104 | DEPENDENCIES 105 | better_errors 106 | binding_of_caller 107 | github_api 108 | language_colors 109 | octicons 110 | rackup (~> 2.1) 111 | sass 112 | sinatra 113 | sinatra-contrib 114 | 115 | BUNDLED WITH 116 | 2.5.21 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Github Stars 2 | 3 | ## Demo 4 | 5 | Check it out [here](https://github-stars-in-ruby.herokuapp.com/) 6 | 7 | ![search](https://user-images.githubusercontent.com/18503982/80301206-5cb5fa80-8768-11ea-86fa-1171f9ff7a66.png) 8 | 9 | ## Reason 10 | 11 | Github only shows 30 repositories per page on a user's profile. Personally, I have 350+ starred repositories, so having to click "Next" for every page is ridiculous. 12 | 13 | ## Time Saved 14 | 15 | This really depends on how many stars a user has on their page. For my account [@syedabutalib](https://github.com/SyedAbutalib), it takes 53 seconds to get to the last page of my starred repositories. Using this app, it only took 11 seconds, which is only 20% of the original time. 16 | 17 | ## Installation 18 | 19 | `gem install bundler` 20 | 21 | `bundle install` 22 | 23 | `ruby app.rb` 24 | 25 | go to `http://localhost:4567/` 26 | -------------------------------------------------------------------------------- /app.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'sinatra' 4 | require 'sinatra/reloader' if development? 5 | require 'better_errors' 6 | require 'octicons' 7 | require 'language_colors' 8 | 9 | configure :development do 10 | use BetterErrors::Middleware 11 | BetterErrors.application_root = __dir__ 12 | end 13 | 14 | require_relative 'github_wrapper' 15 | 16 | get('/') do 17 | erb :index 18 | end 19 | 20 | not_found do 21 | erb :index, locals: { rip: 'Invalid page.' } 22 | end 23 | 24 | post('/') do 25 | username = params[:username] || 'alipervaiz' 26 | g = GithubWrapper.new 27 | list = g.goodies(username) 28 | if list.nil? 29 | return erb :index, locals: { rip: 'The username you have entered does not exist.' } 30 | end 31 | 32 | @list = list 33 | @repo = Octicons::Octicon.new('repo') 34 | @dot = Octicons::Octicon.new('dot-fill') 35 | @star = Octicons::Octicon.new('star') 36 | @forked = Octicons::Octicon.new('repo-forked') 37 | @lc = LanguageColors::LanguageColors.new 38 | # puts Gem.loaded_specs.values.map(&:full_gem_path) 39 | 40 | erb :masonry, locals: { list: @list, 'username' => username, 41 | repo: @repo.to_svg, dot: @dot.to_svg, 42 | star: @star.to_svg, forked: @forked.to_svg, lc: @lc } 43 | end 44 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | require './app' 2 | run Sinatra::Application 3 | -------------------------------------------------------------------------------- /github_wrapper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'github_api' 4 | 5 | # This class will hold the stars function 6 | class GithubWrapper 7 | def stars(username) 8 | gh = Github.new auto_pagination: true 9 | mashes = gh.activity.starring.starred user: username 10 | # logger(mashes.first) 11 | list = [] 12 | mashes.each do |f| 13 | list << f.full_name 14 | end 15 | list 16 | end 17 | 18 | def goodies(username) 19 | gh = Github.new auto_pagination: true 20 | begin 21 | mashes = gh.activity.starring.starred user: username 22 | rescue StandardError 23 | return nil 24 | end 25 | 26 | list = [] 27 | mashes.each do |f| 28 | list << [f.name, f.description, f.forks_count, f.stargazers_count, 29 | f.language, f.full_name] 30 | end 31 | list 32 | end 33 | 34 | def logger(mash) 35 | puts "\n\nlogger has ran\n\n" 36 | File.open('mash.log', 'w') { |f| f.write mash.to_s } 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SyedAbuTalib/Github-Stars/0f181cbd5de36b6a081f7c0d213148d899c9dbd9/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SyedAbuTalib/Github-Stars/0f181cbd5de36b6a081f7c0d213148d899c9dbd9/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SyedAbuTalib/Github-Stars/0f181cbd5de36b6a081f7c0d213148d899c9dbd9/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/card.css: -------------------------------------------------------------------------------- 1 | @import url(https://cdn.jsdelivr.net/gh/tonsky/FiraCode@3/distr/fira_code.css); 2 | 3 | .card-text, 4 | .card-title { 5 | font-family: "Fira Code", monospace; 6 | } 7 | 8 | @supports (font-variation-settings: normal) { 9 | .card-text, 10 | .card-title { 11 | font-family: "Fira Code VF", monospace; 12 | } 13 | } 14 | 15 | .card-text { 16 | font-size: 0.9em; 17 | padding-right: 1em; 18 | overflow-wrap: break-word; 19 | } 20 | 21 | .card-bottom { 22 | display: flex; 23 | /* padding: 1em; */ 24 | font-size: 0.9em; 25 | } 26 | 27 | .box1 { 28 | box-sizing: inherit; 29 | margin: 0; 30 | color: rgb(36, 41, 46); 31 | box-shadow: rgba(0, 0, 0, 0.2) 0px 10px 30px -15px; 32 | text-align: left; 33 | font-family: "Roboto Mono", monospace; 34 | } 35 | -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SyedAbuTalib/Github-Stars/0f181cbd5de36b6a081f7c0d213148d899c9dbd9/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SyedAbuTalib/Github-Stars/0f181cbd5de36b6a081f7c0d213148d899c9dbd9/public/favicon-32x32.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SyedAbuTalib/Github-Stars/0f181cbd5de36b6a081f7c0d213148d899c9dbd9/public/favicon.ico -------------------------------------------------------------------------------- /public/index.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css?family=Dosis&display=swap"); 2 | 3 | body { 4 | font-family: "Dosis", sans-serif; 5 | font-style: normal; 6 | font-weight: 100; 7 | background-color: #f6fafb; 8 | } 9 | 10 | /* Base styling */ 11 | .mega { 12 | width: inherit; 13 | } 14 | 15 | .search_container { 16 | margin: 0 auto; 17 | padding-top: 64px; 18 | padding-bottom: 32px; 19 | } 20 | 21 | .search_title { 22 | font-size: 22px; 23 | font-weight: 900; 24 | text-align: center; 25 | color: #ff8b88; 26 | } 27 | 28 | .search_input { 29 | width: 100%; 30 | padding: 10px; 31 | 32 | background-color: transparent; 33 | transition: transform 250ms ease-in-out; 34 | font-size: 14px; 35 | line-height: 18px; 36 | 37 | color: #575756; 38 | background-color: transparent; 39 | 40 | border-radius: 50px; 41 | border: 1px solid #575756; 42 | transition: all 250ms ease-in-out; 43 | backface-visibility: hidden; 44 | } 45 | 46 | .search_input::placeholder { 47 | color: rgba(87, 87, 86, 0.8); 48 | text-transform: uppercase; 49 | letter-spacing: 1.5px; 50 | } 51 | 52 | .search_input:hover, 53 | .search_input:focus { 54 | padding: 12px 0; 55 | outline: 0; 56 | border: 1px solid transparent; 57 | border-bottom: 1px solid #575756; 58 | border-radius: 0; 59 | background-position: 100% center; 60 | } 61 | 62 | .credits_container { 63 | margin-top: 24px; 64 | } 65 | 66 | .credits_text { 67 | text-align: center; 68 | font-size: 13px; 69 | line-height: 18px; 70 | } 71 | 72 | .heart { 73 | color: #e25555; 74 | } 75 | 76 | .fake_user { 77 | margin: auto; 78 | width: 40%; 79 | } 80 | 81 | /* search_container on large screens */ 82 | @media only screen and (min-width: 1024px) { 83 | .search_container { 84 | width: 430px; 85 | margin: auto; 86 | } 87 | } 88 | 89 | /* search_container on medium-sized screens */ 90 | @media only screen and (max-width: 1023px) and (min-width: 768px) { 91 | .search_container { 92 | width: 430px; 93 | margin: auto; 94 | } 95 | } 96 | 97 | /* search_container on small screens */ 98 | @media only screen and (max-width: 767px) and (min-width: 0px) { 99 | .search_container { 100 | width: 80%; 101 | margin: auto; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /public/masonry.css: -------------------------------------------------------------------------------- 1 | /* Box-sizing reset: //w3bits.com/?p=3225 */ 2 | html { 3 | box-sizing: content-box; 4 | } 5 | 6 | img { 7 | max-width: 100%; 8 | height: auto; 9 | } 10 | 11 | *, 12 | *:before, 13 | *:after { 14 | box-sizing: inherit; 15 | } 16 | 17 | /* The Masonry Container */ 18 | .masonry { 19 | /* margin: 1.5em auto; */ 20 | margin: 0 auto; 21 | max-width: 90%; 22 | column-gap: 1em; 23 | } 24 | 25 | /* The Masonry Brick */ 26 | .item { 27 | width: inherit; 28 | padding: 1em; 29 | /* margin: 0 0 1.5em; */ 30 | box-sizing: content-box; 31 | -webkit-column-break-inside: avoid; 32 | page-break-inside: avoid; 33 | break-inside: avoid; 34 | } 35 | 36 | /* Masonry on large screens */ 37 | @media only screen and (min-width: 1024px) { 38 | .masonry { 39 | column-count: 4; 40 | } 41 | } 42 | 43 | /* Masonry on medium-sized screens */ 44 | @media only screen and (max-width: 1023px) and (min-width: 768px) { 45 | .masonry { 46 | column-count: 3; 47 | } 48 | } 49 | 50 | /* Masonry on small screens */ 51 | @media only screen and (max-width: 767px) and (min-width: 540px) { 52 | .masonry { 53 | column-count: 2; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /views/_error.erb: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /views/_footer.erb: -------------------------------------------------------------------------------- 1 |
2 |

Made with by Syed AbuTalib

3 |
4 | -------------------------------------------------------------------------------- /views/_head.erb: -------------------------------------------------------------------------------- 1 | 2 | Github Stars 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /views/_navbar.erb: -------------------------------------------------------------------------------- 1 | 14 | -------------------------------------------------------------------------------- /views/_searchbar.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |

4 | Search for a user 5 |

6 |
7 | 8 | 9 |
10 |
11 |
12 | -------------------------------------------------------------------------------- /views/card.erb: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 |
<%= repo %> <%= f[0] %>
7 |
8 |

<%= f[1] %>

9 |
10 | <% unless f[4].nil? %> 11 |

12 | <%= dot %> 13 | <%= f[4] %> 14 |

15 | <% end %> 16 |

<%= star %> <%= f[3] %>

17 |

<%= forked %> <%= f[2] %>

18 |
19 |
20 |
21 |
22 |
23 | -------------------------------------------------------------------------------- /views/index.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= erb :_head %> 4 | 5 | <%= erb :_navbar %> 6 | <% if defined? rip %> 7 | <%= erb :_error, locals: { rip: rip } %> 8 | <% end %> 9 | <%= erb :_searchbar %> 10 | <%= erb :_footer %> 11 | 12 | 13 | -------------------------------------------------------------------------------- /views/masonry.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= erb :_head %> 4 | 5 | <%= erb :_navbar %> 6 | <%= erb :_searchbar, locals: { username: username } %> 7 |
8 | <% list.each do |f| %> 9 | <%= erb :card, locals: { repo: repo, dot: dot, 10 | star: star, forked: forked, lc: @lc, f: f } %> 11 | <% end %> 12 |
13 | <%= erb :_footer %> 14 | 15 | 16 | --------------------------------------------------------------------------------