diff --git a/app/assets/javascripts/wizard/components/theme-preview.js.es6 b/app/assets/javascripts/wizard/components/theme-preview.js.es6 index 23045e5675a..738be14f695 100644 --- a/app/assets/javascripts/wizard/components/theme-preview.js.es6 +++ b/app/assets/javascripts/wizard/components/theme-preview.js.es6 @@ -3,14 +3,18 @@ import { observes } from "ember-addons/ember-computed-decorators"; import { createPreviewComponent, darkLightDiff, - chooseBrighter, + chooseDarker, LOREM } from "wizard/lib/preview"; -export default createPreviewComponent(659, 320, { +export default createPreviewComponent(225, 120, { logo: null, avatar: null, + click() { + this.sendAction("onChange", this.get("colorsId")); + }, + @observes("step.fieldsById.base_scheme_id.value") themeChanged() { this.triggerRepaint(); @@ -24,19 +28,19 @@ export default createPreviewComponent(659, 320, { }, paint(ctx, colors, width, height) { - const headerHeight = height * 0.15; + const headerHeight = height * 0.3; this.drawFullHeader(colors); - const margin = width * 0.02; - const avatarSize = height * 0.1; - const lineHeight = height / 19.0; + const margin = width * 0.04; + const avatarSize = height * 0.2; + const lineHeight = height / 9.5; // Draw a fake topic this.scaleImage( this.avatar, margin, - headerHeight + height * 0.17, + headerHeight + height * 0.085, avatarSize, avatarSize ); @@ -46,33 +50,48 @@ export default createPreviewComponent(659, 320, { ctx.beginPath(); ctx.fillStyle = colors.primary; ctx.font = `bold ${titleFontSize}em 'Arial'`; - ctx.fillText("Welcome to Discourse", margin, height * 0.25); + ctx.fillText(I18n.t("wizard.previews.topic_title"), margin, height * 0.3); - const bodyFontSize = height / 440.0; + const bodyFontSize = height / 220.0; ctx.font = `${bodyFontSize}em 'Arial'`; let line = 0; const lines = LOREM.split("\n"); - for (let i = 0; i < 10; i++) { - line = height * 0.3 + i * lineHeight; + for (let i = 0; i < 4; i++) { + line = height * 0.35 + i * lineHeight; ctx.fillText(lines[i], margin + avatarSize + margin, line); } + // Share Button + ctx.beginPath(); + ctx.rect(margin, line + lineHeight, width * 0.14, height * 0.14); + ctx.fillStyle = darkLightDiff(colors.primary, colors.secondary, 90, 65); + ctx.fill(); + ctx.fillStyle = chooseDarker(colors.primary, colors.secondary); + ctx.font = `${bodyFontSize}em 'Arial'`; + ctx.fillText( + I18n.t("wizard.previews.share_button"), + margin + width / 55, + line + lineHeight * 1.85 + ); + // Reply Button ctx.beginPath(); - ctx.rect(width * 0.57, line + lineHeight, width * 0.1, height * 0.07); + ctx.rect( + margin * 2 + width * 0.14, + line + lineHeight, + width * 0.14, + height * 0.14 + ); ctx.fillStyle = colors.tertiary; ctx.fill(); - ctx.fillStyle = chooseBrighter(colors.primary, colors.secondary); + ctx.fillStyle = colors.secondary; ctx.font = `${bodyFontSize}em 'Arial'`; - ctx.fillText("Reply", width * 0.595, line + lineHeight * 1.85); - - // Icons - ctx.font = `${bodyFontSize}em FontAwesome`; - ctx.fillStyle = colors.love; - ctx.fillText("\uf004", width * 0.48, line + lineHeight * 1.8); - ctx.fillStyle = darkLightDiff(colors.primary, colors.secondary, 65, 55); - ctx.fillText("\uf040", width * 0.525, line + lineHeight * 1.8); + ctx.fillText( + I18n.t("wizard.previews.reply_button"), + margin * 2 + width * 0.14 + width / 55, + line + lineHeight * 1.85 + ); // Draw Timeline const timelineX = width * 0.8; @@ -80,7 +99,7 @@ export default createPreviewComponent(659, 320, { ctx.strokeStyle = colors.tertiary; ctx.lineWidth = 0.5; ctx.moveTo(timelineX, height * 0.3); - ctx.lineTo(timelineX, height * 0.6); + ctx.lineTo(timelineX, height * 0.7); ctx.stroke(); // Timeline diff --git a/app/assets/javascripts/wizard/components/theme-previews.js.es6 b/app/assets/javascripts/wizard/components/theme-previews.js.es6 new file mode 100644 index 00000000000..57c74ccab27 --- /dev/null +++ b/app/assets/javascripts/wizard/components/theme-previews.js.es6 @@ -0,0 +1,7 @@ +export default Ember.Component.extend({ + actions: { + changed(value) { + this.set("field.value", value); + } + } +}); diff --git a/app/assets/javascripts/wizard/lib/preview.js.es6 b/app/assets/javascripts/wizard/lib/preview.js.es6 index f3aee2439ac..887a72ba186 100644 --- a/app/assets/javascripts/wizard/lib/preview.js.es6 +++ b/app/assets/javascripts/wizard/lib/preview.js.es6 @@ -2,17 +2,14 @@ import getUrl from "discourse-common/lib/get-url"; export const LOREM = ` -Lorem ipsum dolor sit amet, consectetur adipiscing elit. -Nullam eget sem non elit tincidunt rhoncus. Fusce velit nisl, -porttitor sed nisl ac, consectetur interdum metus. Fusce in -consequat augue, vel facilisis felis. Nunc tellus elit, and -semper vitae orci nec, blandit pharetra enim. Aenean a ebus -posuere nunc. Maecenas ultrices viverra enim ac commodo -Vestibulum nec quam sit amet libero ultricies sollicitudin. -Nulla quis scelerisque sem, eget volutpat velit. Fusce eget -accumsan sapien, nec feugiat quam. Quisque non risus. -placerat lacus vitae, lacinia nisi. Sed metus arcu, iaculis -sit amet cursus nec, sodales at eros.`; +Lorem ipsum dolor sit amet, +consectetur adipiscing elit. +Nullam eget sem non elit +tincidunt rhoncus. Fusce +velit nisl, porttitor sed +nisl ac, consectetur interdum +metus. Fusce in consequat +augue, vel facilisis felis.`; const scaled = {}; @@ -75,7 +72,9 @@ export function createPreviewComponent(width, height, obj) { return false; } - const colors = this.get("wizard").getCurrentColors(); + const colors = this.get("wizard").getCurrentColors( + this.get("colorsId") + ); if (!colors) { return; } @@ -137,16 +136,10 @@ export function createPreviewComponent(width, height, obj) { const headerMargin = headerHeight * 0.2; const logoHeight = headerHeight - headerMargin * 2; - if (this.logo) { - const logoWidth = (logoHeight / this.logo.height) * this.logo.width; - this.scaleImage( - this.logo, - headerMargin, - headerMargin, - logoWidth, - logoHeight - ); - } + ctx.beginPath(); + ctx.fillStyle = colors.header_primary; + ctx.font = `bold ${logoHeight}px 'Arial'`; + ctx.fillText("Discourse", headerMargin, headerHeight - headerMargin); // Top right menu this.scaleImage( @@ -370,6 +363,14 @@ export function chooseBrighter(primary, secondary) { : primary; } +export function chooseDarker(primary, secondary) { + if (chooseBrighter(primary, secondary) === primary) { + return secondary; + } else { + return primary; + } +} + export function darkLightDiff(adjusted, comparison, lightness, darkness) { const adjustedCol = parseColor(adjusted); const comparisonCol = parseColor(comparison); diff --git a/app/assets/javascripts/wizard/models/wizard.js.es6 b/app/assets/javascripts/wizard/models/wizard.js.es6 index 28dc9f02973..95fa48bfb03 100644 --- a/app/assets/javascripts/wizard/models/wizard.js.es6 +++ b/app/assets/javascripts/wizard/models/wizard.js.es6 @@ -23,18 +23,18 @@ const Wizard = Ember.Object.extend({ }, // A bit clunky, but get the current colors from the appropriate step - getCurrentColors() { + getCurrentColors(schemeId) { const colorStep = this.get("steps").findBy("id", "colors"); if (!colorStep) { return; } - const themeChoice = colorStep.get("fieldsById.base_scheme_id"); + const themeChoice = colorStep.get("fieldsById.theme_previews"); if (!themeChoice) { return; } - const themeId = themeChoice.get("value"); + const themeId = schemeId ? schemeId : themeChoice.get("value"); if (!themeId) { return; } diff --git a/app/assets/javascripts/wizard/templates/components/theme-previews.hbs b/app/assets/javascripts/wizard/templates/components/theme-previews.hbs new file mode 100644 index 00000000000..34e5ea8e32f --- /dev/null +++ b/app/assets/javascripts/wizard/templates/components/theme-previews.hbs @@ -0,0 +1,13 @@ + diff --git a/app/assets/stylesheets/wizard.scss b/app/assets/stylesheets/wizard.scss index ef006c48d1a..ce145bb11b3 100644 --- a/app/assets/stylesheets/wizard.scss +++ b/app/assets/stylesheets/wizard.scss @@ -40,7 +40,9 @@ body.wizard { } .wizard-warning { - font-family: sans-serif, p { + font-family: sans-serif; + + p { margin-top: 0; } @@ -71,6 +73,11 @@ body.wizard { font-weight: bold; } +.wizard-step-form { + max-height: 500px; + overflow-y: auto; +} + .wizard-step-emoji { .radio-area { display: flex; @@ -106,6 +113,29 @@ body.wizard { } } +.wizard-step-colors { + .grid { + margin: 0 auto; + list-style-type: none; + text-align: center; + + li { + display: inline-block; + vertical-align: top; + margin: 15px; + .radio-area { + text-align: left; + font-size: 14px; + font-weight: bold; + & > * { + position: relative; + right: 7px; + } + } + } + } +} + .wizard-column { position: relative; z-index: 11; @@ -483,6 +513,9 @@ body.wizard { .wizard-column { margin: auto !important; } + .wizard-step-form { + max-height: auto; + } .wizard-step-contents { min-height: auto !important; } diff --git a/app/models/color_scheme.rb b/app/models/color_scheme.rb index d03b865c7ea..22dcd2c92fe 100644 --- a/app/models/color_scheme.rb +++ b/app/models/color_scheme.rb @@ -5,7 +5,7 @@ require_dependency 'distributed_cache' class ColorScheme < ActiveRecord::Base CUSTOM_SCHEMES = { - dark: { + 'Dark': { "primary" => 'dddddd', "secondary" => '222222', "tertiary" => '0f82af', @@ -16,6 +16,84 @@ class ColorScheme < ActiveRecord::Base "danger" => 'e45735', "success" => '1ca551', "love" => 'fa6c8d' + }, + # By @itsbhanusharma + 'Neutral': { + "primary" => '000000', + "secondary" => 'ffffff', + "tertiary" => '51839b', + "quaternary" => 'b85e48', + "header_background" => '333333', + "header_primary" => 'f3f3f3', + "highlight" => 'ecec70', + "danger" => 'b85e48', + "success" => '518751', + "love" => 'fa6c8d' + }, + # By @Flower_Child + 'Grey Amber': { + "primary" => 'd9d9d9', + "secondary" => '3d4147', + "tertiary" => 'fdd459', + "quaternary" => 'fdd459', + "header_background" => '36393e', + "header_primary" => 'd9d9d9', + "highlight" => 'fdd459', + "danger" => 'e45735', + "success" => 'fdd459', + "love" => 'fdd459' + }, + # By @awesomerobot + 'Shades of Blue': { + "primary" => '203243', + "secondary" => 'eef4f7', + "tertiary" => '416376', + "quaternary" => '5e99b9', + "header_background" => '86bddb', + "header_primary" => 'ffffff', + "highlight" => '86bddb', + "danger" => 'bf3c3c', + "success" => '70db82', + "love" => 'fc94cb' + }, + # By @mikechristopher + 'Latte': { + "primary" => 'f2e507', + "secondary" => '262322', + "tertiary" => 'f7f2ed', + "quaternary" => 'd7c9aa', + "header_background" => 'd7c9aa', + "header_primary" => '262322', + "highlight" => 'd7c9aa', + "danger" => 'db9584', + "success" => '78be78', + "love" => '8f6201' + }, + # By @Flower_Child + 'Summer': { + "primary" => '874342', + "secondary" => 'fffff4', + "tertiary" => 'fe9896', + "quaternary" => 'fcc9d0', + "header_background" => '96ccbf', + "header_primary" => 'fff1e7', + "highlight" => 'f3c07f', + "danger" => 'cfebdc', + "success" => 'fcb4b5', + "love" => 'f3c07f' + }, + # By @Flower_Child + 'Dark Rose': { + "primary" => 'ca9cb2', + "secondary" => '3a2a37', + "tertiary" => 'fdd459', + "quaternary" => '7e566a', + "header_background" => 'a97189', + "header_primary" => 'd9b2bb', + "highlight" => '6c3e63', + "danger" => '6c3e63', + "success" => 'd9b2bb', + "love" => 'd9b2bb' } } @@ -26,7 +104,7 @@ class ColorScheme < ActiveRecord::Base end list = [ - { id: 'default', colors: base_with_hash } + { id: 'Light', colors: base_with_hash } ] CUSTOM_SCHEMES.each do |k, v| @@ -71,7 +149,7 @@ class ColorScheme < ActiveRecord::Base def self.base_color_schemes base_color_scheme_colors.map do |hash| - scheme = new(name: I18n.t("color_schemes.#{hash[:id]}"), base_scheme_id: hash[:id]) + scheme = new(name: I18n.t("color_schemes.#{hash[:id].downcase.gsub(' ', '_')}"), base_scheme_id: hash[:id]) scheme.colors = hash[:colors].map { |k, v| { name: k.to_s, hex: v.sub("#", "") } } scheme.is_base = true scheme @@ -140,7 +218,7 @@ class ColorScheme < ActiveRecord::Base def base_colors colors = nil - if base_scheme_id && base_scheme_id != "default" + if base_scheme_id && base_scheme_id != "Light" colors = CUSTOM_SCHEMES[base_scheme_id.to_sym] end colors || ColorScheme.base_colors @@ -148,7 +226,7 @@ class ColorScheme < ActiveRecord::Base def resolved_colors resolved = ColorScheme.base_colors.dup - if base_scheme_id && base_scheme_id != "default" + if base_scheme_id && base_scheme_id != "Light" if scheme = CUSTOM_SCHEMES[base_scheme_id.to_sym] scheme.each do |name, value| resolved[name] = value diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 111713f7735..edb33eda8f0 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -3995,3 +3995,8 @@ en: admin: "Admin" moderator: "Moderator" regular: "Regular User" + + previews: + topic_title: "Discussion topic" + share_button: "Share" + reply_button: "Reply" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 2e07af6bd18..7ec50e083a7 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -3185,11 +3185,23 @@ en: color_schemes: base_theme_name: "Base" - default: "Light Scheme" + light: "Light Scheme" dark: "Dark Scheme" - default_theme_name: "Default" - dark_theme_name: "Dark" + neutral: "Neutral Scheme" + grey_amber: "Grey Amber Scheme" + shades_of_blue: "Shades of Blue Scheme" + latte: "Latte Scheme" + summer: "Summer Scheme" + dark_rose: "Dark Rose Scheme" + default_theme_name: "Light" light_theme_name: "Light" + dark_theme_name: "Dark" + neutral_theme_name: "Neutral" + grey_amber_theme_name: "Grey Amber" + shades_of_blue_theme_name: "Shades of Blue" + latte_theme_name: "Latte" + summer_theme_name: "Summer" + dark_rose_theme_name: "Dark Rose" about: "About" guidelines: "Guidelines" diff --git a/db/fixtures/600_themes.rb b/db/fixtures/600_themes.rb index 0575e1ea29d..be8ee222a84 100644 --- a/db/fixtures/600_themes.rb +++ b/db/fixtures/600_themes.rb @@ -2,9 +2,9 @@ if !Theme.exists? STDERR.puts "> Seeding dark and light themes" - name = I18n.t("wizard.step.colors.fields.theme_id.choices.dark.label") - dark_scheme = ColorScheme.find_by(base_scheme_id: "dark") - dark_scheme ||= ColorScheme.create_from_base(name: name, via_wizard: true, base_scheme_id: "dark") + name = I18n.t("color_schemes.dark_theme_name") + dark_scheme = ColorScheme.find_by(base_scheme_id: "Dark") + dark_scheme ||= ColorScheme.create_from_base(name: name, via_wizard: true, base_scheme_id: "Dark") name = I18n.t('color_schemes.dark_theme_name') _dark_theme = Theme.create(name: name, user_id: -1, diff --git a/lib/wizard/builder.rb b/lib/wizard/builder.rb index eb5f7d04b1e..1d7a2e5a4b0 100644 --- a/lib/wizard/builder.rb +++ b/lib/wizard/builder.rb @@ -118,39 +118,27 @@ class Wizard @wizard.append_step('colors') do |step| default_theme = Theme.find_by(id: SiteSetting.default_theme_id) - scheme_id = default_theme&.color_scheme&.base_scheme_id || 'default' + scheme_id = default_theme&.color_scheme&.base_scheme_id || 'Light' - themes = step.add_field(id: 'base_scheme_id', type: 'dropdown', required: true, value: scheme_id) + themes = step.add_field(id: 'theme_previews', type: 'component', required: true, value: scheme_id) ColorScheme.base_color_scheme_colors.each do |t| with_hash = t[:colors].dup with_hash.map { |k, v| with_hash[k] = "##{v}" } themes.add_choice(t[:id], data: { colors: with_hash }) end - step.add_field(id: 'theme_preview', type: 'component') step.on_update do |updater| - scheme_name = updater.fields[:base_scheme_id] + scheme_name = updater.fields[:theme_previews] || 'Light' + name = I18n.t("color_schemes.#{scheme_name.downcase.gsub(' ', '_')}_theme_name") theme = nil + scheme = ColorScheme.find_by(base_scheme_id: scheme_name, via_wizard: true) + scheme ||= ColorScheme.create_from_base(name: name, via_wizard: true, base_scheme_id: scheme_name) + themes = Theme.where(color_scheme_id: scheme.id).order(:id).to_a + theme = themes.find(&:default?) + theme ||= themes.first - if scheme_name == "dark" - scheme = ColorScheme.find_by(base_scheme_id: 'dark', via_wizard: true) - - name = I18n.t("wizard.step.colors.fields.theme_id.choices.dark.label") - scheme ||= ColorScheme.create_from_base(name: name, via_wizard: true, base_scheme_id: "dark") - - theme = Theme.find_by(color_scheme_id: scheme.id) - name = I18n.t('color_schemes.dark_theme_name') - theme ||= Theme.create(name: name, color_scheme_id: scheme.id, user_id: @wizard.user.id) - else - themes = Theme.where(color_scheme_id: nil).order(:id).to_a - theme = themes.find(&:default?) - theme ||= themes.first - - name = I18n.t('color_schemes.light_theme_name') - theme ||= Theme.create(name: name, user_id: @wizard.user.id) - end - + theme ||= Theme.create(name: name, user_id: @wizard.user.id, color_scheme_id: scheme.id) theme.set_default! end end diff --git a/spec/components/wizard/step_updater_spec.rb b/spec/components/wizard/step_updater_spec.rb index d10c2120e9e..0a858c8b888 100644 --- a/spec/components/wizard/step_updater_spec.rb +++ b/spec/components/wizard/step_updater_spec.rb @@ -151,12 +151,12 @@ describe Wizard::StepUpdater do let!(:color_scheme) { Fabricate(:color_scheme, name: 'existing', via_wizard: true) } it "updates the scheme" do - updater = wizard.create_updater('colors', base_scheme_id: 'dark') + updater = wizard.create_updater('colors', theme_previews: 'Dark') updater.update expect(updater.success?).to eq(true) expect(wizard.completed_steps?('colors')).to eq(true) theme = Theme.find_by(id: SiteSetting.default_theme_id) - expect(theme.color_scheme.base_scheme_id).to eq('dark') + expect(theme.color_scheme.base_scheme_id).to eq('Dark') end end @@ -167,14 +167,14 @@ describe Wizard::StepUpdater do context 'dark theme' do it "creates the theme" do - updater = wizard.create_updater('colors', base_scheme_id: 'dark', allow_dark_light_selection: true) + updater = wizard.create_updater('colors', theme_previews: 'Dark', allow_dark_light_selection: true) expect { updater.update }.to change { Theme.count }.by(1) theme = Theme.last expect(theme.user_id).to eq(wizard.user.id) - expect(theme.color_scheme.base_scheme_id).to eq('dark') + expect(theme.color_scheme.base_scheme_id).to eq('Dark') end end @@ -187,14 +187,14 @@ describe Wizard::StepUpdater do theme = Theme.last expect(theme.user_id).to eq(wizard.user.id) - expect(theme.color_scheme).to eq(nil) + expect(theme.color_scheme).to eq(ColorScheme.find_by(name: 'Light')) end end end context "without an existing scheme" do it "creates the scheme" do - updater = wizard.create_updater('colors', base_scheme_id: 'dark', allow_dark_light_selection: true) + updater = wizard.create_updater('colors', theme_previews: 'Dark', allow_dark_light_selection: true) updater.update expect(updater.success?).to eq(true) expect(wizard.completed_steps?('colors')).to eq(true)