UX: Wizard style preview improvements

* Render date on timeline
* Render timeline handle thicker and with a small gap at top
* Make sure body text does not overflow over timeline with
  bounding box calculation and dymanic font resizing
* Other minor improvements to spacing/sizing
This commit is contained in:
Martin Brennan 2024-12-05 17:15:13 +10:00
parent 2ac2c42b06
commit af5eed5005
No known key found for this signature in database
GPG Key ID: BD981EFEEC8F5675
3 changed files with 87 additions and 35 deletions

View File

@ -248,17 +248,20 @@ export default class PreviewBase extends Component {
ctx.drawImage(scaled[key], x, y, w, h);
}
get headerHeight() {
return this.height * 0.15;
}
drawFullHeader(colors, font, logo) {
const { ctx } = this;
const headerHeight = this.height * 0.15;
drawHeader(ctx, colors, this.width, headerHeight);
drawHeader(ctx, colors, this.width, this.headerHeight);
const avatarSize = this.height * 0.1;
const headerMargin = headerHeight * 0.2;
const headerMargin = this.headerHeight * 0.2;
if (logo) {
const logoHeight = headerHeight - headerMargin * 2;
const logoHeight = this.headerHeight - headerMargin * 2;
const ratio = logoHeight / logo.height;
this.scaleImage(
@ -285,7 +288,7 @@ export default class PreviewBase extends Component {
colors.primary_low_mid ||
darkLightDiff(colors.primary, colors.secondary, 45, 55);
const pathScale = headerHeight / 1200;
const pathScale = this.headerHeight / 1200;
// search icon SVG path
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"
@ -390,6 +393,29 @@ export default class PreviewBase extends Component {
x += categoriesSize * 0.6;
ctx.fillText("Top", x, headerHeight + headerMargin * 1.5 + fontSize);
}
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);
}
}
}
function loadImage(src) {

View File

@ -7,8 +7,8 @@ import HomepagePreview from "./-homepage-preview";
import PreviewBaseComponent from "./-preview-base";
export default class Index extends PreviewBaseComponent {
width = 628;
height = 322;
width = 630;
height = 380;
logo = null;
avatar = null;
previewTopic = true;
@ -111,51 +111,60 @@ export default class Index extends PreviewBaseComponent {
}
paint({ ctx, colors, font, headingFont, width, height }) {
const headerHeight = height * 0.3;
this.drawFullHeader(colors, headingFont, this.logo);
const margin = 20;
const avatarSize = height * 0.15;
const avatarSize = height * 0.1 + 5;
const lineHeight = height / 14;
const leftHandTextGutter = margin + avatarSize + margin;
const timelineX = width * 0.86;
// Draw a fake topic
this.scaleImage(
this.avatar,
margin,
headerHeight + height * 0.09,
this.headerHeight + height * 0.22,
avatarSize,
avatarSize
);
const titleFontSize = headerHeight / 55;
const titleFontSize = this.headerHeight / 30;
// Topic title
ctx.beginPath();
ctx.fillStyle = colors.primary;
ctx.font = `bold ${titleFontSize}em '${headingFont}'`;
ctx.fillText(i18n("wizard.previews.topic_title"), margin, height * 0.3);
const bodyFontSize = height / 330.0;
// Topic OP text
const bodyFontSize = 1;
ctx.font = `${bodyFontSize}em '${font}'`;
let line = 0;
const lines = i18n("wizard.homepage_preview.topic_ops.what_books").split(
"\n"
let verticalLinePos = 0;
const topicOp = i18n("wizard.homepage_preview.topic_ops.what_books");
const topicOpLines = topicOp.split("\n");
this.resizeTextLinesToFitRect(
topicOpLines,
timelineX - leftHandTextGutter,
ctx,
bodyFontSize,
font,
(textLine, idx) => {
verticalLinePos = height * 0.4 + idx * lineHeight;
ctx.fillText(textLine, leftHandTextGutter, verticalLinePos);
}
);
for (let i = 0; i < lines.length; i++) {
line = height * 0.4 + i * lineHeight;
ctx.fillText(lines[i], margin + avatarSize + margin, line);
}
ctx.font = `${bodyFontSize}em '${font}'`;
// Share Button
// Share button
const shareButtonWidth =
Math.round(ctx.measureText(i18n("wizard.previews.share_button")).width) +
20;
margin;
ctx.beginPath();
ctx.rect(margin, line + lineHeight, shareButtonWidth, height * 0.1);
ctx.rect(margin, verticalLinePos, shareButtonWidth, height * 0.1);
// accounts for hard-set color variables in solarized themes
ctx.fillStyle =
colors.primary_low ||
@ -165,18 +174,18 @@ export default class Index extends PreviewBaseComponent {
ctx.fillText(
i18n("wizard.previews.share_button"),
margin + 10,
line + lineHeight * 1.9
verticalLinePos + lineHeight * 0.9
);
// Reply Button
// Reply button
const replyButtonWidth =
Math.round(ctx.measureText(i18n("wizard.previews.reply_button")).width) +
20;
margin;
ctx.beginPath();
ctx.rect(
shareButtonWidth + margin + 10,
line + lineHeight,
verticalLinePos,
replyButtonWidth,
height * 0.1
);
@ -185,12 +194,11 @@ export default class Index extends PreviewBaseComponent {
ctx.fillStyle = colors.secondary;
ctx.fillText(
i18n("wizard.previews.reply_button"),
shareButtonWidth + margin + 20,
line + lineHeight * 1.9
shareButtonWidth + margin * 2,
verticalLinePos + lineHeight * 0.9
);
// Draw Timeline
const timelineX = width * 0.86;
// Draw timeline
ctx.beginPath();
ctx.strokeStyle = colors.tertiary;
ctx.lineWidth = 0.5;
@ -198,17 +206,29 @@ export default class Index extends PreviewBaseComponent {
ctx.lineTo(timelineX, height * 0.7);
ctx.stroke();
// Timeline
// Timeline handle
ctx.beginPath();
ctx.strokeStyle = colors.tertiary;
ctx.lineWidth = 2;
ctx.moveTo(timelineX, height * 0.3);
ctx.lineWidth = 3;
ctx.moveTo(timelineX, height * 0.3 + 10);
ctx.lineTo(timelineX, height * 0.4);
ctx.stroke();
// Timeline post count
const postCountY = height * 0.3 + margin + 10;
ctx.font = `Bold ${bodyFontSize}em ${font}`;
ctx.fillStyle = colors.primary;
ctx.fillText("1 / 20", timelineX + margin, height * 0.3 + margin * 1.5);
ctx.fillText("1 / 20", timelineX + margin / 2, postCountY);
// Timeline post date
ctx.beginPath();
ctx.font = `${bodyFontSize * 0.9}em ${font}`;
ctx.fillStyle = darkLightDiff(colors.primary, colors.secondary, 70, 65);
ctx.fillText(
"Nov 22",
timelineX + margin / 2,
postCountY + lineHeight * 0.75
);
}
@action

View File

@ -151,6 +151,12 @@ body.wizard {
}
}
&__step.styling .wizard-container__field.styling-preview-field {
label {
display: none;
}
}
&__field {
margin-bottom: 1em;
}