Merge branch 'main' into feature/theme-stimulus

This commit is contained in:
Andreas Nedbal 2023-01-21 13:40:58 +01:00
commit de3e04812d
19 changed files with 838 additions and 62 deletions

76
.github/workflows/lint.yml vendored Normal file
View file

@ -0,0 +1,76 @@
name: Lint
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
rubocop:
name: Rubocop
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.3.0
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Run rubocop
uses: reviewdog/action-rubocop@v2
with:
rubocop_version: gemfile
rubocop_extensions: rubocop-rails:gemfile
reporter: github-pr-check
eslint:
name: ESLint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.3.0
- name: Set up Node 14
uses: actions/setup-node@v3
with:
node-version: '14'
cache: 'yarn'
- name: Install node modules
run: |
npm i -g yarn
yarn install --frozen-lockfile
- uses: reviewdog/action-eslint@v1
with:
reporter: github-check
eslint_flags: '--ext .ts app/javascript'
haml-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.3.0
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- uses: patch-technology/action-haml-lint@0.4
with:
reporter: github-check
rubocop_version: gemfile
stylelint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.3.0
- name: Set up Node 14
uses: actions/setup-node@v3
with:
node-version: '14'
cache: 'yarn'
- name: Install node modules
run: |
npm i -g yarn
yarn install --frozen-lockfile
- name: stylelint
uses: pixeldesu/action-stylelint@5ec750b03a94da735352bdb02e9dfc3d5af33aba
with:
github_token: ${{ secrets.github_token }}
reporter: github-pr-check
stylelint_input: 'app/assets/stylesheets/**/*.scss'

View file

@ -52,6 +52,7 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: '14'
cache: 'yarn'
- name: Copy default configuration
run: |
cp config/database.yml.postgres config/database.yml
@ -78,24 +79,3 @@ jobs:
with:
token: ${{ secrets.CODECOV_TOKEN }}
file: ./coverage/coverage.xml
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3.3.0
- name: Install dependencies
run: sudo apt update && sudo apt-get install -y libpq-dev libxml2-dev libxslt1-dev libmagickwand-dev imagemagick libidn11-dev
- name: Set up Ruby
uses: ruby/setup-ruby@v1
with:
bundler-cache: true
- name: Run rubocop
uses: reviewdog/action-rubocop@v2
with:
rubocop_version: gemfile
rubocop_extensions: rubocop-rails:gemfile
reporter: github-pr-check
- run: yarn install
- uses: reviewdog/action-eslint@v1
with:
reporter: github-check
eslint_flags: '--ext .ts app/javascript'

29
.stylelintrc.json Normal file
View file

@ -0,0 +1,29 @@
{
"extends": [
"stylelint-config-standard-scss"
],
"plugins": [
"stylelint-scss"
],
"rules": {
"scss/at-import-partial-extension": null,
"scss/at-rule-no-unknown": true,
"at-rule-no-unknown": null,
"color-hex-length": "long",
"color-hex-case": "upper",
"comment-whitespace-inside": null,
"declaration-block-no-duplicate-properties": true,
"function-name-case": null,
"max-empty-lines": 2,
"number-leading-zero": "always",
"no-descending-specificity": null,
"no-duplicate-at-import-rules": true,
"rule-empty-line-before": ["always-multi-line", {"ignore": ["after-comment"]}],
"shorthand-property-no-redundant-values": [true, {"severity": "warning"}],
"selector-class-pattern": null,
"selector-id-pattern": null,
"selector-max-id": 1,
"string-quotes": "double",
"value-keyword-case": "lower"
}
}

View file

@ -184,7 +184,7 @@ GEM
nokogiri (>= 1.5.11, < 2.0.0)
formatador (1.1.0)
glob (0.3.1)
globalid (1.0.0)
globalid (1.0.1)
activesupport (>= 5.0)
haml (6.1.1)
temple (>= 0.8.2)
@ -323,7 +323,7 @@ GEM
activesupport (>= 3.0.0)
questiongenerator (1.0.0)
racc (1.6.2)
rack (2.2.5)
rack (2.2.6.2)
rack-protection (2.2.2)
rack
rack-test (2.0.2)

View file

@ -1,6 +1,5 @@
import start from 'retrospring/common';
import initAnswerbox from 'retrospring/features/answerbox/index';
import initCapabilities from 'retrospring/features/capabilities';
import initInbox from 'retrospring/features/inbox/index';
import initUser from 'retrospring/features/user';
import initSettings from 'retrospring/features/settings/index';
@ -14,7 +13,6 @@ import initWebpush from 'retrospring/features/webpush';
import initWebpushSettingsButtons from 'retrospring/features/webpush/settingsButtons';
start();
document.addEventListener('turbo:load', initCapabilities);
document.addEventListener('DOMContentLoaded', initAnswerbox);
document.addEventListener('DOMContentLoaded', initInbox);
document.addEventListener('DOMContentLoaded', initUser);

