diff --git a/about.json b/about.json index 415ba01..16a0c2e 100644 --- a/about.json +++ b/about.json @@ -8,7 +8,9 @@ "minimum_discourse_version": null, "maximum_discourse_version": null, "assets": {}, - "modifiers": {}, + "modifiers": { + "svg_icons": ["fire"] + }, "components": [ "https://github.com/discourse/discourse-sidebar-new-topic-button.git", "https://github.com/discourse/discourse-search-banner.git", diff --git a/javascripts/discourse/components/card/topic-author-avatar-column.gjs b/javascripts/discourse/components/card/topic-author-avatar-column.gjs new file mode 100644 index 0000000..260e158 --- /dev/null +++ b/javascripts/discourse/components/card/topic-author-avatar-column.gjs @@ -0,0 +1,9 @@ +import avatar from "discourse/helpers/avatar"; + +const TopicAuthorAvatarColumn = ; + +export default TopicAuthorAvatarColumn; diff --git a/javascripts/discourse/components/card/topic-author-column.gjs b/javascripts/discourse/components/card/topic-author-column.gjs new file mode 100644 index 0000000..a239d73 --- /dev/null +++ b/javascripts/discourse/components/card/topic-author-column.gjs @@ -0,0 +1,5 @@ +const TopicAuthorColumn = ; + +export default TopicAuthorColumn; diff --git a/javascripts/discourse/components/card/topic-category-column.gjs b/javascripts/discourse/components/card/topic-category-column.gjs new file mode 100644 index 0000000..ca8ae87 --- /dev/null +++ b/javascripts/discourse/components/card/topic-category-column.gjs @@ -0,0 +1,7 @@ +import { categoryLinkHTML } from "discourse/helpers/category-link"; + +const TopicCategoryColumn = ; + +export default TopicCategoryColumn; diff --git a/javascripts/discourse/components/card/topic-likes-column.gjs b/javascripts/discourse/components/card/topic-likes-column.gjs new file mode 100644 index 0000000..f1d6aff --- /dev/null +++ b/javascripts/discourse/components/card/topic-likes-column.gjs @@ -0,0 +1,9 @@ +import icon from "discourse/helpers/d-icon"; + +const TopicLikesColumn = ; + +export default TopicLikesColumn; diff --git a/javascripts/discourse/components/card/topic-replies-column.gjs b/javascripts/discourse/components/card/topic-replies-column.gjs new file mode 100644 index 0000000..53e2ac8 --- /dev/null +++ b/javascripts/discourse/components/card/topic-replies-column.gjs @@ -0,0 +1,9 @@ +import icon from "discourse/helpers/d-icon"; + +const TopicRepliesColumn = ; + +export default TopicRepliesColumn; diff --git a/javascripts/discourse/components/card/topic-status-column.gjs b/javascripts/discourse/components/card/topic-status-column.gjs new file mode 100644 index 0000000..9e207ad --- /dev/null +++ b/javascripts/discourse/components/card/topic-status-column.gjs @@ -0,0 +1,115 @@ +import Component from "@glimmer/component"; +import { on } from "@ember/modifier"; +import { action } from "@ember/object"; +import { service } from "@ember/service"; +import { and } from "truth-helpers"; +import icon from "discourse/helpers/d-icon"; +import i18n from "discourse-i18n"; + +export default class TopicStatusColumn extends Component { + @service currentUser; + @service siteSettings; + + get canAct() { + return this.currentUser && !this.args.disableActions; + } + + get statusClass() { + let classes = ["topic-status-card"]; + if (this.args.topic.bookmarked) { + classes.push("--bookmark"); + } else if (this.args.topic.closed && this.args.topic.archived) { + classes.push("--locked --archived"); + } else if (this.args.topic.closed) { + classes.push("--locked"); + } else if (this.args.topic.archived) { + classes.push("--archived"); + } else if (this.args.topic.is_warning) { + classes.push("--warning"); + } else if ( + this.args.showPrivateMessageIcon && + this.args.topic.isPrivateMessage + ) { + classes.push("--private-message"); + } else if (this.args.topic.pinned) { + classes.push("--pinned"); + } else if (this.args.topic.unpinned) { + classes.push("--unpinned"); + } + return classes.join(" "); + } + + get heatMap() { + return this.args.topic.views > this.siteSettings.topic_views_heat_medium; + } + + @action + togglePinned(event) { + event.preventDefault(); + this.args.topic.togglePinnedForUser(); + } + + +} diff --git a/javascripts/discourse/initializers/topic-list-columns.gjs b/javascripts/discourse/initializers/topic-list-columns.gjs new file mode 100644 index 0000000..0fa2e50 --- /dev/null +++ b/javascripts/discourse/initializers/topic-list-columns.gjs @@ -0,0 +1,81 @@ +import { withPluginApi } from "discourse/lib/plugin-api"; +import TopicAuthorAvatarColumn from "../components/card/topic-author-avatar-column"; +import TopicAuthorColumn from "../components/card/topic-author-column"; +import TopicCategoryColumn from "../components/card/topic-category-column"; +import TopicLikesColumn from "../components/card/topic-likes-column"; +import TopicRepliesColumn from "../components/card/topic-replies-column"; +import TopicStatusColumn from "../components/card/topic-status-column"; + +const TopicAuthor = ; + +const TopicAuthorAvatar = ; + +const TopicCategoryStatus = ; + +const TopicLikesReplies = ; + +export default { + name: "topic-list-customizations", + + initialize() { + withPluginApi("1.39.0", (api) => { + api.registerValueTransformer( + "topic-list-columns", + ({ value: columns }) => { + columns.add("topic-author", { + item: TopicAuthor, + after: "activity", + }); + columns.add("topic-category-status", { + item: TopicCategoryStatus, + after: "topic-author", + }); + columns.add("topic-author-avatar", { + item: TopicAuthorAvatar, + after: "topic-category-status", + }); + columns.add("topic-likes-replies", { + item: TopicLikesReplies, + after: "topic-author-avatar", + }); + columns.delete("posters"); + columns.delete("views"); + columns.delete("replies"); + return columns; + } + ); + + api.registerValueTransformer( + "topic-list-item-class", + ({ value: classes, context }) => { + if (context.topic.pinned || context.topic.pinned_globally) { + classes.push("--pinned"); + } + return classes; + } + ); + + api.registerValueTransformer("topic-list-item-mobile-layout", () => { + return false; + }); + }); + }, +}; diff --git a/locales/en.yml b/locales/en.yml index e38fc70..0b63ef7 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -1,5 +1,12 @@ en: theme_metadata: - description: "" - settings: - example_setting: A description of a setting. + description: "A simple, beautiful theme for the future of Discourse that improves the out of the box experience for sites." + topic_bookmarked: "Bookmarked" + topic_closed_archived: "Closed and archived" + topic_closed: "Closed" + topic_archived: "Archived" + topic_warning: "Warning" + topic_personal_message: "Personal message" + topic_pinned: "Pinned" + topic_unpinned: "Unpinned" + topic_hot: "Hot" diff --git a/package.json b/package.json index 5ac81bd..9eb29d3 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "prettier": "2.8.8" }, "engines": { - "node": ">= 22", + "node": ">= 18", "npm": "please-use-pnpm", "yarn": "please-use-pnpm", "pnpm": "9.x" diff --git a/scss/topic-cards.scss b/scss/topic-cards.scss index 0940c62..f410b09 100644 --- a/scss/topic-cards.scss +++ b/scss/topic-cards.scss @@ -1,3 +1,331 @@ +// 390x844 – mobile/portrait – (Figma iPhone 13 & 14) +// 744x1133 – tablet/portrait – (Figma iPad mini 8.3) +// 1280x832 – desktop small – (Figma MacBook Air) + +:root { + --hot-color: oklch(63.79% 0.1823 34.77); +} + +$extra-small: 435px; +$small: 576px; +$medium: 980px; +$extra-large: 1280px; + +.topic-list .topic-list-item-separator { + display: none; +} + +.topic-list > .topic-list-body > .topic-list-item.last-visit { + border-bottom: 1px solid var(--primary-300); +} + +.topic-list-body { + border: none; + display: flex; + flex-direction: column; + gap: 1em; + @media screen and (max-width: $extra-small) { + gap: 0.5em; + } +} + +body.user-messages-page .topic-list-item { + .topic-category-status-data { + display: none; + } + grid-template-areas: + "avatar author status status . . activity" + ". topic-title topic-title topic-title likes-replies likes-replies likes-replies"; + &.excerpt-expanded { + grid-template-columns: 44px repeat(6, 1fr) auto; + grid-template-rows: 22px auto auto 30px; + grid-template-areas: + "avatar author status status . . . activity" + "avatar topic-title topic-title topic-title topic-title . . ." + ". excerpt excerpt excerpt excerpt excerpt . ." + ". excerpt excerpt excerpt excerpt excerpt likes-replies likes-replies"; + @media screen and (max-width: $extra-large) { + grid-template-areas: + "avatar author status status . . . activity" + "avatar topic-title topic-title topic-title topic-title . . ." + ". excerpt excerpt excerpt excerpt excerpt . likes-replies" + ". excerpt excerpt excerpt excerpt excerpt . likes-replies"; + } + } + @media screen and (max-width: $small) { + grid-template-columns: 25px auto repeat(6, 1fr); + grid-template-rows: auto auto; + grid-template-areas: + "topic-title topic-title topic-title topic-title topic-title topic-title topic-title activity" + "avatar author . . . . . likes-replies"; + .topic-excerpt { + display: none; + } + } +} + +.topic-list-item { + -webkit-font-smoothing: antialiased; + text-overflow: ellipsis; + padding: 0.75em 1rem; + border: 1px solid var(--primary-300); + display: grid; + grid-template-columns: 44px min-content min-content auto min-content min-content min-content; + + grid-template-rows: 22px minmax(22px, auto); + grid-template-areas: + "avatar author status status . . activity" + ". topic-title topic-title topic-title likes-replies likes-replies category"; + &.excerpt-expanded { + grid-template-columns: 44px repeat(6, 1fr) auto; + grid-template-rows: 22px auto auto 30px; + grid-template-areas: + "avatar author status status . . . activity" + "avatar topic-title topic-title topic-title topic-title . . ." + ". excerpt excerpt excerpt excerpt excerpt . ." + ". excerpt excerpt excerpt excerpt excerpt likes-replies category"; + @media screen and (max-width: $extra-large) { + grid-template-areas: + "avatar author status status . . . activity" + "avatar topic-title topic-title topic-title topic-title . . ." + ". excerpt excerpt excerpt excerpt excerpt . likes-replies" + ". excerpt excerpt excerpt excerpt excerpt . category"; + } + @media screen and (max-width: $small) { + grid-template-columns: 25px auto repeat(6, 1fr); + grid-template-rows: auto auto auto; + grid-template-areas: + "category-status category-status category-status . . . . activity" + "topic-title topic-title topic-title topic-title topic-title topic-title topic-title topic-title" + "avatar author . . . . . likes-replies"; + .topic-excerpt { + display: none; + } + } + } + grid-column-gap: 12px; + grid-row-gap: 8px; + border-radius: var(--d-border-radius); + @media screen and (max-width: $medium) { + grid-template-columns: 44px min-content min-content auto min-content min-content min-content; + grid-template-rows: 22px minmax(22px, auto); + grid-template-areas: + "avatar author status status . . activity" + ". topic-title topic-title topic-title . . likes-replies" + ". topic-title topic-title topic-title . . category"; + } + @media screen and (max-width: $small) { + grid-template-columns: 25px auto repeat(6, 1fr); + grid-template-rows: auto auto auto; + grid-template-areas: + "category-status category-status category-status . . . . activity" + "topic-title topic-title topic-title topic-title topic-title topic-title topic-title topic-title" + "avatar author . . . . . likes-replies"; + } + @media screen and (max-width: $extra-small) { + border: none; + border-bottom: 1px solid var(--primary-200); + } + + // display contents + td.main-link, + td.posters, + td.posts, + td.views, + td.activity { + display: contents; + } + + td.num.posts a { + padding: 0; + } + + // avatar & author + .topic-author-avatar-data { + grid-area: avatar; + margin: 0; + } + .topic-author-avatar img.avatar { + width: 44px; + height: 44px; + border-radius: var(--d-border-radius); + @media screen and (max-width: $small) { + width: 25px; + height: 25px; + } + } + td.topic-author-data { + grid-area: author; + display: flex; + gap: 0.5em; + align-items: center; + } + .topic-author-data .topic-author { + color: var(--primary-500); + } + + // status + .topic-status-card { + display: flex; + flex-direction: row; + gap: 4px; + align-items: center; + padding: 0 6px; + font-size: var(--font-down-2); + font-weight: 600; + border-radius: var(--d-border-radius); + border: 1px solid var(--status-color); + color: var(--status-color); + height: min-content; + grid-area: status; + width: min-content; + @media screen and (max-width: $small) { + height: calc(100% - 2px); + } + svg { + font-size: var(--font-down-1); + color: var(--status-color); + } + } + + .topic-status-card.--bookmark { + display: none; + } + .topic-status-card.--pinned, + .topic-status-card.--unpinned { + --status-color: var(--primary-500); + cursor: pointer; + background-color: transparent; + line-height: unset; + } + .topic-status-card.--hot { + --status-color: var(--hot-color); + } + + // title + td.main-link .link-top-line { + font-size: var(--font-0); + grid-area: topic-title; + font-weight: 500; + } + + .link-top-line .event-date { + font-size: var(--font-down-3); + } + + td.main-link a.topic-status { + display: none; + } + + td.main-link .link-top-line a.raw-topic-link { + padding: 0; + } + + .topic-post-badges .badge-notification.unread-posts { + background-color: var(--tertiary); + color: var(--tertiary); + overflow: hidden; + height: 8px; + width: 8px; + padding: 0; + top: -2px; + min-width: unset; + } + + // excerpt + .topic-excerpt { + grid-area: excerpt; + margin: 0; + font-size: var(--font-down-2); + } + + // timestamp + td.activity .post-activity { + grid-area: activity; + font-size: var(--font-down-1); + color: var(--primary-500); + margin-left: auto; + padding: 0; + } + + // metadata + // metadata - category + td.main-link .link-bottom-line { + display: none; + } + + td.topic-category-status-data { + display: contents; + @media screen and (max-width: $small) { + grid-area: category-status; + display: flex; + gap: 0.5em; + align-items: center; + } + } + td.topic-category-status-data .badge-category__wrapper { + grid-area: category; + } + + td.topic-category-status-data .badge-category__wrapper { + overflow: unset; + border-radius: var(--d-border-radius); + padding: 6px; + align-self: flex-end; + background-color: light-dark( + oklch(from var(--category-badge-color) 97% calc(c * 0.3) h), + oklch(from var(--category-badge-color) 45% calc(c * 0.5) h) + ); + + @media screen and (max-width: $small) { + padding: 2px 6px; + } + + .badge-category__name { + color: light-dark( + oklch(from var(--category-badge-color) 20% calc(c * 1) h), + oklch(from var(--category-badge-color) 100% calc(c * 0.9) h) + ); + } + } + td.main-link .discourse-tags { + display: none; + } + + // metadata - likes and replies + td.posts .badge-posts { + grid-area: replies; + align-self: center; + font-weight: normal; + } + + td.topic-likes-replies-data { + grid-area: likes-replies; + display: flex; + flex-direction: row; + gap: 0.5em; + justify-content: flex-end; + height: min-content; + align-self: flex-end; + padding-bottom: 4px; + } + .topic-likes-replies-data .topic-likes, + .topic-likes-replies-data .topic-replies { + display: flex; + flex-direction: row; + gap: 0.5em; + align-items: center; + color: var(--primary-500); + svg { + color: var(--primary-600); + } + } +} + +.topic-list-header { + display: none; +} + .topic-list-item { background: var(--d-content-background); box-shadow: 0px 0px 26px 1px diff --git a/settings.yml b/settings.yml deleted file mode 100644 index e3cd1c4..0000000 --- a/settings.yml +++ /dev/null @@ -1,2 +0,0 @@ -example_setting: - default: true