diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index e74fbf93601..53168b09624 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,7 +1,7 @@ # See here for image contents: https://github.com/microsoft/vscode-dev-containers/blob/v0.205.1/containers/ruby/.devcontainer/base.Dockerfile # [Choice] Ruby version (use -bullseye variants on local arm64/Apple Silicon): 3, 3.0, 2, 2.7, 2.6, 3-bullseye, 3.0-bullseye, 2-bullseye, 2.7-bullseye, 2.6-bullseye, 3-buster, 3.0-buster, 2-buster, 2.7-buster, 2.6-buster -ARG VARIANT=2.7-bullseye +ARG VARIANT=3.1-bullseye FROM mcr.microsoft.com/vscode/devcontainers/ruby:${VARIANT} # [Choice] Node.js version: none, lts/*, 16, 14, 12, 10 diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 9bedfdfe3a6..d3c437c1242 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -15,7 +15,6 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: 2.7.4 bundler-cache: true - name: Set up Node.js diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 97bba97377f..2cea4f92e1d 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,7 +44,6 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: 2.7.4 bundler-cache: true # runs 'bundle install' and caches installed gems automatically - name: Set up Node.js diff --git a/.ruby-version b/.ruby-version index a4dd9dba4fb..fd2a01863fd 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -2.7.4 +3.1.0 diff --git a/Dockerfile b/Dockerfile index 56ae30d2997..e2b6f601da7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:2.7.4-alpine +FROM ruby:3.1.0-alpine ENV RAILS_ENV production WORKDIR /app @@ -6,7 +6,7 @@ WORKDIR /app # Update rubygems RUN gem update --system RUN printf "install: --no-rdoc --no-ri\nupdate: --no-rdoc --no-ri" > ~/.gemrc -RUN gem install --no-document --force bundler -v 2.2.24 +RUN gem install --no-document --force bundler -v 2.3.6 RUN bundle config set without development:test # Install packages diff --git a/Gemfile b/Gemfile index 2f72565176d..3236bc9cfcf 100644 --- a/Gemfile +++ b/Gemfile @@ -3,13 +3,12 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } -ruby '2.7.4' +ruby '3.1.0' gem 'bootsnap', '>= 1.4.4', require: false -gem 'date', '>= 3.2.1' # CVE-2021-41817対応 gem 'image_processing', '~> 1.2' gem 'jbuilder', '~> 2.7' -gem 'puma', '~> 5.5' +gem 'puma', '~> 5.6' gem 'rails', '~> 6.1.4.4' gem 'sass-rails', '>= 6' gem 'webpacker', '~> 5.0' @@ -19,10 +18,10 @@ gem 'active_decorator' gem 'active_flag' gem 'active_storage_validations' gem 'acts_as_list' -gem 'acts-as-taggable-on', '~> 7.0' +gem 'acts-as-taggable-on' +gem 'addressable' gem 'any_login' gem 'cocoon' -gem 'coffee-rails', '~> 5.0.0' gem 'commonmarker' gem 'data_migrate' gem 'diffy' @@ -34,6 +33,9 @@ gem 'jquery-rails' gem 'kaminari' gem 'mentionable', '~> 0.2.1' gem 'meta-tags' +gem 'net-imap', require: false +gem 'net-pop', require: false +gem 'net-smtp', require: false # TODO: Remove it if you use rails 7.0.1 gem 'oauth2' gem 'omniauth', '~> 1.9.1' gem 'omniauth-github', '~> 1.4.0' @@ -51,7 +53,6 @@ gem 'sorcery', '~> 0.16.2' gem 'sorcery-jwt' gem 'stripe' gem 'stripe-i18n', git: 'https://github.com/komagata/stripe-i18n', branch: 'update-depencency' -gem 'sucker_punch', '~> 2.0' group :development, :test do gem 'byebug', platforms: %i[mri mingw x64_mingw] @@ -63,7 +64,7 @@ group :development, :test do end group :development do - gem 'listen', '~> 3.3' + gem 'listen' gem 'spring' gem 'spring-watcher-listen', '~> 2.0.0' gem 'web-console', '>= 4.1.0' @@ -72,6 +73,7 @@ group :development do gem 'bullet' gem 'bundle_outdated_formatter' gem 'letter_opener_web', '~> 1.0' + gem 'rack-dev-mark' gem 'rack-mini-profiler', '~> 2.0' gem 'rubocop', require: false gem 'rubocop-fjord', '~> 0.2.0', require: false @@ -86,7 +88,7 @@ group :test do gem 'capybara', '>= 2.15' gem 'minitest-retry' gem 'selenium-webdriver' - gem 'vcr' + gem 'vcr', github: 'vcr/vcr' gem 'webdrivers' gem 'webmock' end diff --git a/Gemfile.lock b/Gemfile.lock index 2f5078105fa..e89ac4b3346 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,6 +7,12 @@ GIT i18n (>= 0.6, < 2.0) railties (>= 4.0) +GIT + remote: https://github.com/vcr/vcr.git + revision: 8ced6c96e01737a418cd270e0382a8c2c6d85f7f + specs: + vcr (6.0.0) + GEM remote: https://rubygems.org/ specs: @@ -78,8 +84,8 @@ GEM minitest (>= 5.1) tzinfo (~> 2.0) zeitwerk (~> 2.3) - acts-as-taggable-on (7.0.0) - activerecord (>= 5.0, < 6.2) + acts-as-taggable-on (9.0.1) + activerecord (>= 6.0, < 7.1) acts_as_list (1.0.4) activerecord (>= 4.2) addressable (2.8.0) @@ -89,7 +95,7 @@ GEM ast (2.4.2) bcrypt (3.1.16) bindex (0.8.1) - bootsnap (1.10.2) + bootsnap (1.10.3) msgpack (~> 1.2) builder (3.2.4) bullet (7.0.1) @@ -113,13 +119,6 @@ GEM childprocess (4.1.0) cocoon (1.2.15) coderay (1.1.3) - coffee-rails (5.0.0) - coffee-script (>= 2.2.0) - railties (>= 5.2.0) - coffee-script (2.4.1) - coffee-script-source - execjs - coffee-script-source (1.12.2) commonmarker (0.23.2) concurrent-ruby (1.1.9) crack (0.4.5) @@ -128,15 +127,14 @@ GEM data_migrate (7.0.2) activerecord (>= 5.0) railties (>= 5.0) - date (3.2.2) dead_end (3.1.1) declarative (0.0.20) diffy (3.4.0) + digest (3.1.0) digest-crc (0.6.4) rake (>= 12.0.0, < 14.0.0) discord-notifier (1.0.3) erubi (1.10.0) - execjs (2.8.1) faraday (1.9.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -201,11 +199,12 @@ GEM hashie (5.0.0) holiday_jp (0.8.1) httpclient (2.8.3) - i18n (1.9.1) + i18n (1.10.0) concurrent-ruby (~> 1.0) image_processing (1.12.1) mini_magick (>= 4.9.5, < 5) ruby-vips (>= 2.0.17, < 3) + io-wait (0.2.1) jbuilder (2.11.5) actionview (>= 5.0.0) activesupport (>= 5.0.0) @@ -263,6 +262,21 @@ GEM multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.2) + io-wait + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout nio4r (2.5.8) nokogiri (1.13.1) mini_portile2 (~> 2.7.0) @@ -291,7 +305,7 @@ GEM ast (~> 2.4.1) pastel (0.8.0) tty-color (~> 0.5) - pg (1.3.0) + pg (1.3.1) postmark (1.22.0) json postmark-rails (0.22.0) @@ -306,12 +320,14 @@ GEM psych (4.0.3) stringio public_suffix (4.0.6) - puma (5.6.1) + puma (5.6.2) nio4r (~> 2.0) racc (1.6.0) rack (2.2.3) rack-cors (1.1.1) rack (>= 2.0.0) + rack-dev-mark (0.7.9) + rack (>= 1.1, < 2.3) rack-mini-profiler (2.3.3) rack (>= 1.2.0) rack-proxy (0.7.2) @@ -358,7 +374,7 @@ GEM activerecord (>= 5.2.4) activesupport (>= 5.2.4) i18n - rb-fsevent (0.11.0) + rb-fsevent (0.11.1) rb-inotify (0.10.1) ffi (~> 1.0) regexp_parser (2.2.0) @@ -369,7 +385,7 @@ GEM retriable (3.1.2) rexml (3.2.5) rollbar (3.3.0) - rubocop (1.25.0) + rubocop (1.25.1) parallel (~> 1.10) parser (>= 3.1.0.0) rainbow (>= 2.2.2, < 4.0) @@ -452,11 +468,11 @@ GEM unicode_utils (~> 1.4) strings-ansi (0.2.0) stripe (5.43.0) - sucker_punch (2.1.2) - concurrent-ruby (~> 1.0) + strscan (3.0.1) temple (0.8.2) thor (1.2.1) tilt (2.0.10) + timeout (0.2.0) traceroute (0.8.1) rails (>= 3.0.0) trailblazer-option (0.1.2) @@ -472,7 +488,6 @@ GEM unicode-display_width (2.1.0) unicode_utils (1.4.0) uniform_notifier (1.14.2) - vcr (6.0.0) view_source_map (0.3.0) rails (>= 5) web-console (4.2.0) @@ -510,8 +525,9 @@ DEPENDENCIES active_decorator active_flag active_storage_validations - acts-as-taggable-on (~> 7.0) + acts-as-taggable-on acts_as_list + addressable any_login bootsnap (>= 1.4.4) bullet @@ -519,10 +535,8 @@ DEPENDENCIES byebug capybara (>= 2.15) cocoon - coffee-rails (~> 5.0.0) commonmarker data_migrate - date (>= 3.2.1) dead_end diffy discord-notifier @@ -534,18 +548,22 @@ DEPENDENCIES jquery-rails kaminari letter_opener_web (~> 1.0) - listen (~> 3.3) + listen mentionable (~> 0.2.1) meta-tags minitest-retry + net-imap + net-pop + net-smtp oauth2 omniauth (~> 1.9.1) omniauth-github (~> 1.4.0) pg postmark-rails pry-byebug - puma (~> 5.5) + puma (~> 5.6) rack-cors + rack-dev-mark rack-mini-profiler (~> 2.0) rack-user_agent rails (~> 6.1.4.4) @@ -569,9 +587,8 @@ DEPENDENCIES spring-watcher-listen (~> 2.0.0) stripe stripe-i18n! - sucker_punch (~> 2.0) traceroute - vcr + vcr! view_source_map web-console (>= 4.1.0) webdrivers @@ -579,7 +596,7 @@ DEPENDENCIES webpacker (~> 5.0) RUBY VERSION - ruby 2.7.4p191 + ruby 3.1.0p0 BUNDLED WITH - 2.2.30 + 2.3.6 diff --git a/app/assets/images/completion/completion_background.svg b/app/assets/images/completion/completion_background.svg new file mode 100644 index 00000000000..79ec092303c --- /dev/null +++ b/app/assets/images/completion/completion_background.svg @@ -0,0 +1,1522 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/completion/completion_default.png b/app/assets/images/completion/completion_default.png new file mode 100644 index 00000000000..2f9cc5605c9 Binary files /dev/null and b/app/assets/images/completion/completion_default.png differ diff --git a/app/assets/stylesheets/article.sass b/app/assets/stylesheets/article.sass index 7aef806c227..a686cb07c30 100644 --- a/app/assets/stylesheets/article.sass +++ b/app/assets/stylesheets/article.sass @@ -1,12 +1,13 @@ @import common-imports @import /blocks/base/body @import /blocks/footer/footer +@import /blocks/shared/flash .articles__header margin-bottom: 1rem .articles__title - +text-block(1.75rem 1.4, center) + +text-block(1.75rem 1.4, center 700) .articles__item:not(:first-child) border-top: solid 1px $border @@ -19,7 +20,9 @@ text-decoration: underline .articles__item-title - +text-block(1.125rem 1.4, $default-text) + +text-block(1.125rem 1.4, $default-text 700) + .articles__item.is-wip & + color: $muted-text .articles__item-metas display: flex @@ -81,6 +84,8 @@ font-size: 2rem +media-breakpoint-down(sm) font-size: 1.625rem + &.is-wip + color: $muted-text .article__metas display: flex @@ -180,3 +185,16 @@ +media-breakpoint-up(md) max-width: 20rem +margin(horizontal, auto) + +.article__title-label + background-color: #ccc + font-size: .75rem + display: inline-block + vertical-align: middle + padding: .25rem .5rem + margin-right: .25rem + border-radius: 1rem + margin-top: -.5em + font-weight: 400 + color: $default-text + line-height: 1 diff --git a/app/assets/stylesheets/atoms/_a-completion-message.sass b/app/assets/stylesheets/atoms/_a-completion-message.sass new file mode 100644 index 00000000000..acde9251485 --- /dev/null +++ b/app/assets/stylesheets/atoms/_a-completion-message.sass @@ -0,0 +1,29 @@ +.a-completion-message + background-color: $info + +padding(vertical, .75rem) + &:not(:last-child) + margin-bottom: 1.25rem + +.a-completion-message__inner + +media-breakpoint-up(md) + display: flex + justify-content: center + align-items: center + +.a-completion-message__title + +text-block(1em 1.45, center $reversal-text 600) + +media-breakpoint-up(md) + font-size: 1rem + +media-breakpoint-down(sm) + font-size: .8125rem + +.a-completion-message__actions-item + +media-breakpoint-up(md) + width: 10rem + +media-breakpoint-down(sm) + +.a-completion-message__inner-end + +media-breakpoint-up(md) + margin-left: 1rem + +media-breakpoint-down(sm) + margin-top: .75rem diff --git a/app/assets/stylesheets/atoms/_a-placeholder.sass b/app/assets/stylesheets/atoms/_a-placeholder.sass index e051d1c937c..65e67173e2e 100644 --- a/app/assets/stylesheets/atoms/_a-placeholder.sass +++ b/app/assets/stylesheets/atoms/_a-placeholder.sass @@ -11,6 +11,13 @@ &.a-user-icon background-color: $placeholder display: block + &.thread-header-metas + height: 1.4em + background-color: $placeholder + width: 50% + &.thread-header-title + height: 1.5em + width: 70% &.thread-list-item-title height: 1.5em width: 50% @@ -18,6 +25,24 @@ height: 1.4em width: 70% +margin(horizontal, 0) + &.a-button + background-color: $placeholder + border: none + &.page-nav__item-link-inner + height: 1.4em + width: 100% + background-color: $placeholder + display: block + &.practice-status.category-practices-item__status + background-color: $placeholder + &.categories-item__title + height: 1.5em + width: 50% + background-color: $placeholder + &.category-practices-item__title-link + height: 1.5em + width: 50% + background-color: $placeholder &.is-long-text background-color: transparent p @@ -36,7 +61,21 @@ width: 80% &:nth-child(5) width: 60% + &:nth-child(6) + width: 20% &:nth-child(7) + width: 100% + &:nth-child(8) + width: 80% + &:nth-child(9) + width: 60% + &:nth-child(10) + width: 20% + &:nth-child(11) + width: 80% + &:nth-child(12) + width: 60% + &:nth-child(13) width: 20% .a-card.is-loading diff --git a/app/assets/stylesheets/blocks/card/_congrats-card-body.sass b/app/assets/stylesheets/blocks/card/_congrats-card-body.sass new file mode 100644 index 00000000000..83edf604e9d --- /dev/null +++ b/app/assets/stylesheets/blocks/card/_congrats-card-body.sass @@ -0,0 +1,22 @@ +.congrats-card-body__title + +text-block(1.5rem 1.5, 700) + +media-breakpoint-up(md) + font-size: 1.5rem + +media-breakpoint-down(sm) + font-size: 1rem + +.congrats-card-body__image-container + margin-top: 1.25rem + +.congrats-card-body__image-container + width: 100% + max-width: 28rem + +margin(horizontal, auto) + +.congrats-card-body__image + border-radius: .75rem + border: solid .5rem $background + +.congrats-card-body + .card-main-actions + margin-top: 1.25rem diff --git a/app/assets/stylesheets/blocks/form/_reference-books-form.sass b/app/assets/stylesheets/blocks/form/_reference-books-form.sass index d430315b2bc..9445ed50f7f 100644 --- a/app/assets/stylesheets/blocks/form/_reference-books-form.sass +++ b/app/assets/stylesheets/blocks/form/_reference-books-form.sass @@ -2,7 +2,7 @@ border: solid 1px $border-more-shade background-color: $background-shade border-radius: .25rem - margin-bottom: 1.5rem + position: relative +media-breakpoint-up(md) padding: 1rem 1.5rem 1.25rem +media-breakpoint-down(sm) @@ -11,7 +11,7 @@ margin-top: 2rem .reference-books-form__delete - +position(absolute, right -.25rem, top -.5rem) + +position(absolute, right -.75rem, top -.75rem) +size(2.5rem) .reference-books-form__delete-link diff --git a/app/assets/stylesheets/blocks/page/_page-body.sass b/app/assets/stylesheets/blocks/page/_page-body.sass index 909f529b80d..ec31ea5ea7b 100644 --- a/app/assets/stylesheets/blocks/page/_page-body.sass +++ b/app/assets/stylesheets/blocks/page/_page-body.sass @@ -2,19 +2,32 @@ +padding(vertical, 1.5rem) +media-breakpoint-down(sm) +padding(vertical, 1.125rem) + .page-header + & + border-top: solid 1px $border-shade .page-body__inner position: relative +.page-body__columns + +media-breakpoint-up(lg) + display: flex + gap: 1.5rem + +.page-body__column + &.is-main + flex: 1 + &.is-sub + flex: 0 0 14rem + .page-optional-header +padding(vertical, .875rem) - border-bottom: solid 1px $border-shade + border-bottom: solid 1px $border-more-shade .page-optional-header__title - +text-block(1em 1.4, center flex) + +text-block(1em 1.4, center 600 flex) align-items: center +media-breakpoint-up(md) - font-size: 1.25rem + font-size: 1.125rem +media-breakpoint-down(sm) font-size: 1rem diff --git a/app/assets/stylesheets/blocks/page/_page-tabs.sass b/app/assets/stylesheets/blocks/page/_page-tabs.sass index e0663a070bd..e2a1c3c4fd0 100644 --- a/app/assets/stylesheets/blocks/page/_page-tabs.sass +++ b/app/assets/stylesheets/blocks/page/_page-tabs.sass @@ -8,6 +8,11 @@ +media-breakpoint-down(sm) >.container +padding(horizontal, 0) + .page-header + & + border-top: solid 1px $border-more-shade + .page-tools &:last-child + border-bottom: none + .page-tabs__items display: flex diff --git a/app/assets/stylesheets/blocks/page/_page-tools.sass b/app/assets/stylesheets/blocks/page/_page-tools.sass new file mode 100644 index 00000000000..e8dd44c93dc --- /dev/null +++ b/app/assets/stylesheets/blocks/page/_page-tools.sass @@ -0,0 +1,5 @@ +.page-tools + .page-header + & + border-top: solid 1px $border-more-shade + & + .page-body + border-top: solid 1px $border-more-shade diff --git a/app/assets/stylesheets/blocks/page/_two-columns.sass b/app/assets/stylesheets/blocks/page/_two-columns.sass index 0c2eb500b5b..d9043be0dba 100644 --- a/app/assets/stylesheets/blocks/page/_two-columns.sass +++ b/app/assets/stylesheets/blocks/page/_two-columns.sass @@ -1,10 +1,14 @@ .two-columns +position(relative) - +media-breakpoint-up(lg) - display: flex - justify-content: space-between - align-items: flex-start + display: flex + gap: 1.5rem + +media-breakpoint-down(md) + flex-direction: column -.two-columns__inner - flex: 100 - max-width: $thread-max-width +.two-columns__column + &.is-main + flex: 1 + max-width: $thread-max-width + &.is-sub + +media-breakpoint-up(lg) + flex: 0 0 20rem diff --git a/app/assets/stylesheets/blocks/practice/_categories.sass b/app/assets/stylesheets/blocks/practice/_categories.sass index c301d9a1a26..7a5120c5176 100644 --- a/app/assets/stylesheets/blocks/practice/_categories.sass +++ b/app/assets/stylesheets/blocks/practice/_categories.sass @@ -27,7 +27,7 @@ +position(relative, top -3.5rem) .categories-item__title - +text-block(1.5rem 1.45, $main-text 600) + +text-block(1.5rem 1.5, $main-text 600) position: relative +media-breakpoint-down(sm) font-size: 1.25rem diff --git a/app/assets/stylesheets/blocks/practice/_completion-massage.sass b/app/assets/stylesheets/blocks/practice/_completion-massage.sass new file mode 100644 index 00000000000..fdf729b13f9 --- /dev/null +++ b/app/assets/stylesheets/blocks/practice/_completion-massage.sass @@ -0,0 +1,2 @@ +.completion-massage + background-color: $success diff --git a/app/assets/stylesheets/blocks/practice/_sticky-message.sass b/app/assets/stylesheets/blocks/practice/_sticky-message.sass index 342b4bf251e..c208fd1d952 100644 --- a/app/assets/stylesheets/blocks/practice/_sticky-message.sass +++ b/app/assets/stylesheets/blocks/practice/_sticky-message.sass @@ -4,7 +4,7 @@ width: 100% +position(sticky, left 0, bottom 0, 1) +padding(vertical, .5rem) - +text-block(1rem 1.4, center $reversal-text) + +text-block(.875rem 1.4, center $reversal-text) a +hover-link-reversal color: $reversal-text diff --git a/app/assets/stylesheets/blocks/shared/_modal.sass b/app/assets/stylesheets/blocks/shared/_modal.sass index 26edd77bde7..ee108a78b1a 100644 --- a/app/assets/stylesheets/blocks/shared/_modal.sass +++ b/app/assets/stylesheets/blocks/shared/_modal.sass @@ -14,11 +14,14 @@ font-size: .875rem .modal-header - padding: .25rem 1rem display: flex align-items: center justify-content: space-between border-bottom: solid 1px $background + +media-breakpoint-up(md) + padding: .25rem 1.5rem + +media-breakpoint-down(sm) + padding: .25rem 1rem .modal-header__close display: flex @@ -26,15 +29,18 @@ justify-content: center +size(2.75rem) cursor: pointer - margin-right: -.75rem - opacity: .7 + opacity: .4 transition: all .2s ease-out position: relative + +media-breakpoint-up(md) + margin-right: -1.5rem + +media-breakpoint-down(sm) + margin-right: -1rem &::before, &::after content: "" display: block - +size(50% 2px) + +size(40% 2px) background-color: $default-text +position(absolute, left 50%, top 50%) border-radius: 2px @@ -60,12 +66,21 @@ .modal-body max-height: calc(100vh - 11.5rem) overflow: auto - padding: 1rem border-bottom: solid 1px $background + +media-breakpoint-up(md) + padding: 1rem 1.5rem + +media-breakpoint-down(sm) + padding: 1rem .modal-title - font-size: 1.25rem font-weight: 600 + +media-breakpoint-up(md) + font-size: 1.25rem + +media-breakpoint-down(sm) + font-size: 1rem .modal-footer - padding: .25rem 1rem + +media-breakpoint-up(md) + padding: .25rem 1.5rem + +media-breakpoint-down(sm) + padding: .25rem 1rem diff --git a/app/assets/stylesheets/blocks/shared/_page-tags-nav.sass b/app/assets/stylesheets/blocks/shared/_page-tags-nav.sass index ee3df3da2f1..8f79bcd51e7 100644 --- a/app/assets/stylesheets/blocks/shared/_page-tags-nav.sass +++ b/app/assets/stylesheets/blocks/shared/_page-tags-nav.sass @@ -4,11 +4,6 @@ border-radius: .25rem +media-breakpoint-up(lg) +position(sticky, right 0, top 3.5rem) - flex: 1 - min-width: 20rem - margin-left: 1.5rem - +media-breakpoint-down(md) - margin-top: 1rem .page-tags-nav__header border-bottom: solid 1px $border diff --git a/app/assets/stylesheets/blocks/shared/_pagination.sass b/app/assets/stylesheets/blocks/shared/_pagination.sass index c6f43540ef7..49a2d5e467f 100644 --- a/app/assets/stylesheets/blocks/shared/_pagination.sass +++ b/app/assets/stylesheets/blocks/shared/_pagination.sass @@ -1,22 +1,19 @@ .pagination +position(relative, 1) - +media-breakpoint-up(md) - margin-bottom: 1rem - .page-body &:first-child + &:first-child + +media-breakpoint-up(md) + margin-bottom: 1rem margin-top: -.75rem - +media-breakpoint-down(sm) - margin-bottom: .5rem - .page-body &:first-child + +media-breakpoint-down(sm) + margin-bottom: .5rem margin-top: -.25rem - .container + &, - .thread-list + &, - .two-columns + & + .pill-nav + .page-body & + margin-top: 0 + &:not(:first-child) +media-breakpoint-up(md) margin-top: 1rem - margin-bottom: 0 +media-breakpoint-down(sm) margin-top: .5rem - margin-bottom: 0 .pagination__items display: flex diff --git a/app/assets/stylesheets/blocks/shared/_pill-nav.sass b/app/assets/stylesheets/blocks/shared/_pill-nav.sass index 9faa6f6c21f..7d6ab0d5406 100644 --- a/app/assets/stylesheets/blocks/shared/_pill-nav.sass +++ b/app/assets/stylesheets/blocks/shared/_pill-nav.sass @@ -1,6 +1,5 @@ .pill-nav - border-bottom: none - &:not(:last-child) + .page-tools &:not(:last-child) margin-bottom: 1.5rem .pill-nav__items diff --git a/app/assets/stylesheets/blocks/shared/_sort-nav.sass b/app/assets/stylesheets/blocks/shared/_sort-nav.sass index 2ce78d2e2cc..6bdb4e19220 100644 --- a/app/assets/stylesheets/blocks/shared/_sort-nav.sass +++ b/app/assets/stylesheets/blocks/shared/_sort-nav.sass @@ -12,7 +12,7 @@ flex-direction: column .sort-nav__label - +text-block(.8125rem 1.45) + +text-block(.75rem 1.4) margin-right: .5rem white-space: nowrap +media-breakpoint-down(sm) diff --git a/app/assets/stylesheets/blocks/tags/_popular-tags.sass b/app/assets/stylesheets/blocks/tags/_random-tags.sass similarity index 62% rename from app/assets/stylesheets/blocks/tags/_popular-tags.sass rename to app/assets/stylesheets/blocks/tags/_random-tags.sass index 01c65e8721c..7060ac812ba 100644 --- a/app/assets/stylesheets/blocks/tags/_popular-tags.sass +++ b/app/assets/stylesheets/blocks/tags/_random-tags.sass @@ -1,23 +1,6 @@ -.random-tags - +position(fixed, right 0, top 0, bottom 0, 3) - +size(14rem 100vh) - background-color: $main - overflow-y: auto - +media-breakpoint-down(lg) - display: none - -.random-tags__header - border-bottom: solid 1px $side-border - -.random-tags__header-inner - +padding(vertical, .75rem) - -.random-tags__title - +text-block(.875rem 1.4, center $reversal-text) - .random-tags__item &:not(:last-child) - border-bottom: dashed 1px $side-border + border-bottom: dashed 1px $border .random-tags__item-link +flex-link @@ -36,11 +19,11 @@ .random-tags__item-count +position(absolute, right 0, top 2px) - +text-block(.625rem, flex center $reversal-text) + +text-block(.625rem, flex center $default-text) justify-content: center align-items: center +padding(horizontal, .75em) - background-color: rgba(black, .4) + background-color: $background height: 1.5em border-radius: 1em @@ -57,13 +40,13 @@ +fa(fas '\f521') .is-first &, .is-first &::before - color: #deea20 + color: #e3a822 .is-second &, .is-second &::before - color: $reversal-text + color: #898888 .is-third &, .is-third &::before - color: #f3b8a6 + color: #dc7e61 .is-up & font-size: 1.125em .is-low & diff --git a/app/assets/stylesheets/blocks/thread/_thread-list-item-meta.sass b/app/assets/stylesheets/blocks/thread/_thread-list-item-meta.sass index b205355d1cf..f915a0b9a9c 100644 --- a/app/assets/stylesheets/blocks/thread/_thread-list-item-meta.sass +++ b/app/assets/stylesheets/blocks/thread/_thread-list-item-meta.sass @@ -2,6 +2,8 @@ .a-user-name, .a-meta font-size: .75rem + .thread-list-item-title + & + margin-top: .25em .thread-list-item-meta__items +text-block(.75rem 1.4) diff --git a/app/assets/stylesheets/blocks/user/_companies-item.sass b/app/assets/stylesheets/blocks/user/_companies-item.sass index b8bc199273c..e2368a40c13 100644 --- a/app/assets/stylesheets/blocks/user/_companies-item.sass +++ b/app/assets/stylesheets/blocks/user/_companies-item.sass @@ -1,6 +1,4 @@ .companies-item - padding-top: .375rem - padding-bottom: 1.5rem height: 100% .companies-item__inner diff --git a/app/assets/stylesheets/blocks/user/_user-group.sass b/app/assets/stylesheets/blocks/user/_user-group.sass index c759e1ce086..78682f47d11 100644 --- a/app/assets/stylesheets/blocks/user/_user-group.sass +++ b/app/assets/stylesheets/blocks/user/_user-group.sass @@ -30,9 +30,9 @@ .user-group__title-icon margin-right: .375em &.is-first - color: #c1ad15 + color: #e3a822 &.is-second - color: #a0a0a0 + color: #898888 &.is-third color: #dc7e61 diff --git a/app/assets/stylesheets/blocks/user/_users-item.sass b/app/assets/stylesheets/blocks/user/_users-item.sass index 6e4f9450292..e6d009df7cf 100644 --- a/app/assets/stylesheets/blocks/user/_users-item.sass +++ b/app/assets/stylesheets/blocks/user/_users-item.sass @@ -1,10 +1,5 @@ .users-item height: 100% - +media-breakpoint-up(md) - +padding(vertical, .375rem .5rem) - +media-breakpoint-down(sm) - [class*=col-]:not(:first-child) & - margin-top: 1rem .users-item__inactive-message background-color: $danger diff --git a/app/assets/stylesheets/blocks/user/_users.sass b/app/assets/stylesheets/blocks/user/_users.sass deleted file mode 100644 index 16c8f80babb..00000000000 --- a/app/assets/stylesheets/blocks/user/_users.sass +++ /dev/null @@ -1,3 +0,0 @@ -.users - +media-breakpoint-up(md) - margin-bottom: -.5rem diff --git a/app/assets/stylesheets/completion.sass b/app/assets/stylesheets/completion.sass new file mode 100644 index 00000000000..0ec9f86a5bd --- /dev/null +++ b/app/assets/stylesheets/completion.sass @@ -0,0 +1,4 @@ +@import common-imports +@import blocks/shared/flash +@import blocks/shared/modal +@import completion/**/* diff --git a/app/assets/stylesheets/completion/_completion-base.sass b/app/assets/stylesheets/completion/_completion-base.sass new file mode 100644 index 00000000000..6ed3f62a0a4 --- /dev/null +++ b/app/assets/stylesheets/completion/_completion-base.sass @@ -0,0 +1,80 @@ +$completion: #00a0dd + +body.is-completion + background-color: $completion + +.completion-wrapper + min-height: 100vh + display: flex + flex-direction: column + &::before + content: '' + background-image: image_url('completion/completion_background.svg') + background-repeat: repeat + +position(fixed, left 0, top 0, right 0, bottom 0, 1) + +size(100%) + opacity: .075 + +media-breakpoint-up(md) + background-size: 16rem auto + +.completion-wrapper__start + flex: 1 + +position(relative, 2) + +.completion-wrapper__end + +position(relative, 2) + +.complestion + +padding(vertical, 4rem 2rem) + +.complestion__title + +text-block(2rem 1.5, 800 center $reversal-text) + font-family: YakuHanJP_Narrow,Hiragino Sans,Hiragino Kaku Gothic ProN,BIZ UDPGothic,Meiryo,sans-serif + +.complestion__body + margin-top: 3rem + +.complestion__image + border-radius: 1rem + border: solid .75rem shade($completion, 30%) + +.welcome-footer + +media-breakpoint-up(md) + +padding(vertical, 3rem) + +media-breakpoint-down(sm) + padding-bottom: 1.5rem + body.welcome & .container + +padding(horizontal, 0) + +.welcome-footer__nav + margin-bottom: 1.5rem + +.welcome-footer__nav-items + +media-breakpoint-up(md) + display: flex + justify-content: center + +.welcome-footer__nav-item + +media-breakpoint-up(md) + +padding(horizontal, .5rem) + +.welcome-footer__nav-item-link + +text-block(.875rem 1, $reversal-text) + +media-breakpoint-up(md) + +hover-link + +media-breakpoint-down(sm) + text-decoration: none + display: flex + align-items: center + +padding(horizontal, 1rem) + border-bottom: solid 1px $border + +size(100% 2.75rem) + +.welcome-footer-copyright + justify-content: center + align-items: center + +text-block(.875rem 1.45, flex $reversal-text) + +.welcome-footer-copyright__author + display: block + +margin(horizontal, .1em .5em) diff --git a/app/assets/stylesheets/helpers/_state.sass b/app/assets/stylesheets/helpers/_state.sass index 783bf0782bb..51f771d53c7 100644 --- a/app/assets/stylesheets/helpers/_state.sass +++ b/app/assets/stylesheets/helpers/_state.sass @@ -5,6 +5,14 @@ html display: none !important body + .is-hidden-lg-up + +media-breakpoint-up(lg) + display: none + + .is-hidden-lg-down + +media-breakpoint-down(lg) + display: none + .is-hidden-md-up +media-breakpoint-up(md) display: none @@ -13,10 +21,6 @@ html +media-breakpoint-down(md) display: none - .is-hidden-lg-up - +media-breakpoint-up(lg) - display: none - .is-hidden-sm-down +media-breakpoint-down(sm) display: none diff --git a/app/assets/stylesheets/mixins/_grid.sass b/app/assets/stylesheets/mixins/_grid.sass index a9c3e61da19..043d5a4c75f 100644 --- a/app/assets/stylesheets/mixins/_grid.sass +++ b/app/assets/stylesheets/mixins/_grid.sass @@ -1,19 +1,3 @@ -// Container widths -// -// Set the container width, and override it for fixed navbars in media queries. - -.#{$container-class-name} - +make-container - max-width: $container-max-width - -// Fluid container -// -// Utilizes the mixin meant for fixed width containers, but without any defined -// width for fluid, full width layouts. - -.container-fluid - +make-container - // Row // // Rows contain and clear the floats of your columns. @@ -25,157 +9,16 @@ // // Common styles for small and large grid columns -.row>[class*=col-] - position: relative - // Inner gutter via padding - +padding(horizontal, $grid-gutter-width / 2) - +make-grid-columns -.col-xs-first - order: -1 -.col-xs-last - order: 1 - -+media-breakpoint-up(sm) - .col-sm-first - order: -1 - .col-sm-last - order: 1 - -+media-breakpoint-up(md) - .col-md-first - order: -1 - .col-md-last - order: 1 - -+media-breakpoint-up(lg) - .col-lg-first - order: -1 - .col-lg-last - order: 1 - -+media-breakpoint-up(xl) - .col-xl-first - order: -1 - .col-xl-last - order: 1 - -// Alignment for every column in row - -.row-xs-top - align-items: flex-start -.row-xs-center - align-items: center -.row-xs-bottom - align-items: flex-end - -+media-breakpoint-up(sm) - .row-sm-top - align-items: flex-start - .row-sm-center - align-items: center - .row-sm-bottom - align-items: flex-end - -+media-breakpoint-up(md) - .row-md-top - align-items: flex-start - .row-md-center - align-items: center - .row-md-bottom - align-items: flex-end - -+media-breakpoint-up(lg) - .row-lg-top - align-items: flex-start - .row-lg-center - align-items: center - .row-lg-bottom - align-items: flex-end - -+media-breakpoint-up(xl) - .row-xl-top - align-items: flex-start - .row-xl-center - align-items: center - .row-xl-bottom - align-items: flex-end - -// Alignment per column - -.col-xs-top - align-self: flex-start -.col-xs-center - align-self: center -.col-xs-bottom - align-self: flex-end - -+media-breakpoint-up(sm) - .col-sm-top - align-self: flex-start - .col-sm-center - align-self: center - .col-sm-bottom - align-self: flex-end - -+media-breakpoint-up(md) - .col-md-top - align-self: flex-start - .col-md-center - align-self: center - .col-md-bottom - align-self: flex-end - -+media-breakpoint-up(lg) - .col-lg-top - align-self: flex-start - .col-lg-center - align-self: center - .col-lg-bottom - align-self: flex-end - -+media-breakpoint-up(xl) - .col-xl-top - align-self: flex-start - .col-xl-center - align-self: center - .col-xl-bottom - align-self: flex-end - =grid($gutter-size) &.row - +margin(horizontal, $gutter-size/2 * -1) - >* - +padding(horizontal, $gutter-size/2) + gap: px_to_rem($gutter-size) // helper .row @for $i from 0 through 16 $gutter-size: $i * 4 - $breakpoints: xs, sm, md, lg, xl, false - $scopes: up, down, only - @each $breakpoint in $breakpoints - @if $breakpoint - @each $scope in $scopes - &.is-gutter-width-#{$gutter-size}-#{$breakpoint}-#{$scope} - @if $scope == up - +media-breakpoint-up($breakpoint) - +margin(horizontal, px_to_rem($gutter-size * 1px, $base-px) / -2) - >[class*=col-] - +padding(horizontal, px_to_rem($gutter-size * 1px, $base-px) / 2) - @else if $scope == down - +media-breakpoint-down($breakpoint) - +margin(horizontal, px_to_rem($gutter-size * 1px, $base-px) / -2) - >[class*=col-] - +padding(horizontal, px_to_rem($gutter-size * 1px, $base-px) / 2) - @else if $scope == only - +media-breakpoint-only($breakpoint) - +margin(horizontal, px_to_rem($gutter-size * 1px, $base-px) / -2) - >[class*=col-] - +padding(horizontal, px_to_rem($gutter-size * 1px, $base-px) / 2) - @else - &.is-gutter-width-#{$gutter-size} - +margin(horizontal, px_to_rem($gutter-size * 1px, $base-px) / -2) - >[class*=col-] - +padding(horizontal, px_to_rem($gutter-size * 1px, $base-px) / 2) + &.is-gutter-width-#{$gutter-size} + gap: #{$gutter-size / 16}rem + +make-grid-columns($grid-columns, #{$gutter-size / 16}rem) diff --git a/app/assets/stylesheets/mixins/grid/_grid-framework.sass b/app/assets/stylesheets/mixins/grid/_grid-framework.sass index 35e1a64cb9a..03e857ba33f 100644 --- a/app/assets/stylesheets/mixins/grid/_grid-framework.sass +++ b/app/assets/stylesheets/mixins/grid/_grid-framework.sass @@ -2,39 +2,17 @@ // // Generate semantic grid columns with these mixins. -=make-container($gutter: $grid-gutter-width) - +padding(horizontal, $gutter / 2) - =make-row($gutter: $grid-gutter-width) display: flex flex-wrap: wrap - +margin(horizontal, $gutter / -2) - -=make-col($gutter: $grid-gutter-width) - position: relative - min-height: 1px - +padding(horizontal, $gutter / 2) - -=make-col-span($size, $columns: $grid-columns) - flex: 0 0 percentage($size / $columns) - width: percentage($size / $columns) - // for firefox bug - max-width: percentage($size / $columns) - -=make-col-offset($size, $columns: $grid-columns) - margin-left: percentage($size / $columns) - -=make-col-push($size, $columns: $grid-columns) - left: if($size > 0, percentage($size / $columns), auto) + gap: $gutter -=make-col-pull($size, $columns: $grid-columns) - right: if($size > 0, percentage($size / $columns), auto) +=make-col-span($size, $columns: $grid-columns, $grid-gutter-width: 1rem) + $one-line-columns-count: $columns / $size + $gutter-count: $one-line-columns-count - 1 + $total-gutter-width: calc(#{$grid-gutter-width} * #{$gutter-count}) + $column-margin: $total-gutter-width / $one-line-columns-count -=make-col-modifier($type, $size, $columns) - // Work around the lack of dynamic mixin @include support (https://github.com/sass/sass/issues/626) - @if $type == push - +make-col-push($size, $columns) - @else if $type == pull - +make-col-pull($size, $columns) - @else if $type == offset - +make-col-offset($size, $columns) + flex: 0 0 calc(#{percentage($size / $columns)} - #{$column-margin}) + width: calc(#{percentage($size / $columns)} - #{$column-margin}) + max-width: calc(#{percentage($size / $columns)} - #{$column-margin}) diff --git a/app/assets/stylesheets/mixins/grid/_grid.sass b/app/assets/stylesheets/mixins/grid/_grid.sass index 07f64dbeb79..fcf3936700d 100644 --- a/app/assets/stylesheets/mixins/grid/_grid.sass +++ b/app/assets/stylesheets/mixins/grid/_grid.sass @@ -8,8 +8,4 @@ +media-breakpoint-up($breakpoint) @for $i from 1 through $columns .col-#{$breakpoint}-#{$i} - +make-col-span($i, $columns) - @each $modifier in pull, push, offset - @for $i from 0 through $columns - .#{$modifier}-#{$breakpoint}-#{$i} - +make-col-modifier($modifier, $i, $columns) + +make-col-span($i, $columns, $gutter) diff --git a/app/assets/stylesheets/shared/_base.sass b/app/assets/stylesheets/shared/_base.sass index a19cac81d32..10ae3011f06 100644 --- a/app/assets/stylesheets/shared/_base.sass +++ b/app/assets/stylesheets/shared/_base.sass @@ -43,12 +43,6 @@ body margin-left: 0 body.is-admin-page & margin-right: 0 - body.has-random-tags & - margin-right: 14rem - +media-breakpoint-down(lg) - margin-right: 0 - +media-breakpoint-down(sm) - margin-right: 0 body.is-error-page & padding-top: 4rem overflow-y: auto diff --git a/app/assets/stylesheets/welcome/_faqs-item.sass b/app/assets/stylesheets/welcome/_faqs-item.sass index dcf061a301c..7242ff4f8cb 100644 --- a/app/assets/stylesheets/welcome/_faqs-item.sass +++ b/app/assets/stylesheets/welcome/_faqs-item.sass @@ -21,12 +21,12 @@ position: absolute +media-breakpoint-up(md) +size(2.5rem) - left: -1.5rem - top: -1.25rem + left: -2.5rem + top: -2.25rem +media-breakpoint-down(sm) +size(2.125rem) - left: -.75rem - top: -1.25rem + left: -2.125rem + top: -1.875rem .faqs-item__body p diff --git a/app/assets/stylesheets/welcome/_welcome-member.sass b/app/assets/stylesheets/welcome/_welcome-member.sass index fe8e9ee8d78..332ddc52e08 100644 --- a/app/assets/stylesheets/welcome/_welcome-member.sass +++ b/app/assets/stylesheets/welcome/_welcome-member.sass @@ -1,7 +1,3 @@ -.welcome-members - [class*=col-] - margin-bottom: 1.5rem - .welcome-member background-color: rgba($base, .8) border: solid 2px $welcome-card-border diff --git a/app/assets/stylesheets/welcome/_welcome-small-sections.sass b/app/assets/stylesheets/welcome/_welcome-small-sections.sass index c154b1a5450..1b487f17a2b 100644 --- a/app/assets/stylesheets/welcome/_welcome-small-sections.sass +++ b/app/assets/stylesheets/welcome/_welcome-small-sections.sass @@ -1,5 +1,4 @@ .welcome-small-sections - margin-bottom: -2rem .welcome-child-section__title + & margin-top: 1.5rem .welcome-section__title + & @@ -53,16 +52,12 @@ .welcome-small-section height: 100% - padding-bottom: 2rem &.is-wide height: auto padding-bottom: 0 max-width: 55rem margin-top: 1.5rem +margin(horizontal, auto) - .welcome-small-sections.is-about [class*=col-]:not(:last-child) & - +media-breakpoint-down(sm) - padding-bottom: 3rem .welcome-child-section.is-unlimited & padding-bottom: 0 diff --git a/app/controllers/admin/campaigns_controller.rb b/app/controllers/admin/campaigns_controller.rb new file mode 100644 index 00000000000..93f97c3550d --- /dev/null +++ b/app/controllers/admin/campaigns_controller.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +class Admin::CampaignsController < AdminController + before_action :set_campaign, only: %i[edit update] + def new + @campaign = Campaign.new(start_at: Time.current.beginning_of_day) + end + + def create + @campaign = Campaign.new(campaign_params) + if @campaign.save + redirect_to admin_campaigns_path, notice: 'お試し延長を作成しました。' + else + render :new + end + end + + def index + @campaigns = Campaign.order(end_at: :desc) + end + + def edit; end + + def update + if @campaign.update(campaign_params) + redirect_to admin_campaigns_path, notice: 'お試し延長を更新しました。' + else + render :edit + end + end + + private + + def set_campaign + @campaign = Campaign.find(params[:id]) + end + + def campaign_params + params.require(:campaign).permit(:start_at, :end_at, :title) + end +end diff --git a/app/controllers/api/practices/learning/completion_message_controller.rb b/app/controllers/api/practices/learning/completion_message_controller.rb new file mode 100644 index 00000000000..b4313a6fe00 --- /dev/null +++ b/app/controllers/api/practices/learning/completion_message_controller.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class API::Practices::Learning::CompletionMessageController < API::BaseController + def update + learning = current_user.learnings.find_by(practice_id: params[:practice_id]) + if learning.update(completion_message_displayed: true) + head :ok + else + head :bad_request + end + end +end diff --git a/app/controllers/api/products/unassigned_controller.rb b/app/controllers/api/products/unassigned_controller.rb index d518b91a47c..e2857f7ac86 100644 --- a/app/controllers/api/products/unassigned_controller.rb +++ b/app/controllers/api/products/unassigned_controller.rb @@ -13,4 +13,14 @@ def index @latest_product_submitted_just_6days = @products.find { |product| product.elapsed_days == 6 } @latest_product_submitted_over_7days = @products.find { |product| product.elapsed_days >= 7 } end + + def counts + products = Product + .unassigned + .unchecked + .not_wip + @passed5 = products.count { |product| product.elapsed_days == 5 } + @passed6 = products.count { |product| product.elapsed_days == 6 } + @over7 = products.count { |product| product.elapsed_days >= 7 } + end end diff --git a/app/controllers/api/talks/unreplied_controller.rb b/app/controllers/api/talks/unreplied_controller.rb index 4aa609cecaa..c1ffe412b56 100644 --- a/app/controllers/api/talks/unreplied_controller.rb +++ b/app/controllers/api/talks/unreplied_controller.rb @@ -2,6 +2,6 @@ class API::Talks::UnrepliedController < API::BaseController def index - @talks = Talk.unreplied + @talks = Talk.unreplied.page(params[:page]) end end diff --git a/app/controllers/api/talks_controller.rb b/app/controllers/api/talks_controller.rb index 61206714b6a..075452cbec0 100644 --- a/app/controllers/api/talks_controller.rb +++ b/app/controllers/api/talks_controller.rb @@ -2,6 +2,6 @@ class API::TalksController < API::BaseController def index - @talks = Talk.all + @talks = Talk.page(params[:page]) end end diff --git a/app/controllers/articles_controller.rb b/app/controllers/articles_controller.rb index 379cf337226..024d967457a 100644 --- a/app/controllers/articles_controller.rb +++ b/app/controllers/articles_controller.rb @@ -5,13 +5,17 @@ class ArticlesController < ApplicationController before_action :require_admin_login, except: %i[index show] def index - @articles = Article.all.order(created_at: :desc) + @articles = list_articles @articles = @articles.tagged_with(params[:tag]) if params[:tag] render layout: 'article' end def show - render layout: 'article' + if !@article.wip? || admin_or_mentor_login? + render layout: 'article' + else + redirect_to root_path, alert: '管理者・メンターとしてログインしてください' + end end def new @@ -23,17 +27,18 @@ def edit; end def create @article = Article.new(article_params) @article.user = current_user - + set_wip_or_published_time if @article.save - redirect_to @article, notice: '記事を作成しました' + redirect_to redirect_url(@article), notice: notice_message(@article) else render :new end end def update + set_wip_or_published_time if @article.update(article_params) - redirect_to @article, notice: '記事を更新しました' + redirect_to redirect_url(@article), notice: notice_message(@article) else render :edit end @@ -50,7 +55,37 @@ def set_article @article = Article.find(params[:id]) end + def list_articles + if admin_or_mentor_login? + Article.all.order(created_at: :desc) + else + Article.all.where(wip: false).order(created_at: :desc) + end + end + def article_params params.require(:article).permit(:title, :body, :tag_list) end + + def redirect_url(article) + article.wip? ? edit_article_url(article) : article + end + + def set_wip_or_published_time + if params[:commit] == 'WIP' + @article.wip = true + else + @article.wip = false + @article.published_at = Time.current + end + end + + def notice_message(article) + case params[:action] + when 'create' + article.wip? ? '記事をWIPとして保存しました' : '記事を作成しました' + when 'update' + article.wip? ? '記事をWIPとして保存しました' : '記事を更新しました' + end + end end diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index 72131a15cd8..9cd2de23a00 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -12,8 +12,9 @@ def index .order(published_at: :desc) .limit(3) @completed_learnings = current_user.learnings.where(status: 3).includes(:practice).order(updated_at: :desc) - @inactive_students = User.with_attached_avatar.inactive_students_and_trainees.order(updated_at: :desc) + @inactive_students = User.with_attached_avatar.inactive_students_and_trainees.includes(:company).order(updated_at: :desc) @job_seeking_users = User.with_attached_avatar.job_seeking.includes(:reports, :products, :works, :course, :company) + @students_and_trainees = User.students_and_trainees.with_attached_avatar.includes(:company) display_events_on_dashboard set_required_fields render aciton: :index diff --git a/app/controllers/practices/completion_controller.rb b/app/controllers/practices/completion_controller.rb new file mode 100644 index 00000000000..602074192ef --- /dev/null +++ b/app/controllers/practices/completion_controller.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +class Practices::CompletionController < ApplicationController + layout 'completion' + + def show + @practice = Practice.find(params[:practice_id]) + end +end diff --git a/app/controllers/practices_controller.rb b/app/controllers/practices_controller.rb index d537ea0110f..2d3744e7f54 100644 --- a/app/controllers/practices_controller.rb +++ b/app/controllers/practices_controller.rb @@ -9,6 +9,7 @@ class PracticesController < ApplicationController def show @categories = @practice.categories + @tweet_url = @practice.tweet_url(practice_completion_url(@practice.id)) end def new @@ -47,6 +48,7 @@ def practice_params :submission, :open_product, :include_progress, + :ogp_image, :memo, category_ids: [], reference_books_attributes: %i[id title price page_url must_read cover description _destroy] diff --git a/app/controllers/products_controller.rb b/app/controllers/products_controller.rb index 5f2417c4381..320cb2b3249 100644 --- a/app/controllers/products_controller.rb +++ b/app/controllers/products_controller.rb @@ -10,9 +10,15 @@ def index; end def show @product = find_product - @reports = @product.user.reports.limit(10).order(reported_on: :DESC) + @reports = @product.user + .reports + .limit(10) + .includes(:comments, :checks) + .order(reported_on: :DESC) @practice = find_practice + @learning = @product.learning # decoratorメソッド用にcontrollerでインスタンス変数化 @footprints = find_footprints + @tweet_url = @practice.tweet_url(practice_completion_url(@practice.id)) footprint! respond_to do |format| format.html @@ -85,13 +91,13 @@ def find_my_product end def find_footprints - find_product.footprints.with_avatar.order(created_at: :desc) + @product.footprints.with_avatar.order(created_at: :desc) end def footprint! - return unless find_product.user != current_user + return unless @product.user != current_user - find_product.footprints.create_or_find_by(user: current_user) + @product.footprints.create_or_find_by(user: current_user) end def check_permission! diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index 80484355f00..503243b8298 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -51,7 +51,7 @@ def create set_wip canonicalize_learning_times(@report) if @report.save - redirect_to redirect_url(@report), notice: notice_message(@report) + redirect_to redirect_url(@report), notice: notice_message(@report), flash: flash_contents(@report) else render :new end @@ -63,7 +63,7 @@ def update @report.assign_attributes(report_params) canonicalize_learning_times(@report) if @report.save - redirect_to redirect_url(@report), notice: notice_message(@report) + redirect_to redirect_url(@report), notice: notice_message(@report), flash: flash_contents(@report) else render :edit end @@ -133,13 +133,17 @@ def set_wip end def redirect_url(report) - report.wip? ? edit_report_url(report) : report + report.wip? ? edit_report_url(report) : report_url(report) end def notice_message(report) report.wip? ? '日報をWIPとして保存しました。' : '日報を保存しました。' end + def flash_contents(report) + { notify_help: !report.wip? && report.sad? } + end + def set_watch @watch = Watch.new end diff --git a/app/controllers/scheduler/link_checker_controller.rb b/app/controllers/scheduler/link_checker_controller.rb index 1368d20d0bd..1ef88c0308f 100644 --- a/app/controllers/scheduler/link_checker_controller.rb +++ b/app/controllers/scheduler/link_checker_controller.rb @@ -2,8 +2,12 @@ class Scheduler::LinkCheckerController < SchedulerController def show - checker = LinkChecker::Checker.new - checker.notify_missing_links - render plain: checker.errors.join("\n") + documents = Page.all + Practice.all + links = LinkChecker::Extractor.extract_links_from_multi(documents) + summary_of_broken_links = LinkChecker::Checker.check_broken_links(links) + + ChatNotifier.message(summary_of_broken_links, username: 'リンクチェッカー', webhook_url: ENV['DISCORD_BUG_WEBHOOK_URL']) + + render plain: summary_of_broken_links end end diff --git a/app/decorators/learning_decorator.rb b/app/decorators/learning_decorator.rb new file mode 100644 index 00000000000..8a443ab5e7b --- /dev/null +++ b/app/decorators/learning_decorator.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module LearningDecorator + def should_display_message_automatically?(current_user:) + user == current_user && complete? && !completion_message_displayed? + end +end diff --git a/app/helpers/notification_helper.rb b/app/helpers/notification_helper.rb new file mode 100644 index 00000000000..1ea64f22958 --- /dev/null +++ b/app/helpers/notification_helper.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +module NotificationHelper + def ensure_notifications?(target) + current_user.notifications.by_target(target).unreads.latest_of_each_link.size.positive? + end +end diff --git a/app/javascript/admin_companies.vue b/app/javascript/admin_companies.vue index 7fb919d67f0..23564c7b39f 100644 --- a/app/javascript/admin_companies.vue +++ b/app/javascript/admin_companies.vue @@ -1,5 +1,5 @@ diff --git a/app/javascript/loading-courses-practices-page-items-placeholder.vue b/app/javascript/loading-courses-practices-page-items-placeholder.vue new file mode 100644 index 00000000000..b8204fc7b31 --- /dev/null +++ b/app/javascript/loading-courses-practices-page-items-placeholder.vue @@ -0,0 +1,30 @@ + + + diff --git a/app/javascript/loading-courses-practices-page-placeholder.vue b/app/javascript/loading-courses-practices-page-placeholder.vue new file mode 100644 index 00000000000..aa9470b0637 --- /dev/null +++ b/app/javascript/loading-courses-practices-page-placeholder.vue @@ -0,0 +1,35 @@ + + + diff --git a/app/javascript/loading-question-page-itme-placeholder.vue b/app/javascript/loading-question-page-itme-placeholder.vue new file mode 100644 index 00000000000..6fae7930e78 --- /dev/null +++ b/app/javascript/loading-question-page-itme-placeholder.vue @@ -0,0 +1,43 @@ + diff --git a/app/javascript/loading-question-page-placeholder.vue b/app/javascript/loading-question-page-placeholder.vue new file mode 100644 index 00000000000..526f4d70ae0 --- /dev/null +++ b/app/javascript/loading-question-page-placeholder.vue @@ -0,0 +1,20 @@ + + + diff --git a/app/javascript/markdown-it-task-lists-initializer.js b/app/javascript/markdown-it-task-lists-initializer.js index ef51377d787..eeaf841d22b 100644 --- a/app/javascript/markdown-it-task-lists-initializer.js +++ b/app/javascript/markdown-it-task-lists-initializer.js @@ -61,7 +61,7 @@ export default class { }) }) .catch((error) => { - console.warn('Failed to parsing', error) + console.warn(error) }) } } diff --git a/app/javascript/memo.vue b/app/javascript/memo.vue index b351cd0330d..7575662f7ab 100644 --- a/app/javascript/memo.vue +++ b/app/javascript/memo.vue @@ -104,7 +104,7 @@ export default { } }) .catch((error) => { - console.warn('Failed to parsing', error) + console.warn(error) }) }, updateMemo: function () { @@ -142,7 +142,7 @@ export default { } }) .catch((error) => { - console.warn('Failed to parsing', error) + console.warn(error) }) }, deleteMemo: function () { @@ -167,7 +167,7 @@ export default { } }) .catch((error) => { - console.warn('Failed to parsing', error) + console.warn(error) }) } } diff --git a/app/javascript/niconico_calendar.vue b/app/javascript/niconico_calendar.vue index 4276c808b7c..bb3df687ee0 100644 --- a/app/javascript/niconico_calendar.vue +++ b/app/javascript/niconico_calendar.vue @@ -153,7 +153,7 @@ export default { this.loaded = true }) .catch((error) => { - console.warn('Failed to parsing', error) + console.warn(error) }) }, methods: { diff --git a/app/javascript/notifications.vue b/app/javascript/notifications.vue index 2d8379773f2..f50d3c1b819 100644 --- a/app/javascript/notifications.vue +++ b/app/javascript/notifications.vue @@ -1,5 +1,5 @@