View file

@ -0,0 +1,21 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
connect(): void {
const capabilities = [];
if ('share' in navigator) {
capabilities.push('cap-web-share');
}
if ('serviceWorker' in navigator) {
capabilities.push('cap-service-worker');
}
if ('Notification' in window) {
capabilities.push('cap-notification');
}
this.element.classList.add(...capabilities);
}
}

View file

@ -1,13 +0,0 @@
export default (): void => {
if ('share' in navigator) {
document.body.classList.add('cap-web-share');
}
if ('serviceWorker' in navigator) {
document.body.classList.add('cap-service-worker');
}
if ('Notification' in window) {
document.body.classList.add('cap-notification');
}
}

View file

@ -6,6 +6,7 @@ import CharacterCountWarningController from "retrospring/controllers/character_c
import FormatPopupController from "retrospring/controllers/format_popup_controller";
import CollapseController from "retrospring/controllers/collapse_controller";
import ThemeController from "retrospring/controllers/theme_controller";
import CapabilitiesController from "retrospring/controllers/capabilities_controller";
/**
* This module sets up Stimulus and our controllers
@ -18,6 +19,7 @@ export default function (): void {
window['Stimulus'] = Application.start();
window['Stimulus'].register('announcement', AnnouncementController);
window['Stimulus'].register('autofocus', AutofocusController);
window['Stimulus'].register('capabilities', CapabilitiesController);
window['Stimulus'].register('character-count', CharacterCountController);
window['Stimulus'].register('character-count-warning', CharacterCountWarningController);
window['Stimulus'].register('collapse', CollapseController);

View file

@ -53,7 +53,7 @@ class User < ApplicationRecord # rubocop:disable Metrics/ClassLength
foreign_key: "banned_by_id",
dependent: :nullify
SCREEN_NAME_REGEX = /\A[a-zA-Z0-9_]{1,16}\z/
SCREEN_NAME_REGEX = /\A[a-zA-Z0-9_]+\z/
WEBSITE_REGEX = /https?:\/\/([A-Za-z.-]+)\/?(?:.*)/i
before_validation do
@ -61,7 +61,12 @@ class User < ApplicationRecord # rubocop:disable Metrics/ClassLength
end
validates :email, fake_email: true, typoed_email: true
validates :screen_name, presence: true, format: { with: SCREEN_NAME_REGEX }, uniqueness: { case_sensitive: false }, screen_name: true
validates :screen_name,
presence: true,
format: { with: SCREEN_NAME_REGEX, message: I18n.t("activerecord.validation.user.screen_name.format") },
length: { minimum: 1, maximum: 16 },
uniqueness: { case_sensitive: false },
screen_name: true
mount_uploader :profile_picture, ProfilePictureUploader, mount_on: :profile_picture_file_name
process_in_background :profile_picture

View file

@ -13,7 +13,7 @@
·
%a{ href: question_path(a.question.user.screen_name, a.question.id) }
= t(".answers", count: a.question.answer_count)
.answerbox__question-body{ data: { controller: "collapse" } }
.answerbox__question-body{ data: { controller: a.question.long? ? "collapse" : nil } }
.answerbox__question-text{ class: a.question.long? && !display_all ? "collapsed" : "", data: { collapse_target: "content" } }
= question_markdown a.question.content
- if a.question.long? && !display_all

View file

@ -3,7 +3,7 @@
- if @question.nil?
= render "answerbox/header", a: a, display_all: display_all
.card-body
.answerbox__answer-body{ data: { controller: "collapse" } }
.answerbox__answer-body{ data: { controller: a.long? ? "collapse" : nil } }
.answerbox__answer-text{ class: a.long? && !display_all ? "collapsed" : "", data: { collapse_target: "content" } }
= markdown a.content
- if a.long? && !display_all

View file

@ -14,7 +14,7 @@
·
%a{ href: question_path(i.question.user.screen_name, i.question.id) }
= t(".answers", count: i.question.answer_count)
.answerbox__question-body{ data: { controller: "collapse" } }
.answerbox__question-body{ data: { controller: i.question.long? ? "collapse" : nil } }
.answerbox__question-text{ class: i.question.long? ? "collapsed" : "", data: { collapse_target: "content" } }
= question_markdown i.question.content
- if i.question.long?

View file

@ -23,7 +23,7 @@
= csrf_meta_tags
= yield(:og)
= yield(:meta)
%body{ class: user_signed_in? ? '' : 'not-logged-in' }
%body{ class: user_signed_in? ? nil : 'not-logged-in', data: { controller: "capabilities" } }
- if user_signed_in?
= render 'navigation/main'
- else

View file

@ -8,12 +8,8 @@
icon: 'inbox', icon_only: true
- if APP_CONFIG.dig(:features, :discover, :enabled) || current_user.mod?
= nav_entry t("navigation.discover"), discover_path, icon: 'compass', icon_only: true
%li.nav-item
%a.nav-link{ href: '#', data: { bs_toggle: 'dropdown', bs_target: '#rs-mobile-nav-notifications' }, aria: { controls: 'rs-mobile-nav-notifications', expanded: 'false' } }
%i.fa{ class: "fa-#{notifications_icon}" }
%span.visually-hidden= t("navigation.notifications")
%span.badge.badge-pill.badge-primary= notification_count
= render 'navigation/dropdown/notifications', notifications: notifications, size: "mobile"
= nav_entry t("navigation.notifications"), notifications_path("all"), icon: notifications_icon,
badge: notification_count, badge_color: "primary", icon_only: true
%li.nav-item.profile--image-dropdown
%a.nav-link{ href: '#', data: { bs_toggle: 'dropdown', bs_target: '#rs-mobile-nav-profile' }, aria: { controls: 'rs-mobile-nav-profile', expanded: 'false' } }
%img.avatar-md.d-inline{ src: current_user.profile_picture.url(:small) }

View file

@ -13,7 +13,7 @@
= user_screen_name question.user, author_identifier: identifier, url: false
- else
= t("answerbox.header.asked_html", user: user_screen_name(question.user, author_identifier: identifier), time: time_tooltip(question))
.answerbox__question-body{ data: { controller: "collapse" } }
.answerbox__question-body{ data: { controller: question.long? ? "collapse" : nil } }
.answerbox__question-text{ class: question.long? ? "collapsed" : "", data: { collapse_target: "content" } }
= question_markdown question.content
- if question.long?

View file

@ -1,6 +1,6 @@
- type ||= nil
.card.questionbox{ data: { id: q.id } }
.card-body
.card-body{ data: { controller: q.long? ? "collapse" : nil } }
.d-flex
- if type == 'discover'
.flex-shrink-0
@ -13,8 +13,10 @@
·
%a{ href: question_path(q.user.screen_name, q.id) }
= pluralize(q.answer_count, t("voc.answer"))
.answerbox__question-text
.answerbox__question-text{ class: q.long? ? 'collapsed' : '', data: { collapse_target: "content" } }
= question_markdown q.content
- if q.long?
= render "shared/collapse", type: "question"
- if user_signed_in?
.flex-shrink-0.ms-auto
.btn-group

View file

@ -82,6 +82,7 @@ en:
updated_at: "Account updated at"
help:
user:
screen_name: "Alphanumerical and underscores allowed, max. 16 characters"
email: "Don't forget to check your spam folder in case our email might have landed there!"
current_password: "We need your current password to confirm your changes"
profile:
@ -95,6 +96,10 @@ en:
primary_color: "The primary/brand colour of the site, used for navigation, links, etc."
success_color: "Colour used for messages if something went through successfully."
warning_color: "Colour used for warnings if something non-critical has happened."
validation:
user:
screen_name:
format: "contains invalid characters"
helpers:
submit:
user:

View file

@ -2,6 +2,7 @@
"scripts": {
"lint": "yarn run eslint --ext .ts app/javascript",
"lint:fix": "yarn run eslint --ext .ts app/javascript --fix",
"lint:css": "yarn run stylelint \"app/assets/stylesheets/**/*.scss\"",
"build": "esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=assets",
"build:css": "sass ./app/assets/stylesheets/application.sass.scss:./app/assets/builds/application.css --no-source-map --load-path=node_modules"
},
@ -28,6 +29,9 @@
"@typescript-eslint/parser": "^4.11.0",
"esbuild": "^0.17.0",
"eslint": "^7.16.0",
"eslint-plugin-import": "^2.27.4"
"eslint-plugin-import": "^2.27.4",
"stylelint": "^14.16.1",
"stylelint-config-standard-scss": "^6.1.0",
"stylelint-scss": "^4.3.0"
}
}

687
yarn.lock

File diff suppressed because it is too large Load diff