16 Commits
Author SHA1 Message Date
Rafael Silva 4b1af6f717 cache fix 2025-01-15 12:06:06 -03:00
Rafael dos Santos Silva 19af3cb107 Merge pull request #7 from jjaffeux/category-links
UX: Match category cards with tag cards
2025-01-15 09:45:32 -03:00
Jordan Vidrine 7cc39605f5 linting 2025-01-14 19:02:34 -06:00
Jordan Vidrine fed8205a64 DEV: Add fake category data 2025-01-14 15:57:23 -06:00
Jordan Vidrine d669a39a00 UX: Make card clickable link 2025-01-14 15:55:14 -06:00
Jordan Vidrine 6a55f56b91 Merge pull request #6 from jjaffeux/reading-series 2025-01-14 15:37:39 -06:00
Rafael Silva 17e30c3933 lint 2025-01-14 18:30:10 -03:00
Jordan Vidrine ef21ee6b35 DEV: Format 2025-01-14 15:27:23 -06:00
Jordan Vidrine b358456b65 more 2025-01-14 15:19:16 -06:00
Jordan Vidrine 472783d1c1 DEV: Add correct data to method 2025-01-14 15:17:10 -06:00
Jordan Vidrine 2bb1072d29 Merge pull request #5 from jjaffeux/long-words 2025-01-14 11:38:43 -06:00
Jordan Vidrine ff72e3ed37 UX: Adjust styles for long words 2025-01-14 11:30:13 -06:00
Jordan Vidrine 2398ab4fe6 Merge branch 'main' of https://github.com/jjaffeux/discourse-rewind into main 2025-01-14 11:02:12 -06:00
Jordan Vidrine 951a405c4c UX: Simplify hours and minutes shown 2025-01-14 11:02:03 -06:00
Jordan VidrineandJoffrey JAFFEUX 2e8e292b01 UX: More books styling (#4)
Allows to style books as series

---------

Co-authored-by: Joffrey JAFFEUX <[email protected]>
2025-01-14 17:49:57 +01:00
Rafael dos Santos Silva b045b23e04 Merge pull request #3 from jjaffeux/more-books
More books suggested by sam
2025-01-14 12:45:12 -03:00
18 changed files with 227 additions and 49 deletions
@@ -7,7 +7,7 @@ module DiscourseRewind
FakeData = { FakeData = {
data: data:
(Date.new(2024, 1, 1)..Date.new(2024, 12, 31)).map do |date| (Date.new(2024, 1, 1)..Date.new(2024, 12, 31)).map do |date|
{ date:, post_count: rand(0..20), visited: false } { date: date.strftime("%Y-%m-%d"), post_count: rand(0..20), visited: false }
end, end,
identifier: "activity-calendar", identifier: "activity-calendar",
} }
@@ -33,7 +33,13 @@ module DiscourseRewind
) )
.group("generate_series, user_visits.id") .group("generate_series, user_visits.id")
.order("generate_series") .order("generate_series")
.map { |row| { date: row.date, post_count: row.post_count, visited: row.visited } } .map do |row|
{
date: row.date.strftime("%Y-%m-%d"),
post_count: row.post_count,
visited: row.visited,
}
end
{ data: calendar, identifier: "activity-calendar" } { data: calendar, identifier: "activity-calendar" }
end end
@@ -3,7 +3,19 @@
# Topics visited grouped by category # Topics visited grouped by category
module DiscourseRewind module DiscourseRewind
class Rewind::Action::FavoriteCategories < Rewind::Action::BaseReport class Rewind::Action::FavoriteCategories < Rewind::Action::BaseReport
FakeData = {
data: [
{ category_id: 1, name: "cats" },
{ category_id: 2, name: "dogs" },
{ category_id: 3, name: "countries" },
{ category_id: 4, name: "management" },
{ category_id: 5, name: "things" },
],
identifier: "favorite-categories",
}
def call def call
return FakeData if Rails.env.development?
favorite_categories = favorite_categories =
TopicViewItem TopicViewItem
.joins(:topic) .joins(:topic)
@@ -6,32 +6,32 @@ module DiscourseRewind
FakeData = { FakeData = {
data: { data: {
post_received_reactions: { post_received_reactions: {
"open_mouth" => 2, open_mouth: 2,
"cat" => 32, cat: 32,
"dog" => 34, dog: 34,
"heart" => 45, heart: 45,
"grinning" => 82, grinning: 82,
}, },
post_used_reactions: { post_used_reactions: {
"open_mouth" => 2, open_mouth: 2,
"cat" => 32, cat: 32,
"dog" => 34, dog: 34,
"heart" => 45, heart: 45,
"grinning" => 82, grinning: 82,
}, },
chat_used_reactions: { chat_used_reactions: {
"open_mouth" => 2, open_mouth: 2,
"cat" => 32, cat: 32,
"dog" => 34, dog: 34,
"heart" => 45, heart: 45,
"grinning" => 82, grinning: 82,
}, },
chat_received_reactions: { chat_received_reactions: {
"open_mouth" => 2, open_mouth: 2,
"cat" => 32, cat: 32,
"dog" => 34, dog: 34,
"heart" => 45, heart: 45,
"grinning" => 82, grinning: 82,
}, },
}, },
identifier: "reactions", identifier: "reactions",
@@ -4,7 +4,19 @@
# Should we show book covers or just the names? # Should we show book covers or just the names?
module DiscourseRewind module DiscourseRewind
class Rewind::Action::ReadingTime < Rewind::Action::BaseReport class Rewind::Action::ReadingTime < Rewind::Action::BaseReport
FakeData = {
data: {
reading_time: 2_880_000,
book: "The Combined Cosmere works + Wheel of Time",
isbn: "978-0812511819",
series: true,
},
identifier: "reading-time",
}
def call def call
return FakeData if Rails.env.development?
reading_time = UserVisit.where(user_id: user.id).where(visited_at: date).sum(:time_read) reading_time = UserVisit.where(user_id: user.id).where(visited_at: date).sum(:time_read)
book = best_book_fit(reading_time) book = best_book_fit(reading_time)
@@ -15,6 +27,7 @@ module DiscourseRewind
reading_time: reading_time, reading_time: reading_time,
book: book[:title], book: book[:title],
isbn: book[:isbn], isbn: book[:isbn],
series: book[:series],
}, },
identifier: "reading-time", identifier: "reading-time",
} }
@@ -25,110 +38,137 @@ module DiscourseRewind
"The Hunger Games" => { "The Hunger Games" => {
reading_time: 19_740, reading_time: 19_740,
isbn: "978-0439023481", isbn: "978-0439023481",
series: false,
}, },
"The Metamorphosis" => { "The Metamorphosis" => {
reading_time: 3120, reading_time: 3120,
isbn: "978-0553213690", isbn: "978-0553213690",
series: false,
}, },
"To Kill a Mockingbird" => { "To Kill a Mockingbird" => {
reading_time: 22_800, reading_time: 22_800,
isbn: "978-0061120084", isbn: "978-0061120084",
series: false,
}, },
"Pride and Prejudice" => { "Pride and Prejudice" => {
reading_time: 25_200, reading_time: 25_200,
isbn: "978-1503290563", isbn: "978-1503290563",
series: false,
}, },
"1984" => { "1984" => {
reading_time: 16_800, reading_time: 16_800,
isbn: "978-0451524935", isbn: "978-0451524935",
series: false,
}, },
"The Lord of the Rings" => { "The Lord of the Rings" => {
reading_time: 108_000, reading_time: 108_000,
isbn: "978-0544003415", isbn: "978-0544003415",
series: true,
}, },
"Harry Potter and the Sorcerer's Stone" => { "Harry Potter and the Sorcerer's Stone" => {
reading_time: 24_600, reading_time: 24_600,
isbn: "978-0590353427", isbn: "978-0590353427",
series: true,
}, },
"The Great Gatsby" => { "The Great Gatsby" => {
reading_time: 12_600, reading_time: 12_600,
isbn: "978-0743273565", isbn: "978-0743273565",
series: false,
}, },
"The Little Prince" => { "The Little Prince" => {
reading_time: 5400, reading_time: 5400,
isbn: "978-0156012195", isbn: "978-0156012195",
series: false,
}, },
"Animal Farm" => { "Animal Farm" => {
reading_time: 7200, reading_time: 7200,
isbn: "978-0451526342", isbn: "978-0451526342",
series: false,
}, },
"The Catcher in the Rye" => { "The Catcher in the Rye" => {
reading_time: 18_000, reading_time: 18_000,
isbn: "978-0316769488", isbn: "978-0316769488",
series: false,
}, },
"Jane Eyre" => { "Jane Eyre" => {
reading_time: 34_200, reading_time: 34_200,
isbn: "978-0141441146", isbn: "978-0141441146",
series: false,
}, },
"Fahrenheit 451" => { "Fahrenheit 451" => {
reading_time: 15_000, reading_time: 15_000,
isbn: "978-1451673319", isbn: "978-1451673319",
series: false,
}, },
"The Hobbit" => { "The Hobbit" => {
reading_time: 27_000, reading_time: 27_000,
isbn: "978-0547928227", isbn: "978-0547928227",
series: false,
}, },
"The Da Vinci Code" => { "The Da Vinci Code" => {
reading_time: 37_800, reading_time: 37_800,
isbn: "978-0307474278", isbn: "978-0307474278",
series: false,
}, },
"Little Women" => { "Little Women" => {
reading_time: 30_000, reading_time: 30_000,
isbn: "978-0147514011", isbn: "978-0147514011",
series: false,
}, },
"One Hundred Years of Solitude" => { "One Hundred Years of Solitude" => {
reading_time: 46_800, reading_time: 46_800,
isbn: "978-0060883287", isbn: "978-0060883287",
series: false,
}, },
"And Then There Were None" => { "And Then There Were None" => {
reading_time: 16_200, reading_time: 16_200,
isbn: "978-0062073488", isbn: "978-0062073488",
series: false,
}, },
"The Alchemist" => { "The Alchemist" => {
reading_time: 10_800, reading_time: 10_800,
isbn: "978-0061122415", isbn: "978-0061122415",
series: false,
}, },
"The Hitchhiker's Guide to the Galaxy" => { "The Hitchhiker's Guide to the Galaxy" => {
reading_time: 12_600, reading_time: 12_600,
isbn: "978-0345391803", isbn: "978-0345391803",
series: false,
}, },
"The Complete works of Shakespeare" => { "The Complete works of Shakespeare" => {
reading_time: 180_000, reading_time: 180_000,
isbn: "978-1853268953", isbn: "978-1853268953",
series: true,
}, },
"The Game of Thrones Series" => { "The Game of Thrones Series" => {
reading_time: 360_000, reading_time: 360_000,
isbn: "978-0007477159", isbn: "978-0007477159",
series: true,
}, },
"Malazan Book of the Fallen" => { "Malazan Book of the Fallen" => {
reading_time: 720_000, reading_time: 720_000,
isbn: "978-0765348821", isbn: "978-0765348821",
series: true,
}, },
"Terry Pratchett’s Discworld series" => { "Terry Pratchett’s Discworld series" => {
reading_time: 1_440_000, reading_time: 1_440_000,
isbn: "978-9123684458", isbn: "978-9123684458",
series: true,
}, },
"The Wandering Inn web series" => { "The Wandering Inn web series" => {
reading_time: 2_160_000, reading_time: 2_160_000,
isbn: "the-wandering-inn", isbn: "the-wandering-inn",
series: true,
}, },
"The Combined Cosmere works + Wheel of Time" => { "The Combined Cosmere works + Wheel of Time" => {
reading_time: 2_880_000, reading_time: 2_880_000,
isbn: "978-0812511819", isbn: "978-0812511819",
series: true,
}, },
"The Star Trek novels" => { "The Star Trek novels" => {
reading_time: 3_600_000, reading_time: 3_600_000,
isbn: "978-1852860691", isbn: "978-1852860691",
series: true,
}, },
}.symbolize_keys }.symbolize_keys
end end
@@ -150,7 +190,11 @@ module DiscourseRewind
book_title = book_title =
books.group_by { |book| book }.transform_values(&:count).max_by { |_, count| count }.first books.group_by { |book| book }.transform_values(&:count).max_by { |_, count| count }.first
{ title: book_title, isbn: popular_books[book_title][:isbn] } {
title: book_title,
isbn: popular_books[book_title][:isbn],
series: popular_books[book_title][:series],
}
end end
end end
end end
@@ -7,7 +7,7 @@ module DiscourseRewind
{ word: "what", score: 100 }, { word: "what", score: 100 },
{ word: "have", score: 90 }, { word: "have", score: 90 },
{ word: "you", score: 80 }, { word: "you", score: 80 },
{ word: "achieved", score: 70 }, { word: "overachieved", score: 70 },
{ word: "this", score: 60 }, { word: "this", score: 60 },
{ word: "week", score: 50 }, { word: "week", score: 50 },
], ],
+12 -12
View File
@@ -51,19 +51,19 @@ module DiscourseRewind
end end
def fetch_reports(date:, user:, guardian:, year:) def fetch_reports(date:, user:, guardian:, year:)
# key = "rewind:#{guardian.user.username}:#{year}" key = "rewind:#{guardian.user.id}:#{year}"
# reports = Discourse.redis.get(key) cached_reports = Discourse.redis.get(key)
# if Rails.env.development? || !reports if !cached_reports
reports = reports =
::DiscourseRewind::Rewind::Action::BaseReport ::DiscourseRewind::Rewind::Action::BaseReport
.descendants .descendants
.filter { _1.enabled? } .filter { _1.enabled? }
.map { |report| report.call(date:, user:, guardian:) } .map { |report| report.call(date:, user:, guardian:) }
# Discourse.redis.setex(key, CACHE_DURATION, MultiJson.dump(reports)) Discourse.redis.setex(key, CACHE_DURATION, reports.to_json)
# else else
# reports = MultiJson.load(reports.compact, symbolize_keys: true) reports = JSON.parse(cached_reports, symbolize_names: true)
# end end
reports reports
end end
@@ -10,12 +10,12 @@ const FavoriteCategories = <template>
}}</h2> }}</h2>
<div class="rewind-report-container"> <div class="rewind-report-container">
{{#each @report.data as |data|}} {{#each @report.data as |data|}}
<div class="rewind-card"> <a href={{concat "/c/-/" data.category_id}} class="rewind-card">
<a <p
class="favorite-categories__category" class="favorite-categories__category"
href={{concat "/c/-/" data.category_id}} href={{concat "/c/-/" data.category_id}}
>{{data.name}}</a> >{{data.name}}</p>
</div> </a>
{{/each}} {{/each}}
</div> </div>
</div> </div>
@@ -11,10 +11,10 @@ const FavoriteTags = <template>
<div class="rewind-report-container"> <div class="rewind-report-container">
{{#each @report.data as |data|}} {{#each @report.data as |data|}}
<a class="rewind-card" href={{concat "/tag/" data.name}}> <a class="rewind-card" href={{concat "/tag/" data.name}}>
<a <p
class="favorite-tags__tag" class="favorite-tags__tag"
href={{concat "/tag/" data.name}} href={{concat "/tag/" data.name}}
>#{{data.name}}</a> >#{{data.name}}</p>
</a> </a>
{{/each}} {{/each}}
</div> </div>
@@ -8,7 +8,13 @@ export default class ReadingTime extends Component {
let leftOverMinutes = totalMinutes % 60; let leftOverMinutes = totalMinutes % 60;
let totalHours = (totalMinutes - leftOverMinutes) / 60; let totalHours = (totalMinutes - leftOverMinutes) / 60;
return `${totalHours}h ${leftOverMinutes}m`; if (leftOverMinutes >= 35) {
totalHours += 1;
leftOverMinutes = 0;
return `${totalHours}h`;
} else {
return `${totalHours}h ${leftOverMinutes}m`;
}
} }
<template> <template>
@@ -34,6 +40,11 @@ export default class ReadingTime extends Component {
src="/plugins/discourse-rewind/images/books/{{@report.data.isbn}}.jpg" src="/plugins/discourse-rewind/images/books/{{@report.data.isbn}}.jpg"
/> />
</div> </div>
{{#if @report.data.series}}
<div class="book-series one"></div>
<div class="book-series two"></div>
<div class="book-series three"></div>
{{/if}}
</div> </div>
</div> </div>
</div> </div>
@@ -3,6 +3,7 @@ import { on } from "@ember/modifier";
import { action } from "@ember/object"; import { action } from "@ember/object";
import didInsert from "@ember/render-modifiers/modifiers/did-insert"; import didInsert from "@ember/render-modifiers/modifiers/did-insert";
import { htmlSafe } from "@ember/template"; import { htmlSafe } from "@ember/template";
import concatClass from "discourse/helpers/concat-class";
import emoji from "discourse/helpers/emoji"; import emoji from "discourse/helpers/emoji";
import discourseLater from "discourse-common/lib/later"; import discourseLater from "discourse-common/lib/later";
@@ -45,6 +46,10 @@ export default class WordCard extends Component {
}; };
} }
get longWord() {
return this.args.word.length >= 7;
}
get cardStyle() { get cardStyle() {
return htmlSafe(`${this.randomStyle}; ${this.mysteryData.color};`); return htmlSafe(`${this.randomStyle}; ${this.mysteryData.color};`);
} }
@@ -72,7 +77,10 @@ export default class WordCard extends Component {
<div <div
{{on "click" this.handleClick}} {{on "click" this.handleClick}}
{{on "mouseleave" this.handleLeave}} {{on "mouseleave" this.handleLeave}}
class="rewind-card__wrapper" class={{concatClass
"rewind-card__wrapper"
(if this.longWord "-long-word")
}}
style={{this.cardStyle}} style={{this.cardStyle}}
{{didInsert this.registerCardContainer}} {{didInsert this.registerCardContainer}}
role="button" role="button"
@@ -1 +1 @@
<Rewind /> <Rewind />
@@ -4,9 +4,13 @@
gap: 0.5em; gap: 0.5em;
flex-wrap: wrap; flex-wrap: wrap;
} }
.rewind-card { .rewind-card {
@include rewind-border; @include rewind-border;
width: max-content;
flex-grow: 1;
&:hover {
background-color: var(--secondary-very-high);
}
} }
} }
+86 -3
View File
@@ -15,6 +15,7 @@
position: relative; position: relative;
transform-style: preserve-3d; transform-style: preserve-3d;
transform: rotateY(-20deg); transform: rotateY(-20deg);
z-index: 2;
} }
p.reading-time__text { p.reading-time__text {
@@ -76,8 +77,8 @@ p.reading-time__text {
#fff 80%, #fff 80%,
#f9f9f9 85%, #f9f9f9 85%,
#fff 90%, #fff 90%,
#f9f9f9 95%, #b6b6b6 95%,
#fff 100% #b6b6b6 100%
); );
} }
@@ -91,6 +92,7 @@ p.reading-time__text {
transform: translateZ(-17.5px); transform: translateZ(-17.5px);
background-color: var(--book-color); background-color: var(--book-color);
border-radius: 0 5px 5px 0; border-radius: 0 5px 5px 0;
box-shadow: 0px 0px 1px 1px rgba(0, 0, 0, 0.25);
@media screen and (width <= 475px) { @media screen and (width <= 475px) {
width: 100px; width: 100px;
height: 133px; height: 133px;
@@ -115,6 +117,87 @@ p.reading-time__text {
justify-content: space-around; justify-content: space-around;
align-items: center; align-items: center;
background-color: var(--secondary); background-color: var(--secondary);
--book-color: rgba(var(--primary-rgb), 0.4); --book-color: var(--primary-very-high);
@include rewind-border; @include rewind-border;
} }
.book-series {
width: 150px;
height: 200px;
@media screen and (width <= 475px) {
width: 100px;
height: 133px;
}
position: relative;
transform-style: preserve-3d;
transform: rotateY(-20deg);
position: absolute;
background-color: var(--book-color);
border-radius: 0 5px 5px 0;
box-shadow: 0px 0px 1px 1px rgba(0, 0, 0, 0.25);
z-index: 1;
&::before {
position: absolute;
content: " ";
background-color: blue;
left: 0;
top: 4px;
width: 33px;
height: 192px;
@media screen and (width <= 475px) {
left: -43px;
width: 22px;
height: 125px;
}
transform: translateX(128.5px) rotateY(90deg);
background: linear-gradient(
90deg,
#fff 0%,
#f9f9f9 5%,
#fff 10%,
#f9f9f9 15%,
#fff 20%,
#f9f9f9 25%,
#fff 30%,
#f9f9f9 35%,
#fff 40%,
#f9f9f9 45%,
#fff 50%,
#f9f9f9 55%,
#fff 60%,
#f9f9f9 65%,
#fff 70%,
#f9f9f9 75%,
#fff 80%,
#f9f9f9 85%,
#fff 90%,
#b6b6b6 95%,
#b6b6b6 100%
);
}
&.one {
top: 3px;
left: 14px;
@media screen and (width <= 475px) {
top: 3px;
left: 11px;
}
}
&.two {
top: 5px;
left: 22px;
z-index: -1;
@media screen and (width <= 475px) {
top: 5px;
left: 17px;
}
}
&.three {
top: 7px;
left: 31px;
z-index: -2;
@media screen and (width <= 475px) {
display: none;
}
}
}
+10
View File
@@ -137,6 +137,16 @@
0 0 / 6px 6px, 0 0 / 6px 6px,
var(--secondary-low); var(--secondary-low);
} }
&.-long-word .rewind-card__title {
font-size: var(--font-0);
}
&.-long-word .rewind-card {
padding: 2px;
}
.rewind-card__title {
overflow-wrap: anywhere;
hyphens: auto;
}
.rewind-card__image { .rewind-card__image {
image-rendering: pixelated; image-rendering: pixelated;
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 178 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 106 KiB