Skip to content

Commit

Permalink
WIP: Reimplement for new topic list
Browse files Browse the repository at this point in the history
  • Loading branch information
davidtaylorhq committed Dec 4, 2024
1 parent 85ad071 commit f719a42
Show file tree
Hide file tree
Showing 9 changed files with 391 additions and 351 deletions.
155 changes: 155 additions & 0 deletions javascripts/discourse/components/topic-list-thumbnail.gjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import Component from "@glimmer/component";
import { service } from "@ember/service";
import concatClass from "discourse/helpers/concat-class";
import dIcon from "discourse-common/helpers/d-icon";

export default class TopicListThumbnail extends Component {
@service topicThumbnails;

responsiveRatios = [1, 1.5, 2];

// Make sure to update about.json thumbnail sizes if you change these variables
get displayWidth() {
return this.topicThumbnails.displayList
? settings.list_thumbnail_size
: 400;
}

get topic() {
return this.args.topic;
}

get hasThumbnail() {
return !!this.topic.thumbnails;
}

get srcSet() {
const srcSetArray = [];

this.responsiveRatios.forEach((ratio) => {
const target = ratio * this.displayWidth;
const match = this.topic.thumbnails.find(
(t) => t.url && t.max_width === target
);
if (match) {
srcSetArray.push(`${match.url} ${ratio}x`);
}
});

if (srcSetArray.length === 0) {
srcSetArray.push(`${this.original.url} 1x`);
}

return srcSetArray.join(",");
}

get original() {
return this.topic.thumbnails[0];
}

get width() {
return this.original.width;
}

get isLandscape() {
return this.original.width >= this.original.height;
}

get height() {
return this.original.height;
}

get fallbackSrc() {
const largeEnough = this.topic.thumbnails.filter((t) => {
if (!t.url) {
return false;
}
return t.max_width > this.displayWidth * this.responsiveRatios.lastObject;
});

if (largeEnough.lastObject) {
return largeEnough.lastObject.url;
}

return this.original.url;
}

get url() {
return this.topic.linked_post_number
? this.topic.urlForPostNumber(this.topic.linked_post_number)
: this.topic.get("lastUnreadUrl");
}

<template>
<div
class={{concatClass
"topic-list-thumbnail"
(if this.hasThumbnail "has-thumbnail" "no-thumbnail")
}}
>
<a href={{this.url}}>
{{#if this.hasThumbnail}}
<img
class="background-thumbnail"
src={{this.fallbackSrc}}
srcset={{this.srcSet}}
width={{this.width}}
height={{this.height}}
loading="lazy"
/>
<img
class="main-thumbnail"
src={{this.fallbackSrc}}
srcset={{this.srcSet}}
width={{this.width}}
height={{this.height}}
loading="lazy"
/>
{{else}}
<div class="thumbnail-placeholder">
{{dIcon settings.placeholder_icon}}
</div>
{{/if}}
</a>
</div>

{{#if this.topicThumbnails.showLikes}}
<div class="topic-thumbnail-likes">
{{dIcon "heart"}}
<span class="number">
{{this.topic.like_count}}
</span>
</div>
{{/if}}

{{#if this.topicThumbnails.displayBlogStyle}}
<div class="topic-thumbnail-blog-data">
<div class="topic-thumbnail-blog-data-views">
{{dIcon "eye"}}
<span class="number">
{{this.topic.views}}
</span>
</div>
<div class="topic-thumbnail-blog-data-likes">
{{dIcon "heart"}}
<span class="number">
{{this.topic.like_count}}
</span>
</div>
<div class="topic-thumbnail-blog-data-comments">
{{dIcon "comment"}}
<span class="number">
{{this.topic.reply_count}}
</span>
</div>
{{! TODO }}
{{!-- {{raw
"list/activity-column"
topic=this.topic
class="topic-thumbnail-blog-data-activity"
tagName="div"
}} --}}
</div>
{{/if}}
</template>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import Component from "@glimmer/component";
import { service } from "@ember/service";
import { modifier } from "ember-modifier";

export default class extends Component {
@service topicThumbnails;

attachResizeObserver = modifier((element) => {
const topicList = element.closest(".topic-list");

if (!topicList) {
// eslint-disable-next-line no-console
console.error(
"topic-list-thumbnails resize-observer must be inside a topic-list"
);
return;
}

this.topicThumbnails.masonryContainerWidth =
topicList.getBoundingClientRect().width;

const observer = new ResizeObserver(() => {
this.topicThumbnails.masonryContainerWidth =
topicList.getBoundingClientRect().width;
console.log(

Check failure on line 25 in javascripts/discourse/connectors/before-topic-list-body/topic-list-resize-observer.gjs

View workflow job for this annotation

GitHub Actions / ci / linting

Unexpected console statement
"ResizeObserver triggered",
this.topicThumbnails.masonryContainerWidth
);
});
observer.observe(topicList);

return () => {
observer.disconnect();
this.topicThumbnails.masonryContainerWidth = null;
};
});

<template>
{{#if this.topicThumbnails.displayMasonry}}
<div style="display: none;" {{this.attachResizeObserver}}>
<!-- topic-list-thumbnails resize-observer -->

Check failure on line 41 in javascripts/discourse/connectors/before-topic-list-body/topic-list-resize-observer.gjs

View workflow job for this annotation

GitHub Actions / ci / linting

HTML comment detected
</div>
{{/if}}
</template>
}
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
{{!-- has-modern-replacement --}}
{{~raw "topic-list-thumbnail" topic=context.topic location="before-columns"}}
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
{{!-- has-modern-replacement --}}
{{~raw "topic-list-thumbnail" topic=context.topic location="before-link"}}

113 changes: 113 additions & 0 deletions javascripts/discourse/initializers/topic-thumbnails-init.gjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { readOnly } from "@ember/object/computed";
import { service } from "@ember/service";
import { apiInitializer } from "discourse/lib/api";
import TopicListThumbnail from "../components/topic-list-thumbnail";
import MasonryCalculator from "../lib/masonry-calculator";

export default apiInitializer("0.8", (api) => {
const ttService = api.container.lookup("service:topic-thumbnails");

api.registerValueTransformer("topic-list-class", ({ value }) => {
if (ttService.displayMinimalGrid) {
value.push("topic-thumbnails-minimal");
} else if (ttService.displayGrid) {
value.push("topic-thumbnails-grid");
} else if (ttService.displayList) {
value.push("topic-thumbnails-list");
} else if (ttService.displayMasonry) {
value.push("topic-thumbnails-masonry");
} else if (ttService.displayBlogStyle) {
value.push("topic-thumbnails-blog-style-grid");
}
return value;
});

api.registerValueTransformer("topic-list-columns", ({ value: columns }) => {
if (ttService.enabledForRoute && !ttService.displayList) {
columns.add(
"thumbnail",
{
item: TopicListThumbnail,
},
{ before: "topic" }
);
}
return columns;
});

api.renderInOutlet("topic-list-before-link", <template>
{{#if ttService.displayList}}
<TopicListThumbnail @topic={{@outletArgs.topic}} />
{{/if}}
</template>);

api.registerValueTransformer("topic-list-item-mobile-layout", ({ value }) => {
if (ttService.enabledForRoute && !ttService.displayList) {
// Force the desktop layout
return false;
}
return value;
});

// Todo: what do do with docs?
const siteSettings = api.container.lookup("service:site-settings");
if (settings.docs_thumbnail_mode !== "none" && siteSettings.docs_enabled) {
api.modifyClass("component:docs-topic-list", {
pluginId: "topic-thumbnails",
topicThumbnailsService: service("topic-thumbnails"),
classNameBindings: [
"isMinimalGrid:topic-thumbnails-minimal",
"isThumbnailGrid:topic-thumbnails-grid",
"isThumbnailList:topic-thumbnails-list",
"isMasonryList:topic-thumbnails-masonry",
"isBlogStyleGrid:topic-thumbnails-blog-style-grid",
],
isMinimalGrid: readOnly("topicThumbnailsService.displayMinimalGrid"),
isThumbnailGrid: readOnly("topicThumbnailsService.displayGrid"),
isThumbnailList: readOnly("topicThumbnailsService.displayList"),
isMasonryList: readOnly("topicThumbnailsService.displayMasonry"),
isBlogStyleGrid: readOnly("topicThumbnailsService.displayBlogStyle"),
});
}

// Masonry Layout
api.registerValueTransformer(
"topic-list-style",
({ value, context: { topics } }) => {
if (!ttService.displayMasonry) {
return;
}

if (!ttService.masonryContainerWidth) {
return;
}

const calculator = new MasonryCalculator(
api.container,
topics,
ttService.masonryContainerWidth
);
calculator.calculateMasonryLayout();
value += calculator.masonryStyle;

return value;
}
);

api.registerValueTransformer(
"topic-list-item-style",
({ value, context }) => {
if (ttService.displayMasonry) {
const masonryData = context.topic.get("masonryData");
if (masonryData) {
value += [
`--masonry-height: ${Math.round(masonryData.height)}px;`,
`--masonry-height-above: ${Math.round(masonryData.heightAbove)}px;`,
`--masonry-column-index: ${masonryData.columnIndex};`,
].join("");
}
}
return value;
}
);
});
Loading

0 comments on commit f719a42

Please sign in to comment.