diff --git a/.gitignore b/.gitignore index 1bfa5ea8..7b0bcf92 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ git_stats/ /coverage/ /spec/test_files/images/* + +.fontcustom-manifest.json diff --git a/Gemfile b/Gemfile index 1ab02404..4a2ba23d 100644 --- a/Gemfile +++ b/Gemfile @@ -143,7 +143,6 @@ end group :development do gem 'pry-rails' - gem 'rack-mini-profiler', require: false gem 'binding_of_caller' gem 'reek' gem 'rails_best_practices' @@ -156,6 +155,10 @@ group :development do # Use Hanna Bootstrap theme for RDoc documentation # https://github.com/ngs/hanna-bootstrap gem 'hanna-bootstrap' + + # FontCustom for generating the icon font. + # http://fontcustom.com/ + gem 'fontcustom' end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index 9a214cdc..8791fd00 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -62,9 +62,11 @@ GEM binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) builder (3.2.2) - bullet (4.14.7) + bullet (4.14.9) activesupport (>= 3.0.0) uniform_notifier (~> 1.9.0) + celluloid (0.16.0) + timers (~> 4.0.0) climate_control (0.0.3) activesupport (>= 3.0) cocaine (0.5.7) @@ -106,6 +108,11 @@ GEM railties (>= 3.0.0) faker (1.5.0) i18n (~> 0.5) + ffi (1.9.10) + fontcustom (1.3.8) + json (~> 1.4) + listen (>= 1.0, < 3.0) + thor (~> 0.14) friendly_id (5.1.0) activerecord (>= 4.0.0) globalid (0.3.6) @@ -121,6 +128,7 @@ GEM rake sass hashie (3.4.2) + hitimes (1.2.3) i18n (0.7.0) ice_nine (0.11.1) jbuilder (2.3.2) @@ -135,6 +143,10 @@ GEM turbolinks json (1.8.3) kgio (2.10.0) + listen (2.10.1) + celluloid (~> 0.16.0) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9) loofah (2.0.3) nokogiri (>= 1.5.9) mail (2.6.3) @@ -200,8 +212,6 @@ GEM quiet_assets (1.1.0) railties (>= 3.1, < 5.0) rack (1.6.4) - rack-mini-profiler (0.9.7) - rack (>= 1.1.3) rack-protection (1.5.3) rack rack-test (0.6.3) @@ -247,7 +257,10 @@ GEM rainbow (2.0.0) raindrops (0.15.0) rake (10.4.2) - react-rails (1.3.1) + rb-fsevent (0.9.6) + rb-inotify (0.9.5) + ffi (>= 0.5.0) + react-rails (1.3.2) babel-transpiler (>= 0.7.0) coffee-script-source (~> 1.8) connection_pool @@ -281,7 +294,7 @@ GEM rspec-support (~> 3.3.0) rspec-support (3.3.0) ruby-progressbar (1.7.5) - sass (3.4.18) + sass (3.4.19) sass-rails (5.0.4) railties (>= 4.0.0, < 5.0) sass (~> 3.1) @@ -315,7 +328,7 @@ GEM actionpack (>= 3.0) activesupport (>= 3.0) sprockets (>= 2.8, < 4.0) - sqlite3 (1.3.10) + sqlite3 (1.3.11) thin (1.5.1) daemons (>= 1.0.9) eventmachine (>= 0.12.6) @@ -323,6 +336,8 @@ GEM thor (0.19.1) thread_safe (0.3.5) tilt (2.0.1) + timers (4.0.4) + hitimes train_track (0.3.0) activesupport (>= 4.0.0) turbolinks (2.5.3) @@ -361,6 +376,7 @@ DEPENDENCIES devise factory_girl_rails faker + fontcustom friendly_id (~> 5.1.0) hanna-bootstrap jbuilder (~> 2.0) @@ -377,7 +393,6 @@ DEPENDENCIES pry-rails pundit quiet_assets - rack-mini-profiler rails (= 4.2.4) rails_12factor rails_best_practices diff --git a/README.md b/README.md index 53d03d2c..7f58baa1 100644 --- a/README.md +++ b/README.md @@ -4,17 +4,68 @@ ImageHex [![Codeship Status for connorshea/ImageHex](https://codeship.com/projec [View the Wiki for more information.](https://github.com/connorshea/ImageHex/wiki) -Some things to note: - -1. You MUST install ImageMagick. Easily acomplished through the package manager - of most distros and Homebrew. -2. We use a loose form of TDD. Have tests to ensure that your code works, but, - if it makes sense to write code first and tests later, do that as well. Use - discretion. If you're working here you're smart. -3. Push all changes to a branch specifically for the task assigned to you. - Branch that off the "develop" branch. When it's ready to join the rest of - the codebase (when your task is done), merge back into develop. - When we're ready to push up to Heroku, Anthony or Connor will merge - develop back into master and push it up. -4. Set up the DB according to the config file. -5. Use `rake documentation` to generate the RDoc documentation. +**Notes:** + +* You MUST install ImageMagick. Easily accomplished through the package manager + of most distros and Homebrew. +* We use a loose form of TDD. Have tests to ensure that your code works, but, + if it makes sense to write code first and tests later, do that as well. Use + discretion. If you're working here you're smart. +* Push all changes to a branch specifically for the task assigned to you. + The branch should be based off `develop`. When the feature is complete, + open a Pull Request to merge back into `develop`. When we're ready to + push up to Heroku, Anthony or Connor will merge `develop` back into `master` + and push it up. +* Set up the DB according to the config file. +* Use `rake documentation` to generate the RDoc documentation. + + +### Setting up your Development environment + +This tutorial assumes you have some basic understanding of using the Terminal and Git/GitHub. You don't need to be able to hack the Pentagon, but you should know what `cd` and `ls` do, how to make a branch, and how to submit a pull request on GitHub. + +If you don't, check out [Codecademy's Command Line course](https://www.codecademy.com/courses/learn-the-command-line) and GitHub's [Git tutorial](https://help.github.com/articles/set-up-git/) before getting started. + +Before starting you'll want to set up Two Factor Authentication on your GitHub account, if you haven't already (you shouldn't have access to this repo if you haven't done that, so I have no idea how you're reading this). This is to protect our source code and other data that may be used to compromise user information. + +#### OS X +1. Install the Xcode command-line tools with `xcode-select –install`. This'll be necessary to install Homebrew. +2. Install [Homebrew](http://brew.sh/) with the following command: `ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"`. +3. Install [RVM](https://rvm.io/). +4. Use RVM to install Ruby 2.2.3 (`rvm install ruby-2.2.3`) and then switch to that version of Ruby with `rvm use ruby-2.2.3 --default`. +5. Install [Git](https://git-scm.com/) with `brew install git`, then either use Git from the terminal or [the GitHub Desktop app](https://desktop.github.com/) to pull down the ImageHex repository. +6. Install PostgreSQL 9.4 with `brew install postgresql`. We also recommend using [Postgres.app](http://postgresapp.com/) on OS X to get the Postgres server running after the initial setup. +7. Install [ImageMagick](http://www.imagemagick.org/script/index.php) with `brew install imagemagick`. +8. Install [Bundler](http://bundler.io/) with `gem install bundler`. +9. In the ImageHex directory (wherever you installed the Git repository), run `bundle install` to install all the relevant gems you'll need for developing ImageHex. This might take a bit of time, be patient! +10. Run `rake db:setup` to set up the Postgres development server. +11. If everything has gone right so far, you'll be able to start up a Rails server with `rails s`! +12. Get working! + +You can update packages installed with Homebrew at any time with `brew update` and `brew upgrade`. You'll likely want to do this once a week, just in case there are security issues in anything you've installed. We recommend using Homebrew as much as possible to install development dependencies, as it makes uninstalling and updating things much easier! + +#### Linux +Note: Replace `apt-get install` with your distro's equivalent package manager, this uses `apt-get` for simplicity's sake. + +1. Install [RVM](https://rvm.io/). +2. Use RVM to install Ruby 2.2.3 (`rvm install ruby-2.2.3`) and then switch to that version of Ruby with `rvm use ruby-2.2.3 --default`. +3. Install [Git](https://git-scm.com/) if you need to, then use git from the terminal to pull down the ImageHex repository. +4. Install PostgreSQL 9.4 with `apt-get install postgresql`. +5. Install [ImageMagick](http://www.imagemagick.org/script/index.php) with `apt-get install imagemagick`. +6. Install [Bundler](http://bundler.io/) with `gem install bundler`. +7. In the ImageHex directory (wherever you installed the Git repository), run `bundle install` to install all the relevant gems you'll need for developing ImageHex. This might take a bit of time, be patient! +8. Run `rake db:setup` to set up the Postgres development server. +9. If everything has gone right so far, you'll be able to start up a Rails server with `rails s`! +10. Get working! + + +### How do I generate the icon font after adding a new icon? + +Icon font auto-generation technique courtesy of Scott Nelson's post [here](http://thisbythem.com/blog/rails-custom-font-icons/). + +1. Assuming you have Homebrew installed on OS X, run `brew install fontforge ttfautohint` from the terminal. + * If you want to install the prerequisites to FontCustom using other means, you can see the installation instructions in the [FontCustom README](https://github.com/FontCustom/fontcustom/#installation). +2. Add icons as `.svg` files to `app/assets/icons`. +3. From the terminal, in the base ImageHex directory, run `rake icons:compile`. +4. The new icon font should be generated and immediately useable, you can add the new icon to the site by using the auto-generated CSS classes. For example, if we take an SVG named `heart.svg`, the css class will be `icon-heart`. + diff --git a/app/assets/fonts/imagehexicons.eot b/app/assets/fonts/imagehexicons.eot new file mode 100644 index 00000000..d0371f1f Binary files /dev/null and b/app/assets/fonts/imagehexicons.eot differ diff --git a/app/assets/fonts/imagehexicons.svg b/app/assets/fonts/imagehexicons.svg new file mode 100644 index 00000000..d82e0526 --- /dev/null +++ b/app/assets/fonts/imagehexicons.svg @@ -0,0 +1,130 @@ + + + + diff --git a/app/assets/fonts/imagehexicons.ttf b/app/assets/fonts/imagehexicons.ttf new file mode 100644 index 00000000..47ba9b36 Binary files /dev/null and b/app/assets/fonts/imagehexicons.ttf differ diff --git a/app/assets/fonts/imagehexicons.woff b/app/assets/fonts/imagehexicons.woff new file mode 100644 index 00000000..4945804d Binary files /dev/null and b/app/assets/fonts/imagehexicons.woff differ diff --git a/app/assets/icons/checkmark.svg b/app/assets/icons/checkmark.svg new file mode 100644 index 00000000..b1bef055 --- /dev/null +++ b/app/assets/icons/checkmark.svg @@ -0,0 +1,7 @@ + + + + diff --git a/app/assets/icons/close.svg b/app/assets/icons/close.svg new file mode 100644 index 00000000..13bad232 --- /dev/null +++ b/app/assets/icons/close.svg @@ -0,0 +1,10 @@ + + + + diff --git a/app/assets/icons/collection.svg b/app/assets/icons/collection.svg new file mode 100644 index 00000000..374058af --- /dev/null +++ b/app/assets/icons/collection.svg @@ -0,0 +1,9 @@ + + + + diff --git a/app/assets/icons/danger.svg b/app/assets/icons/danger.svg new file mode 100644 index 00000000..7f0b4459 --- /dev/null +++ b/app/assets/icons/danger.svg @@ -0,0 +1,8 @@ + + + + diff --git a/app/assets/icons/download.svg b/app/assets/icons/download.svg new file mode 100644 index 00000000..db7a7538 --- /dev/null +++ b/app/assets/icons/download.svg @@ -0,0 +1,8 @@ + + + + diff --git a/app/assets/icons/dropdown.svg b/app/assets/icons/dropdown.svg new file mode 100644 index 00000000..db8c0868 --- /dev/null +++ b/app/assets/icons/dropdown.svg @@ -0,0 +1,7 @@ + + + + diff --git a/app/assets/icons/edit.svg b/app/assets/icons/edit.svg new file mode 100644 index 00000000..407dbaf7 --- /dev/null +++ b/app/assets/icons/edit.svg @@ -0,0 +1,8 @@ + + + + diff --git a/app/assets/icons/facebook.svg b/app/assets/icons/facebook.svg new file mode 100644 index 00000000..c06f7a4f --- /dev/null +++ b/app/assets/icons/facebook.svg @@ -0,0 +1,8 @@ + + + + diff --git a/app/assets/icons/flag.svg b/app/assets/icons/flag.svg new file mode 100644 index 00000000..ed0a4261 --- /dev/null +++ b/app/assets/icons/flag.svg @@ -0,0 +1,10 @@ + + + + diff --git a/app/assets/icons/folder.svg b/app/assets/icons/folder.svg new file mode 100644 index 00000000..6ff16b16 --- /dev/null +++ b/app/assets/icons/folder.svg @@ -0,0 +1,12 @@ + + + + diff --git a/app/assets/icons/google-plus.svg b/app/assets/icons/google-plus.svg new file mode 100644 index 00000000..9b1d3979 --- /dev/null +++ b/app/assets/icons/google-plus.svg @@ -0,0 +1,14 @@ + + + + diff --git a/app/assets/icons/heart-fill.svg b/app/assets/icons/heart-fill.svg new file mode 100644 index 00000000..19821221 --- /dev/null +++ b/app/assets/icons/heart-fill.svg @@ -0,0 +1,8 @@ + + + + diff --git a/app/assets/icons/heart-outline.svg b/app/assets/icons/heart-outline.svg new file mode 100644 index 00000000..7c0ca520 --- /dev/null +++ b/app/assets/icons/heart-outline.svg @@ -0,0 +1,12 @@ + + + + diff --git a/app/assets/icons/help.svg b/app/assets/icons/help.svg new file mode 100644 index 00000000..545d327f --- /dev/null +++ b/app/assets/icons/help.svg @@ -0,0 +1,18 @@ + + + + diff --git a/app/assets/icons/history.svg b/app/assets/icons/history.svg new file mode 100644 index 00000000..163a3337 --- /dev/null +++ b/app/assets/icons/history.svg @@ -0,0 +1,8 @@ + + + + diff --git a/app/assets/icons/info.svg b/app/assets/icons/info.svg new file mode 100644 index 00000000..1d2be65c --- /dev/null +++ b/app/assets/icons/info.svg @@ -0,0 +1,8 @@ + + + + diff --git a/app/assets/icons/location.svg b/app/assets/icons/location.svg new file mode 100644 index 00000000..69b993b5 --- /dev/null +++ b/app/assets/icons/location.svg @@ -0,0 +1,9 @@ + + + + diff --git a/app/assets/icons/menu.svg b/app/assets/icons/menu.svg new file mode 100644 index 00000000..e60a9941 --- /dev/null +++ b/app/assets/icons/menu.svg @@ -0,0 +1,12 @@ + + + + diff --git a/app/assets/icons/pinterest.svg b/app/assets/icons/pinterest.svg new file mode 100644 index 00000000..a150bbba --- /dev/null +++ b/app/assets/icons/pinterest.svg @@ -0,0 +1,13 @@ + + + + diff --git a/app/assets/icons/plus.svg b/app/assets/icons/plus.svg new file mode 100644 index 00000000..bf3fcd27 --- /dev/null +++ b/app/assets/icons/plus.svg @@ -0,0 +1,7 @@ + + + + diff --git a/app/assets/icons/quote.svg b/app/assets/icons/quote.svg new file mode 100644 index 00000000..e642ab86 --- /dev/null +++ b/app/assets/icons/quote.svg @@ -0,0 +1,14 @@ + + + + diff --git a/app/assets/icons/search.svg b/app/assets/icons/search.svg new file mode 100644 index 00000000..46e22bbd --- /dev/null +++ b/app/assets/icons/search.svg @@ -0,0 +1,11 @@ + + + + diff --git a/app/assets/icons/share.svg b/app/assets/icons/share.svg new file mode 100644 index 00000000..ecccfcc5 --- /dev/null +++ b/app/assets/icons/share.svg @@ -0,0 +1,11 @@ + + + + diff --git a/app/assets/icons/templates/_imagehexicons.scss b/app/assets/icons/templates/_imagehexicons.scss new file mode 100644 index 00000000..5fc08955 --- /dev/null +++ b/app/assets/icons/templates/_imagehexicons.scss @@ -0,0 +1,9 @@ +// +// Icon Font: <%= font_name %> +// + +<%= font_face(url: "font-url", path: @font_path_alt) %> + +<%= glyphs %> +<% @glyphs.each do |name, value| %> +$icon-<%= name.to_s %>: "\<%= value[:codepoint].to_s(16) %>";<% end %> diff --git a/app/assets/icons/trash.svg b/app/assets/icons/trash.svg new file mode 100644 index 00000000..990ced81 --- /dev/null +++ b/app/assets/icons/trash.svg @@ -0,0 +1,12 @@ + + + + diff --git a/app/assets/icons/tumblr.svg b/app/assets/icons/tumblr.svg new file mode 100644 index 00000000..60f9be13 --- /dev/null +++ b/app/assets/icons/tumblr.svg @@ -0,0 +1,11 @@ + + + + diff --git a/app/assets/icons/tv.svg b/app/assets/icons/tv.svg new file mode 100644 index 00000000..dfddafcd --- /dev/null +++ b/app/assets/icons/tv.svg @@ -0,0 +1,8 @@ + + + + diff --git a/app/assets/icons/twitter.svg b/app/assets/icons/twitter.svg new file mode 100644 index 00000000..7ce05fd6 --- /dev/null +++ b/app/assets/icons/twitter.svg @@ -0,0 +1,12 @@ + + + + diff --git a/app/assets/icons/upload.svg b/app/assets/icons/upload.svg new file mode 100644 index 00000000..b33b1ff2 --- /dev/null +++ b/app/assets/icons/upload.svg @@ -0,0 +1,10 @@ + + + + diff --git a/app/assets/icons/warning.svg b/app/assets/icons/warning.svg new file mode 100644 index 00000000..2a542dbe --- /dev/null +++ b/app/assets/icons/warning.svg @@ -0,0 +1,8 @@ + + + + diff --git a/app/assets/javascripts/settings.js b/app/assets/javascripts/settings.js new file mode 100644 index 00000000..569b2f42 --- /dev/null +++ b/app/assets/javascripts/settings.js @@ -0,0 +1,27 @@ +function avatarUploader() { + $("#avatar-uploader").on("change", avatarUploaderPreview); +} + + +function avatarUploaderPreview(event) { + var files = event.target.files || (event.originalEvent.dataTransfer && event.originalEvent.dataTransfer.files); + + console.log(files); + + if (files) { + var img = document.createElement("img"); + img.src = window.URL.createObjectURL(files[0]); + img.width = 150; + img.onload = function() { + window.URL.revokeObjectURL(this.src); + }; + + $("#avatar-uploader-thumbnail-container").html(img); + } +} + +var ready = function() { + avatarUploader(); +}; + +$(document).ready(ready); diff --git a/app/assets/stylesheets/_imagehexicons.scss b/app/assets/stylesheets/_imagehexicons.scss new file mode 100644 index 00000000..11e85dfe --- /dev/null +++ b/app/assets/stylesheets/_imagehexicons.scss @@ -0,0 +1,81 @@ +// +// Icon Font: imagehexicons +// + +@font-face { + font-family: "imagehexicons"; + src: font-url("imagehexicons.eot"); + src: font-url("imagehexicons.eot?#iefix") format("embedded-opentype"), + font-url("imagehexicons.woff") format("woff"), + font-url("imagehexicons.ttf") format("truetype"), + font-url("imagehexicons.svg#imagehexicons") format("svg"); + font-weight: normal; + font-style: normal; +} + +@media screen and (-webkit-min-device-pixel-ratio:0) { + @font-face { + font-family: "imagehexicons"; + src: font-url("imagehexicons.svg#imagehexicons") format("svg"); + } +} + +.icon-checkmark:before { content: "\f100"; } +.icon-close:before { content: "\f101"; } +.icon-collection:before { content: "\f102"; } +.icon-danger:before { content: "\f103"; } +.icon-download:before { content: "\f104"; } +.icon-dropdown:before { content: "\f105"; } +.icon-edit:before { content: "\f11d"; } +.icon-facebook:before { content: "\f106"; } +.icon-flag:before { content: "\f107"; } +.icon-folder:before { content: "\f108"; } +.icon-google-plus:before { content: "\f11c"; } +.icon-heart-fill:before { content: "\f10a"; } +.icon-heart-outline:before { content: "\f10b"; } +.icon-help:before { content: "\f10c"; } +.icon-history:before { content: "\f10d"; } +.icon-info:before { content: "\f10e"; } +.icon-location:before { content: "\f10f"; } +.icon-menu:before { content: "\f110"; } +.icon-pinterest:before { content: "\f111"; } +.icon-plus:before { content: "\f112"; } +.icon-quote:before { content: "\f113"; } +.icon-search:before { content: "\f114"; } +.icon-share:before { content: "\f115"; } +.icon-trash:before { content: "\f116"; } +.icon-tumblr:before { content: "\f117"; } +.icon-tv:before { content: "\f118"; } +.icon-twitter:before { content: "\f119"; } +.icon-upload:before { content: "\f11a"; } +.icon-warning:before { content: "\f11b"; } + +$icon-checkmark: "\f100"; +$icon-close: "\f101"; +$icon-collection: "\f102"; +$icon-danger: "\f103"; +$icon-download: "\f104"; +$icon-dropdown: "\f105"; +$icon-edit: "\f11d"; +$icon-facebook: "\f106"; +$icon-flag: "\f107"; +$icon-folder: "\f108"; +$icon-google-plus: "\f11c"; +$icon-heart-fill: "\f10a"; +$icon-heart-outline: "\f10b"; +$icon-help: "\f10c"; +$icon-history: "\f10d"; +$icon-info: "\f10e"; +$icon-location: "\f10f"; +$icon-menu: "\f110"; +$icon-pinterest: "\f111"; +$icon-plus: "\f112"; +$icon-quote: "\f113"; +$icon-search: "\f114"; +$icon-share: "\f115"; +$icon-trash: "\f116"; +$icon-tumblr: "\f117"; +$icon-tv: "\f118"; +$icon-twitter: "\f119"; +$icon-upload: "\f11a"; +$icon-warning: "\f11b"; diff --git a/app/assets/stylesheets/_scss-variables.scss b/app/assets/stylesheets/_scss-variables.scss index fd0afc51..4ecf5675 100644 --- a/app/assets/stylesheets/_scss-variables.scss +++ b/app/assets/stylesheets/_scss-variables.scss @@ -1,32 +1,5 @@ -// Icons -$icon-search: '\e800'; -$icon-favorite: '\e801'; -$icon-favorited: '\e802'; -$icon-add: '\e803'; -$icon-report: '\e804'; -$icon-share: '\e805'; -$icon-warning: '\e806'; -$icon-danger: '\e807'; -$icon-checkmark: '\e808'; -$icon-info: '\e809'; -$icon-close: '\e80a'; -$icon-location: '\e80b'; -$icon-transcript: '\e80c'; -$icon-source: '\e80d'; -$icon-delete: '\e80e'; -$icon-dropdown: '\e80f'; -$icon-folder: '\e810'; -$icon-collection: '\e811'; -$icon-upload: '\e812'; -$icon-history: '\e813'; -$icon-help: '\e814'; -$icon-menu: '\e815'; -$icon-download: '\e816'; -$icon-facebook: '\e817'; -$icon-twitter: '\e818'; -$icon-google-plus: '\e819'; -$icon-tumblr: '\e81a'; -$icon-pinterest: '\e81b'; +// Imports "icons" file generated by our icon font autogeneration script +@import "imagehexicons"; $icon-placeholder: '\e80c'; @@ -40,7 +13,7 @@ $emph-text: #828282; // Emphasized text $unemph-text: #6d6d6d; // Unemphasized text // Font stack -$font-stack: 'Helvetica Neue', Helvetica, Arial, sans-serif, 'imagehexiconfont'; +$font-stack: 'Helvetica Neue', Helvetica, Arial, sans-serif, 'imagehexicons'; // Error colors $color-success: #5bb289; diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index e1638f39..0d25e297 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -23,18 +23,9 @@ box-sizing: border-box; } -/* Defines the icon font. */ -@font-face { - font-family: 'imagehexiconfont'; - src: font-url('imagehexiconfont.eot'); - src: font-url('imagehexiconfont.ttf') format("truetype"); - font-weight: normal; - font-style: normal; -} - /* Styles applicable to all pages. */ html, body { - font: 400 10px 'Helvetica Neue', Helvetica, Arial, sans-serif, 'imagehexiconfont'; + font: 400 10px $font-stack; background-color: #f0f0f0; margin: 0; overflow-x: hidden; @@ -115,12 +106,12 @@ input[type="email"] { input, textarea { - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif, 'imagehexiconfont'; + font-family: $font-stack; } /* Fix for WebKit input text style. */ input, textarea, keygen, select, button { - font: 400 inherit 'Helvetica Neue', Helvetica, Arial, sans-serif, 'imagehexiconfont'; + font: 400 inherit $font-stack; } // Fix Firefox's ugly default select styling. diff --git a/app/assets/stylesheets/generic.scss b/app/assets/stylesheets/generic.scss index 3aa0a133..ecc3f413 100644 --- a/app/assets/stylesheets/generic.scss +++ b/app/assets/stylesheets/generic.scss @@ -1,5 +1,10 @@ @import "scss-variables"; +.imagehex-empty-note-container { + width: 100%; + display: block; +} + .imagehex-empty-note { display: inline-block; margin: auto; diff --git a/app/assets/stylesheets/icons.scss b/app/assets/stylesheets/icons.scss index 6dc54f52..15654887 100644 --- a/app/assets/stylesheets/icons.scss +++ b/app/assets/stylesheets/icons.scss @@ -8,6 +8,26 @@ font-family: $font-stack; } +[data-icon]:before { content: attr(data-icon); } + +[data-icon]:before, +.icon { + font-family: "imagehexicons"; + font-style: normal; + font-weight: normal; + font-size: 1.4rem; + font-variant: normal; + text-decoration: inherit; + text-rendering: optimizeLegibility; + text-transform: none; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + font-smoothing: antialiased; +} + // Home icon .icon-home:before { content: $icon-placeholder; @@ -33,15 +53,15 @@ } .icon-favorite:before { - content: $icon-favorite; + content: $icon-heart-outline; } .icon-favorited:before { - content: $icon-favorited; + content: $icon-heart-fill; } .icon-add:before { - content: $icon-add; + content: $icon-plus; } .icon-share:before { @@ -49,11 +69,11 @@ } .icon-report:before { - content: $icon-report; + content: $icon-flag; } .icon-delete:before { - content: $icon-delete; + content: $icon-trash; } .icon-checkmark:before { diff --git a/app/assets/stylesheets/images.scss b/app/assets/stylesheets/images.scss index fbe5ab60..71b8ffe5 100644 --- a/app/assets/stylesheets/images.scss +++ b/app/assets/stylesheets/images.scss @@ -1,4 +1,5 @@ @import "scss-variables"; +@import "imagehexicons"; /* Padding for images in image pages. */ /* Adding properties to this can have unintended consequences effecting all images across the site. */ @@ -108,7 +109,7 @@ display: inline-block; &:before { - content: $icon-add; + content: $icon-plus; position: absolute; display: inline-block; @include translate(-24px,-2px); diff --git a/app/assets/stylesheets/settings.scss b/app/assets/stylesheets/settings.scss index d8ade0f9..8f0d2acf 100644 --- a/app/assets/stylesheets/settings.scss +++ b/app/assets/stylesheets/settings.scss @@ -1,2 +1,29 @@ @import "scss-variables"; +#avatar-uploader-thumbnail-container { + width: 150px; + height: 150px; + overflow: hidden; + position: relative; + margin-bottom: 10px; + + img { + object-fit: cover; + width: 150px; + height: 150px; + pointer-events: none; + } +} + +#avatar-uploader { + position: absolute; + // Compensate for the 25px padding in the field-container element. + top: 25px; + left: 0; + display: inline; + width: 2px; + height: 2px; + padding: 75px; + opacity: 0; + cursor: pointer; +} diff --git a/app/assets/stylesheets/tag-group.scss b/app/assets/stylesheets/tag-group.scss index 5b16503e..2a340293 100644 --- a/app/assets/stylesheets/tag-group.scss +++ b/app/assets/stylesheets/tag-group.scss @@ -70,7 +70,7 @@ right: 15px; &:before { - content: $icon-placeholder; + content: $icon-edit; display: inline-block; font-size: 1.9rem; } diff --git a/app/assets/stylesheets/users.scss b/app/assets/stylesheets/users.scss index c7255d47..57a0a162 100644 --- a/app/assets/stylesheets/users.scss +++ b/app/assets/stylesheets/users.scss @@ -87,8 +87,7 @@ pointer-events: none; img { - min-width: 120px; - min-height: 120px; + width: 100%; } @media all and (max-device-width: $mobile-width) { @@ -99,8 +98,7 @@ -webkit-flex-shrink: 0; img { - min-width: 75px; - min-height: 75px; + width: 100%; } } } diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f4d7f68c..10e59e3e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -2,11 +2,6 @@ # The root application controller for Imagehex. # Any functionality we have to access from all controllers goes here. class ApplicationController < ActionController::Base - - def unauthorized - flash[:error] = "You aren't allowed to do that" - redirect_to (request.referer || root_path) - end # Adds different "flash[:type]" types. add_flash_types :warning, :info before_action :set_locale @@ -14,7 +9,15 @@ def unauthorized # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception before_action :configure_devise_permitted_parameters, if: :devise_controller? + + def unauthorized + respond_to do |format| + format.html { redirect_to (request.referer || root_path), warning: I18n.t(".notices.youre_not_allowed_to_do_that") } + end + end + protected + ## # Ensure that a user is logged in. # If one is not, redirect to a page where they can do that. @@ -54,7 +57,7 @@ def per_page # Add a query string for the Locale if needed. def default_url_options(options = {}) return options if I18n.locale == I18n.default_locale - { locale: I18n.locale}.merge options + { locale: I18n.locale }.merge options end ## # Allow devise to add a user's name on creation. @@ -65,9 +68,11 @@ def configure_devise_permitted_parameters DEFAULT_CONTENT = { "nsfw_language" => true } + def content_pref return (params["content_filter"] || current_user.try(:content_pref) or DEFAULT_CONTENT) end + ## # Set the locale. # Locales are either in the URL, or the default (English). diff --git a/app/controllers/collection_images_controller.rb b/app/controllers/collection_images_controller.rb index 31ba6533..2463f2ff 100644 --- a/app/controllers/collection_images_controller.rb +++ b/app/controllers/collection_images_controller.rb @@ -20,8 +20,8 @@ def create authorize c if c.save respond_to do |format| - format.html{redirect_to(request.referrer || root_path)} - format.json{render json: {successful: true}} + format.html { redirect_to(request.referrer || root_path) } + format.json { render json: { successful: true } } end else flash[:warning] = c.errors.full_messages diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb index c00b147e..135e7149 100644 --- a/app/controllers/collections_controller.rb +++ b/app/controllers/collections_controller.rb @@ -75,14 +75,15 @@ def create c = Subjective.new(collection_params) end unless c - flash[:warning] = "Collection type not specified or not applicable." + flash[:warning] = I18n.t(".notices.collection_type_not_specified_or_not_applicable") redirect_to action: "new" and return end - if c.save - redirect_to collection_path(id: c.id) and return - else - flash[:warning] = c.errors.full_messages.join(", ") - redirect_to action: "new" + respond_to do |format| + if c.save + format.html { redirect_to collection_path(id: c.id), notice: I18n.t(".collecton_created_successfully") } + else + format.html { redirect_to new_collection_path, warning: c.errors.full_messages.join(", ") } + end end end diff --git a/app/controllers/frontpage_controller.rb b/app/controllers/frontpage_controller.rb index 95c25b44..b8941ef7 100644 --- a/app/controllers/frontpage_controller.rb +++ b/app/controllers/frontpage_controller.rb @@ -9,7 +9,8 @@ class FrontpageController < ApplicationController def index if current_user puts current_user.image_feed.class - @images = current_user.image_feed.paginate(page: page, per_page: per_page) + @images = current_user.image_feed + .paginate(page: page, per_page: per_page) render "index_with_user" else @images = Image diff --git a/app/controllers/images_controller.rb b/app/controllers/images_controller.rb index d024e618..4ed50954 100644 --- a/app/controllers/images_controller.rb +++ b/app/controllers/images_controller.rb @@ -8,16 +8,6 @@ class ImagesController < ApplicationController before_action :load_image, only: [:comment, :favorite, :created, :update, :edit, :destroy, :show] # Ensure a user is logged in. Defined in the application controller before_action :ensure_user, only: [:unfavorite, :favorite, :created, :new, :create, :update, :edit, :destroy, :report, :comment] - ## - # Remove an image from the current users' favorites. - # The image's id must be in params[:id]. The request must be a DELETE. - # The user must be logged in. - def unfavorite - col = current_user.favorites - image = Image.find(params[:id]) - result = col.images.delete(image) - render json: result - end ## # Create a new comment on the image in params[:id] @@ -26,13 +16,15 @@ def unfavorite # User must be logged in. def comment @comment = Comment.new(comment_params) - if @comment.save - redirect_to @image - else - flash[:errors] = @comment.errors.full_messages - redirect_to @image + respond_to do |format| + if @comment.save + format.html { redirect_to @image, notice: I18n.t(".notices.your_comment_was_submitted_successfully") } + else + format.html { redirect_to @image, warning: @comment.errors.full_messages.join(', ') } + end end end + ## # The current user adds the image to his "Created" collection, # which means he or she was involved in the creation of the image. @@ -50,6 +42,17 @@ def favorite redirect_to(@image) end + ## + # Remove an image from the current users' favorites. + # The image's id must be in params[:id]. The request must be a DELETE. + # The user must be logged in. + def unfavorite + col = current_user.favorites + image = Image.find(params[:id]) + result = col.images.delete(image) + render json: result + end + ## # Find images via the Image#search method. # Query should be in params[:query]. @@ -59,7 +62,7 @@ def search .for_content(content_pref) respond_to do |format| format.html - format.json{render 'index'} + format.json { render 'index' } end end @@ -79,11 +82,13 @@ def report @image = Image.find(params[:id]) @report = Report.new(report_params) @report.reportable = @image - if @report.save - redirect_to @image - else - flash[:error] = @report.errors.full_messages.join(", ") - redirect_to @image + + respond_to do |format| + if @report.save + format.html { redirect_to @image, notice: I18n.t(".notices.report_submitted_thank_you") } + else + format.html { redirect_to @image, warning: @report.errors.full_messages.join(", ") } + end end end @@ -94,12 +99,14 @@ def report # flash[:warning] def create @image = Image.new(image_params) - if @image.save - redirect_to @image - else - # If their image is incorrect, redirect_to the new page again. - flash[:warning] = @image.errors.full_messages.join(', ') - redirect_to action: :new + respond_to do |format| + if @image.save + format.html { redirect_to @image, notice: I18n.t(".notices.image_uploaded_successfully") } + format.json { render :show } + else + # If their image is incorrect, redirect_to the new page again. + format.html { redirect_to new_image_path, warning: @image.errors.full_messages.join(', ') } + end end end @@ -159,6 +166,7 @@ def image_update_params :replies_to_inbox, :description) end + ## # Protected parameters for the image. # @@ -176,7 +184,6 @@ def image_params .merge(user_id: current_user.id) # We add the user id end - ## # Parameters for our report def report_params diff --git a/app/controllers/static_stuff_controller.rb b/app/controllers/static_stuff_controller.rb index b8bb19c8..6f92301c 100644 --- a/app/controllers/static_stuff_controller.rb +++ b/app/controllers/static_stuff_controller.rb @@ -4,14 +4,17 @@ # At some point we should replace this with an NGINX thing or something. class StaticStuffController < ApplicationController ## - # About page. Info about the company you work at. + # About page. Information about what ImageHex is. def about end + ## + # Rules for posting on ImageHex. def rules end + ## - # People page. Info on your co-workers, and yourself. + # People page. Info on persons who have helped develop ImageHex. def people end @@ -20,6 +23,18 @@ def people def contact end + ## + # Frequently Asked Questions def faq end + + ## + # The Help section. + def help + end + + ## + # Press resources and whatnot. + def press + end end diff --git a/app/controllers/tag_groups_controller.rb b/app/controllers/tag_groups_controller.rb index 09a3764f..11395919 100644 --- a/app/controllers/tag_groups_controller.rb +++ b/app/controllers/tag_groups_controller.rb @@ -5,6 +5,7 @@ class TagGroupsController < ApplicationController before_filter :ensure_user, except: :show before_filter :get_image include TrainTrack + ## # Create a new TagGroup. # Sets: @@ -21,12 +22,13 @@ def new # TODO: make this redirect to the new action def create @tag_group = TagGroup.create(tag_group_params) - if @tag_group.save - track @tag_group - redirect_to @image - else - flash[:errors] = @tag_group.errors - render 'new' + respond_to do |format| + if @tag_group.save + track @tag_group + format.html { redirect_to @image, notice: I18n.t(".notices.tag_group_added") } + else + format.html { redirect_to @image, warning: @tag_group.errors.full_messages.join(', ') } + end end end @@ -40,18 +42,21 @@ def edit ## # PUT to update a TagGroup. # On success, redirects to the image. - # On failure, renders the edit action again. + # On failure, redirects to the image and displays errors. def update @tag_group = TagGroup.find(params[:id]) track @tag_group - if @tag_group.update(tag_group_params) - track @tag_group - redirect_to @image - else - flash[:errors] = @tag_group.errors - render 'edit' + + respond_to do |format| + if @tag_group.update(tag_group_params) + track @tag_group + format.html { redirect_to @image, notice: I18n.t(".notices.tag_group_updated") } + else + format.html { redirect_to @image, warning: @tag_group.errors.full_messages.join(', ') } + end end end + protected ## # Parameters to make a tag group. @@ -62,6 +67,7 @@ def tag_group_params .permit(:tag_group_string) .merge(image_id: params[:image_id]) # Add in the image id automatically end + ## # Sets the image on every action. def get_image diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index e3823d9c..198429a9 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -43,11 +43,12 @@ def edit # redirects to the edit page again. def update return unless current_user == User.friendly.find(params[:id]) - if current_user.update(user_params) - redirect_to current_user - else - flash[:error] = current_user.errors.full_messages.join(",") - redirect_to edit_user_path(current_user) + respond_to do |format| + if current_user.update(user_params) + format.html { redirect_to current_user, notice: I18n.t(".notices.changes_have_been_saved") } + else + format.html { redirect_to edit_user_path(current_user), warning: current_user.errors.full_messages.join(",") } + end end end @@ -55,16 +56,14 @@ def update ## # Parameters to update a user. # page_pref:: The amount of images per page. - # avatar_id:: The ID of the users's avatar. Getting refactored out at some - # point in order to allow users to add avatars that aren't - # on ImageHex. + # avatar:: The user's avatar image. # user_page_attributes:: Should have a body attribute, which is the user's # Bio. def user_params params .require(:user) .permit(:page_pref, - :avatar_id, + :avatar, user_page_attributes: [:body], content_pref: [:nsfw_language, :nsfw_gore, diff --git a/app/models/collection.rb b/app/models/collection.rb index becb4603..4d3692c7 100644 --- a/app/models/collection.rb +++ b/app/models/collection.rb @@ -45,9 +45,10 @@ class Collection < ActiveRecord::Base scope :favorites, ->{ where(type: "Favorite") } scope :creations, ->{ where(type: "Creation") } scope :subjective, -> { where(type: "Subjective") } - ##################### - # INSTANCE METHODS # - ##################### + + #################### + # INSTANCE METHODS # + #################### ## # Does a user curate this collection? diff --git a/app/models/image.rb b/app/models/image.rb index 4f677bb1..1a484e35 100644 --- a/app/models/image.rb +++ b/app/models/image.rb @@ -78,8 +78,12 @@ class Image < ActiveRecord::Base validates :nsfw_gore, inclusion: {in: [true, false]} validates :nsfw_sexuality, inclusion: {in: [true, false]} validates :nsfw_nudity, inclusion: {in: [true, false]} - validates_attachment_content_type :f, content_type: /\Aimage\/.*\Z/ - validates_attachment_presence :f + validates_attachment :f, + content_type: { content_type: /\Aimage\/.*\Z/}, + size: { in: 0..5.megabytes}, + presence: true + + validates :user, presence: :true validates :license, presence: true validates :medium, presence: true diff --git a/app/models/user.rb b/app/models/user.rb index 84a5fb17..1d1e8add 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -24,19 +24,35 @@ class User < ActiveRecord::Base friendly_id :name, use: :slugged enum role: [:normal, :admin] + ################ # ASSOCIATIONS # ################ has_one :user_page, autosave: true + # Accept nested attributes for the page accepts_nested_attributes_for :user_page, update_only: true - ## - # ID of the avatar is in avatar_id. - belongs_to :avatar, class_name: "Image" - ## - # Join table: users -> collections - has_many :subscriptions + has_attached_file :avatar, + styles: { + original: "500x500>#", + medium: "300x300>#", + small: "200x200>#", + tiny: "100x100>#" + }, + path: ($AVATAR_PATH ? $AVATAR_PATH : "avatars/:id_:style.:extension") + + + validates_attachment_content_type :avatar, + content_type: /\Aimage\/.*\Z/ + + validates_with AttachmentSizeValidator, + attributes: :avatar, + less_than: 2.megabytes + + ## + # Join table: users -> collections + has_many :subscriptions has_many :comments has_many :subscribed_collections, through: :subscriptions, @@ -61,6 +77,7 @@ class User < ActiveRecord::Base length: {in: 2..25} validates :page_pref, inclusion: {:in => (1..100)} validates_associated :user_page + ############# # CALLBACKS # ############# @@ -70,10 +87,12 @@ class User < ActiveRecord::Base after_initialize :load_page_body before_save :coerce_content_pref! + ############## # ATTRIBUTES # ############## attr_accessor :page_body + #################### # INSTANCE METHODS # #################### @@ -90,13 +109,13 @@ def subscribed_to? c ## # Quickly get a user avatar, pre-resized def avatar_img - avatar.f(:medium) + avatar.url(:medium) end ## # Get a user's avatar thumbnail, pre-resized def avatar_img_thumb - avatar.f(:small) + avatar.url(:tiny) end ## @@ -110,11 +129,13 @@ def image_feed def subscribe! c c.subscribers << self end + ## # Convenience method to access the favorites collection for a user def favorites collections.favorites.first end + ## # Add an image to a user's favorites def favorite! i @@ -163,6 +184,7 @@ def coerce_content_pref! end end.to_h end + ## # Put the user's page body into page_body. # This makes it a bit easier, since you can just say diff --git a/app/models/user_page.rb b/app/models/user_page.rb index 7b651963..e0155696 100644 --- a/app/models/user_page.rb +++ b/app/models/user_page.rb @@ -10,8 +10,11 @@ class UserPage < ActiveRecord::Base ############### validates :user, presence: true validate :elsewhere_has_valid_keys + def elsewhere_has_valid_keys - errors.add(:elsewhere, "must be a has") unless self.elsewhere.is_a? Hash + unless self.elsewhere.is_a? Hash + errors.add(:elsewhere, "must be a has") and return + end unless elsewhere.keys - ALLOWED_ELSEWHERE_KEYS == [] errors.add(:elsewhere, "Elsewhere has weird data") end @@ -19,7 +22,7 @@ def elsewhere_has_valid_keys ## # Allowed keys for Elsewhere - # + # ALLOWED_ELSEWHERE_KEYS = [ "tumblr", "facebook", diff --git a/app/views/images/search.html.erb b/app/views/images/search.html.erb index 3fe0a1d2..d36b8e70 100644 --- a/app/views/images/search.html.erb +++ b/app/views/images/search.html.erb @@ -4,7 +4,7 @@
<%= t(".your_search_didnt_bring_up_any_results") %>
+