UX: Lots of wizard canvas rendering improvements
* Make sure bold body font loads before rendering otherwise the 1/20 post count on the timeline will use wrong font * Fix pill button rendering on homepage preview, now all the widths resize based on the font size/width and all buttons depend on the X position of the button beforehand * Fix the table header labels overlapping by giving them more room based on col position * Moving hardcoded label text into I18n
This commit is contained in:
parent
9c6e5440d8
commit
7c92402e15
|
@ -83,7 +83,7 @@ export default class HomepagePreview extends PreviewBaseComponent {
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.font = `Bold ${bodyFontSize * 1.3}em '${font}'`;
|
ctx.font = `700 ${bodyFontSize * 1.3}em '${font}'`;
|
||||||
ctx.fillStyle = colors.primary;
|
ctx.fillStyle = colors.primary;
|
||||||
ctx.textAlign = "center";
|
ctx.textAlign = "center";
|
||||||
ctx.fillText(category.name, boxStartX + boxWidth / 2, boxStartY + 25);
|
ctx.fillText(category.name, boxStartX + boxWidth / 2, boxStartY + 25);
|
||||||
|
@ -166,7 +166,7 @@ export default class HomepagePreview extends PreviewBaseComponent {
|
||||||
// Categories
|
// Categories
|
||||||
this.categories().forEach((category, idx) => {
|
this.categories().forEach((category, idx) => {
|
||||||
const textPos = y + categoryHeight * 0.35;
|
const textPos = y + categoryHeight * 0.35;
|
||||||
ctx.font = `Bold ${bodyFontSize * 1.1}em '${font}'`;
|
ctx.font = `700 ${bodyFontSize * 1.1}em '${font}'`;
|
||||||
ctx.fillStyle = colors.primary;
|
ctx.fillStyle = colors.primary;
|
||||||
ctx.fillText(category.name, cols[0], textPos);
|
ctx.fillText(category.name, cols[0], textPos);
|
||||||
|
|
||||||
|
@ -262,7 +262,7 @@ export default class HomepagePreview extends PreviewBaseComponent {
|
||||||
// Categories
|
// Categories
|
||||||
this.categories().forEach((category, idx) => {
|
this.categories().forEach((category, idx) => {
|
||||||
const textPos = y + categoryHeight * 0.35;
|
const textPos = y + categoryHeight * 0.35;
|
||||||
ctx.font = `Bold ${bodyFontSize * 1.1}em '${font}'`;
|
ctx.font = `700 ${bodyFontSize * 1.1}em '${font}'`;
|
||||||
ctx.fillStyle = colors.primary;
|
ctx.fillStyle = colors.primary;
|
||||||
ctx.fillText(category.name, cols[0], textPos);
|
ctx.fillText(category.name, cols[0], textPos);
|
||||||
|
|
||||||
|
@ -310,7 +310,7 @@ export default class HomepagePreview extends PreviewBaseComponent {
|
||||||
);
|
);
|
||||||
ctx.fillText(title, cols[3], textPos);
|
ctx.fillText(title, cols[3], textPos);
|
||||||
|
|
||||||
ctx.font = `Bold ${bodyFontSize}em '${font}'`;
|
ctx.font = `700 ${bodyFontSize}em '${font}'`;
|
||||||
ctx.fillText(Math.floor(Math.random() * 90) + 10, cols[4], textPos);
|
ctx.fillText(Math.floor(Math.random() * 90) + 10, cols[4], textPos);
|
||||||
ctx.font = `${bodyFontSize}em '${font}'`;
|
ctx.font = `${bodyFontSize}em '${font}'`;
|
||||||
ctx.fillText(`1h`, cols[4], textPos + topicHeight * 0.4);
|
ctx.fillText(`1h`, cols[4], textPos + topicHeight * 0.4);
|
||||||
|
@ -318,7 +318,7 @@ export default class HomepagePreview extends PreviewBaseComponent {
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.fillStyle = category.color;
|
ctx.fillStyle = category.color;
|
||||||
const badgeSize = topicHeight * 0.1;
|
const badgeSize = topicHeight * 0.1;
|
||||||
ctx.font = `Bold ${bodyFontSize * 0.5}em '${font}'`;
|
ctx.font = `700 ${bodyFontSize * 0.5}em '${font}'`;
|
||||||
ctx.rect(
|
ctx.rect(
|
||||||
cols[3] + margin * 0.25,
|
cols[3] + margin * 0.25,
|
||||||
y + topicHeight * 0.65,
|
y + topicHeight * 0.65,
|
||||||
|
@ -383,17 +383,33 @@ export default class HomepagePreview extends PreviewBaseComponent {
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
};
|
};
|
||||||
|
|
||||||
const cols = [0.02, 0.66, 0.8, 0.87, 0.93].map((c) => c * width);
|
const cols = [0.02, 0.66, 0.75, 0.83, 0.9].map((c) => c * width);
|
||||||
|
|
||||||
// Headings
|
// Headings
|
||||||
const headingY = height * 0.33;
|
const headingY = height * 0.33;
|
||||||
|
|
||||||
ctx.fillStyle = textColor;
|
ctx.fillStyle = textColor;
|
||||||
ctx.font = `${bodyFontSize * 0.9}em '${font}'`;
|
ctx.font = `${bodyFontSize * 0.9}em '${font}'`;
|
||||||
ctx.fillText("Topic", cols[0], headingY);
|
ctx.fillText(
|
||||||
ctx.fillText("Replies", cols[2], headingY);
|
i18n("wizard.homepage_preview.table_headers.topic"),
|
||||||
ctx.fillText("Views", cols[3], headingY);
|
cols[0],
|
||||||
ctx.fillText("Activity", cols[4], headingY);
|
headingY
|
||||||
|
);
|
||||||
|
ctx.fillText(
|
||||||
|
i18n("wizard.homepage_preview.table_headers.replies"),
|
||||||
|
cols[2],
|
||||||
|
headingY
|
||||||
|
);
|
||||||
|
ctx.fillText(
|
||||||
|
i18n("wizard.homepage_preview.table_headers.views"),
|
||||||
|
cols[3],
|
||||||
|
headingY
|
||||||
|
);
|
||||||
|
ctx.fillText(
|
||||||
|
i18n("wizard.homepage_preview.table_headers.activity"),
|
||||||
|
cols[4],
|
||||||
|
headingY
|
||||||
|
);
|
||||||
|
|
||||||
// Topics
|
// Topics
|
||||||
let y = headingY + rowHeight / 2.6;
|
let y = headingY + rowHeight / 2.6;
|
||||||
|
@ -412,7 +428,7 @@ export default class HomepagePreview extends PreviewBaseComponent {
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.fillStyle = category.color;
|
ctx.fillStyle = category.color;
|
||||||
const badgeSize = rowHeight * 0.15;
|
const badgeSize = rowHeight * 0.15;
|
||||||
ctx.font = `Bold ${bodyFontSize * 0.75}em '${font}'`;
|
ctx.font = `700 ${bodyFontSize * 0.75}em '${font}'`;
|
||||||
ctx.rect(cols[0] + 4, y + rowHeight * 0.6, badgeSize, badgeSize);
|
ctx.rect(cols[0] + 4, y + rowHeight * 0.6, badgeSize, badgeSize);
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,7 @@ export default class PreviewBase extends Component {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all(
|
return Promise.all(
|
||||||
fontFaces.map((fontFace) =>
|
fontFaces.map((fontFace) =>
|
||||||
fontFace.load().then((loadedFont) => {
|
fontFace.load().then((loadedFont) => {
|
||||||
document.fonts.add(loadedFont);
|
document.fonts.add(loadedFont);
|
||||||
|
@ -135,7 +135,7 @@ export default class PreviewBase extends Component {
|
||||||
this.loadingFontVariants = false;
|
this.loadingFontVariants = false;
|
||||||
});
|
});
|
||||||
} else if (this.loadedFonts.has(font.id)) {
|
} else if (this.loadedFonts.has(font.id)) {
|
||||||
this.triggerRepaint();
|
return Promise.resolve(this.triggerRepaint());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,8 +162,14 @@ export default class PreviewBase extends Component {
|
||||||
|
|
||||||
reload() {
|
reload() {
|
||||||
Promise.all([this.loadFonts(), this.loadImages()]).then(() => {
|
Promise.all([this.loadFonts(), this.loadImages()]).then(() => {
|
||||||
this.loaded = true;
|
// NOTE: This must be done otherwise the "bold" variant of the body font
|
||||||
this.triggerRepaint();
|
// will not be loaded for some reason before rendering the canvas.
|
||||||
|
//
|
||||||
|
// The header font does not suffer from this issue.
|
||||||
|
this.loadFontVariants(this.wizard.font).then(() => {
|
||||||
|
this.loaded = true;
|
||||||
|
this.triggerRepaint();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,17 +289,16 @@ export default class PreviewBase extends Component {
|
||||||
avatarSize,
|
avatarSize,
|
||||||
avatarSize
|
avatarSize
|
||||||
);
|
);
|
||||||
|
|
||||||
// accounts for hard-set color variables in solarized themes
|
// accounts for hard-set color variables in solarized themes
|
||||||
ctx.fillStyle =
|
ctx.fillStyle =
|
||||||
colors.primary_low_mid ||
|
colors.primary_low_mid ||
|
||||||
darkLightDiff(colors.primary, colors.secondary, 45, 55);
|
darkLightDiff(colors.primary, colors.secondary, 45, 55);
|
||||||
|
|
||||||
const pathScale = this.headerHeight / 1200;
|
const pathScale = this.headerHeight / 1200;
|
||||||
// search icon SVG path
|
|
||||||
const searchIcon = new Path2D(
|
const searchIcon = new Path2D(
|
||||||
"M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"
|
"M505 442.7L405.3 343c-4.5-4.5-10.6-7-17-7H372c27.6-35.3 44-79.7 44-128C416 93.1 322.9 0 208 0S0 93.1 0 208s93.1 208 208 208c48.3 0 92.7-16.4 128-44v16.3c0 6.4 2.5 12.5 7 17l99.7 99.7c9.4 9.4 24.6 9.4 33.9 0l28.3-28.3c9.4-9.4 9.4-24.6.1-34zM208 336c-70.7 0-128-57.2-128-128 0-70.7 57.2-128 128-128 70.7 0 128 57.2 128 128 0 70.7-57.2 128-128 128z"
|
||||||
);
|
);
|
||||||
// hamburger icon
|
|
||||||
const hamburgerIcon = new Path2D(
|
const hamburgerIcon = new Path2D(
|
||||||
"M16 132h416c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H16C7.163 60 0 67.163 0 76v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z"
|
"M16 132h416c8.837 0 16-7.163 16-16V76c0-8.837-7.163-16-16-16H16C7.163 60 0 67.163 0 76v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16zm0 160h416c8.837 0 16-7.163 16-16v-40c0-8.837-7.163-16-16-16H16c-8.837 0-16 7.163-16 16v40c0 8.837 7.163 16 16 16z"
|
||||||
);
|
);
|
||||||
|
@ -321,100 +326,100 @@ export default class PreviewBase extends Component {
|
||||||
|
|
||||||
const { ctx } = this;
|
const { ctx } = this;
|
||||||
|
|
||||||
const categoriesSize = headerHeight * 2;
|
const badgeHeight = headerHeight * 2 * 0.25;
|
||||||
const badgeHeight = categoriesSize * 0.25;
|
|
||||||
const headerMargin = headerHeight * 0.2;
|
const headerMargin = headerHeight * 0.2;
|
||||||
|
const fontSize = Math.round(badgeHeight * 0.5);
|
||||||
|
ctx.font = `${fontSize}px '${font}'`;
|
||||||
|
|
||||||
|
const allCategoriesText = i18n(
|
||||||
|
"wizard.homepage_preview.nav_buttons.all_categories"
|
||||||
|
);
|
||||||
|
const categoriesWidth = ctx.measureText(allCategoriesText).width;
|
||||||
|
const categoriesBoxWidth = categoriesWidth + headerMargin * 2;
|
||||||
|
|
||||||
|
// Box around "all categories >"
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.strokeStyle = colors.primary;
|
ctx.strokeStyle = colors.primary;
|
||||||
ctx.lineWidth = 0.5;
|
ctx.lineWidth = 0.5;
|
||||||
ctx.rect(
|
ctx.rect(
|
||||||
headerMargin,
|
headerMargin,
|
||||||
headerHeight + headerMargin,
|
headerHeight + headerMargin,
|
||||||
categoriesSize,
|
categoriesBoxWidth,
|
||||||
badgeHeight
|
badgeHeight
|
||||||
);
|
);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
|
||||||
const fontSize = Math.round(badgeHeight * 0.5);
|
|
||||||
|
|
||||||
ctx.font = `${fontSize}px '${font}'`;
|
|
||||||
ctx.fillStyle = colors.primary;
|
ctx.fillStyle = colors.primary;
|
||||||
ctx.fillText(
|
ctx.fillText(
|
||||||
"all categories",
|
allCategoriesText,
|
||||||
headerMargin * 1.5,
|
headerMargin * 1.5,
|
||||||
headerHeight + headerMargin * 1.4 + fontSize
|
headerHeight + headerMargin * 1.4 + fontSize
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Caret (>) at the end of "all categories" box
|
||||||
const pathScale = badgeHeight / 1000;
|
const pathScale = badgeHeight / 1000;
|
||||||
// caret icon
|
|
||||||
const caretIcon = new Path2D(
|
const caretIcon = new Path2D(
|
||||||
"M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"
|
"M0 384.662V127.338c0-17.818 21.543-26.741 34.142-14.142l128.662 128.662c7.81 7.81 7.81 20.474 0 28.284L34.142 398.804C21.543 411.404 0 402.48 0 384.662z"
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.translate(
|
ctx.translate(
|
||||||
categoriesSize - headerMargin / 4,
|
categoriesBoxWidth,
|
||||||
headerHeight + headerMargin + badgeHeight / 4
|
headerHeight + headerMargin + badgeHeight / 4
|
||||||
);
|
);
|
||||||
ctx.scale(pathScale, pathScale);
|
ctx.scale(pathScale, pathScale);
|
||||||
ctx.fill(caretIcon);
|
ctx.fill(caretIcon);
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
|
|
||||||
const text = opts.categories ? "Categories" : "Latest";
|
// First top menu item
|
||||||
|
const firstTopMenuItemText = opts.categories
|
||||||
|
? i18n("wizard.homepage_preview.nav_buttons.categories")
|
||||||
|
: i18n("wizard.homepage_preview.nav_buttons.latest");
|
||||||
|
const newText = i18n("wizard.homepage_preview.nav_buttons.new");
|
||||||
|
const unreadText = i18n("wizard.homepage_preview.nav_buttons.unread");
|
||||||
|
const topText = i18n("wizard.homepage_preview.nav_buttons.top");
|
||||||
|
const hotText = i18n("wizard.homepage_preview.nav_buttons.hot");
|
||||||
|
|
||||||
const activeWidth = categoriesSize * (opts.categories ? 0.8 : 0.55);
|
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.fillStyle = colors.tertiary;
|
ctx.fillStyle = colors.tertiary;
|
||||||
ctx.rect(
|
ctx.rect(
|
||||||
headerMargin * 2 + categoriesSize,
|
categoriesBoxWidth + headerMargin * 2,
|
||||||
headerHeight + headerMargin,
|
headerHeight + headerMargin,
|
||||||
activeWidth,
|
ctx.measureText(firstTopMenuItemText).width + headerMargin * 2,
|
||||||
badgeHeight
|
badgeHeight
|
||||||
);
|
);
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
|
|
||||||
ctx.font = `${fontSize}px '${font}'`;
|
ctx.font = `${fontSize}px '${font}'`;
|
||||||
ctx.fillStyle = colors.secondary;
|
ctx.fillStyle = colors.secondary;
|
||||||
let x = headerMargin * 3.0 + categoriesSize;
|
const pillButtonTextY = headerHeight + headerMargin * 1.4 + fontSize;
|
||||||
|
const firstTopMenuItemX = headerMargin * 3.0 + categoriesBoxWidth;
|
||||||
ctx.fillText(
|
ctx.fillText(
|
||||||
text,
|
firstTopMenuItemText,
|
||||||
x - headerMargin * 0.1,
|
firstTopMenuItemX,
|
||||||
headerHeight + headerMargin * 1.5 + fontSize
|
pillButtonTextY,
|
||||||
|
ctx.measureText(firstTopMenuItemText).width
|
||||||
);
|
);
|
||||||
|
|
||||||
ctx.fillStyle = colors.primary;
|
ctx.fillStyle = colors.primary;
|
||||||
x += categoriesSize * (opts.categories ? 0.8 : 0.6);
|
|
||||||
ctx.fillText("New", x, headerHeight + headerMargin * 1.5 + fontSize);
|
|
||||||
|
|
||||||
x += categoriesSize * 0.4;
|
const newTextX =
|
||||||
ctx.fillText("Unread", x, headerHeight + headerMargin * 1.5 + fontSize);
|
firstTopMenuItemX +
|
||||||
|
ctx.measureText(firstTopMenuItemText).width +
|
||||||
|
headerMargin * 2.0;
|
||||||
|
ctx.fillText(newText, newTextX, pillButtonTextY);
|
||||||
|
|
||||||
x += categoriesSize * 0.6;
|
const unreadTextX =
|
||||||
ctx.fillText("Top", x, headerHeight + headerMargin * 1.5 + fontSize);
|
newTextX + ctx.measureText(newText).width + headerMargin * 2.0;
|
||||||
}
|
ctx.fillText(unreadText, unreadTextX, pillButtonTextY);
|
||||||
|
|
||||||
resizeTextLinesToFitRect(
|
const topTextX =
|
||||||
textLines,
|
unreadTextX + ctx.measureText(unreadText).width + headerMargin * 2.0;
|
||||||
rectWidth,
|
ctx.fillText(topText, topTextX, pillButtonTextY);
|
||||||
ctx,
|
|
||||||
fontSize,
|
|
||||||
font,
|
|
||||||
renderCallback
|
|
||||||
) {
|
|
||||||
const maxLengthLine = textLines.reduce((a, b) =>
|
|
||||||
a.length > b.length ? a : b
|
|
||||||
);
|
|
||||||
|
|
||||||
let fontSizeDecreaseMultiplier = 1;
|
const hotTextX =
|
||||||
while (ctx.measureText(maxLengthLine).width > rectWidth) {
|
topTextX + ctx.measureText(topText).width + headerMargin * 2.0;
|
||||||
fontSizeDecreaseMultiplier -= 0.1;
|
ctx.fillText(hotText, hotTextX, pillButtonTextY);
|
||||||
ctx.font = `${fontSize * fontSizeDecreaseMultiplier}em '${font}'`;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < textLines.length; i++) {
|
|
||||||
renderCallback(textLines[i], i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,11 @@ import { action } from "@ember/object";
|
||||||
import { observes } from "@ember-decorators/object";
|
import { observes } from "@ember-decorators/object";
|
||||||
import { bind } from "discourse-common/utils/decorators";
|
import { bind } from "discourse-common/utils/decorators";
|
||||||
import { i18n } from "discourse-i18n";
|
import { i18n } from "discourse-i18n";
|
||||||
import { chooseDarker, darkLightDiff } from "../../../lib/preview";
|
import {
|
||||||
|
chooseDarker,
|
||||||
|
darkLightDiff,
|
||||||
|
resizeTextLinesToFitRect,
|
||||||
|
} from "../../../lib/preview";
|
||||||
import HomepagePreview from "./-homepage-preview";
|
import HomepagePreview from "./-homepage-preview";
|
||||||
import PreviewBaseComponent from "./-preview-base";
|
import PreviewBaseComponent from "./-preview-base";
|
||||||
|
|
||||||
|
@ -133,7 +137,7 @@ export default class Index extends PreviewBaseComponent {
|
||||||
// Topic title
|
// Topic title
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.fillStyle = colors.primary;
|
ctx.fillStyle = colors.primary;
|
||||||
ctx.font = `bold ${titleFontSize}em '${headingFont}'`;
|
ctx.font = `700 ${titleFontSize}em '${headingFont}'`;
|
||||||
ctx.fillText(i18n("wizard.previews.topic_title"), margin, height * 0.3);
|
ctx.fillText(i18n("wizard.previews.topic_title"), margin, height * 0.3);
|
||||||
|
|
||||||
// Topic OP text
|
// Topic OP text
|
||||||
|
@ -144,7 +148,7 @@ export default class Index extends PreviewBaseComponent {
|
||||||
const topicOp = i18n("wizard.homepage_preview.topic_ops.what_books");
|
const topicOp = i18n("wizard.homepage_preview.topic_ops.what_books");
|
||||||
const topicOpLines = topicOp.split("\n");
|
const topicOpLines = topicOp.split("\n");
|
||||||
|
|
||||||
this.resizeTextLinesToFitRect(
|
resizeTextLinesToFitRect(
|
||||||
topicOpLines,
|
topicOpLines,
|
||||||
timelineX - leftHandTextGutter,
|
timelineX - leftHandTextGutter,
|
||||||
ctx,
|
ctx,
|
||||||
|
@ -216,13 +220,14 @@ export default class Index extends PreviewBaseComponent {
|
||||||
|
|
||||||
// Timeline post count
|
// Timeline post count
|
||||||
const postCountY = height * 0.3 + margin + 10;
|
const postCountY = height * 0.3 + margin + 10;
|
||||||
ctx.font = `Bold ${bodyFontSize}em ${font}`;
|
ctx.beginPath();
|
||||||
|
ctx.font = `700 ${bodyFontSize}em '${font}'`;
|
||||||
ctx.fillStyle = colors.primary;
|
ctx.fillStyle = colors.primary;
|
||||||
ctx.fillText("1 / 20", timelineX + margin / 2, postCountY);
|
ctx.fillText("1 / 20", timelineX + margin / 2, postCountY);
|
||||||
|
|
||||||
// Timeline post date
|
// Timeline post date
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.font = `${bodyFontSize * 0.9}em ${font}`;
|
ctx.font = `${bodyFontSize * 0.9}em '${font}'`;
|
||||||
ctx.fillStyle = darkLightDiff(colors.primary, colors.secondary, 70, 65);
|
ctx.fillStyle = darkLightDiff(colors.primary, colors.secondary, 70, 65);
|
||||||
ctx.fillText(
|
ctx.fillText(
|
||||||
"Nov 22",
|
"Nov 22",
|
||||||
|
|
|
@ -138,3 +138,26 @@ export function drawHeader(ctx, colors, width, headerHeight) {
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function resizeTextLinesToFitRect(
|
||||||
|
textLines,
|
||||||
|
rectWidth,
|
||||||
|
ctx,
|
||||||
|
fontSize,
|
||||||
|
font,
|
||||||
|
renderCallback
|
||||||
|
) {
|
||||||
|
const maxLengthLine = textLines.reduce((a, b) =>
|
||||||
|
a.length > b.length ? a : b
|
||||||
|
);
|
||||||
|
|
||||||
|
let fontSizeDecreaseMultiplier = 1;
|
||||||
|
while (ctx.measureText(maxLengthLine).width > rectWidth) {
|
||||||
|
fontSizeDecreaseMultiplier -= 0.1;
|
||||||
|
ctx.font = `${fontSize * fontSizeDecreaseMultiplier}em '${font}'`;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < textLines.length; i++) {
|
||||||
|
renderCallback(textLines[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -72,7 +72,7 @@ class SiteSetting < ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.top_menu_items
|
def self.top_menu_items
|
||||||
top_menu.split("|").map { |menu_item| TopMenuItem.new(menu_item) }
|
top_menu_map.map { |menu_item| TopMenuItem.new(menu_item) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.homepage
|
def self.homepage
|
||||||
|
|
|
@ -7390,6 +7390,14 @@ en:
|
||||||
homepage_preview: "Homepage preview"
|
homepage_preview: "Homepage preview"
|
||||||
|
|
||||||
homepage_preview:
|
homepage_preview:
|
||||||
|
nav_buttons:
|
||||||
|
all_categories: "all categories"
|
||||||
|
new: "New"
|
||||||
|
unread: "Unread"
|
||||||
|
top: "Top"
|
||||||
|
latest: "Latest"
|
||||||
|
hot: "Hot"
|
||||||
|
categories: "Categories"
|
||||||
topic_titles:
|
topic_titles:
|
||||||
what_books: "What books are you reading?"
|
what_books: "What books are you reading?"
|
||||||
what_movies: "What movies have you seen recently?"
|
what_movies: "What movies have you seen recently?"
|
||||||
|
@ -7409,3 +7417,8 @@ en:
|
||||||
icebreakers: "Icebreakers"
|
icebreakers: "Icebreakers"
|
||||||
news: "News"
|
news: "News"
|
||||||
site_feedback: "Site Feedback"
|
site_feedback: "Site Feedback"
|
||||||
|
table_headers:
|
||||||
|
topic: "Topic"
|
||||||
|
replies: "Replies"
|
||||||
|
views: "Views"
|
||||||
|
activity: "Activity"
|
||||||
|
|
|
@ -5423,6 +5423,8 @@ en:
|
||||||
choices:
|
choices:
|
||||||
latest:
|
latest:
|
||||||
label: "Latest Topics"
|
label: "Latest Topics"
|
||||||
|
hot:
|
||||||
|
label: "Hot Topics"
|
||||||
categories_only:
|
categories_only:
|
||||||
label: "Categories Only"
|
label: "Categories Only"
|
||||||
categories_with_featured_topics:
|
categories_with_featured_topics:
|
||||||
|
|
|
@ -222,7 +222,7 @@ module Stylesheet
|
||||||
)
|
)
|
||||||
contents << <<~CSS
|
contents << <<~CSS
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: #{font[:name]};
|
font-family: '#{font[:name]}';
|
||||||
src: #{src};
|
src: #{src};
|
||||||
font-weight: #{variant[:weight]};
|
font-weight: #{variant[:weight]};
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,7 +191,7 @@ class Wizard
|
||||||
|
|
||||||
current =
|
current =
|
||||||
(
|
(
|
||||||
if SiteSetting.top_menu.starts_with?("categories")
|
if SiteSetting.top_menu_map.first == "categories"
|
||||||
SiteSetting.desktop_category_page_style
|
SiteSetting.desktop_category_page_style
|
||||||
else
|
else
|
||||||
"latest"
|
"latest"
|
||||||
|
@ -214,8 +214,8 @@ class Wizard
|
||||||
updater.update_setting(:base_font, updater.fields[:body_font])
|
updater.update_setting(:base_font, updater.fields[:body_font])
|
||||||
updater.update_setting(:heading_font, updater.fields[:heading_font])
|
updater.update_setting(:heading_font, updater.fields[:heading_font])
|
||||||
|
|
||||||
top_menu = SiteSetting.top_menu.split("|")
|
top_menu = SiteSetting.top_menu_map
|
||||||
if updater.fields[:homepage_style] == "latest" && top_menu[0] != "latest"
|
if updater.fields[:homepage_style] == "latest" && top_menu.first != "latest"
|
||||||
top_menu.delete("latest")
|
top_menu.delete("latest")
|
||||||
top_menu.insert(0, "latest")
|
top_menu.insert(0, "latest")
|
||||||
elsif updater.fields[:homepage_style] != "latest"
|
elsif updater.fields[:homepage_style] != "latest"
|
||||||
|
|
Loading…
Reference in New Issue