render rewind in ember

This commit is contained in:
Joffrey JAFFEUX 2024-12-12 17:38:25 +01:00
parent b56070313e
commit 5d165376a1
20 changed files with 84 additions and 134 deletions

View File

@ -4,9 +4,4 @@ Display stats on your last year of Discourse usage.
## Usage
- add `http://127.0.0.1:4200/rewinds?` in `SiteSetting.allowed_iframes`
- example embed of a rewind in a post:
```
<iframe src="http://127.0.0.1:4200/rewinds?year=2024&username=j.jaffeux" width="320" height="500" frameborder="0" style="border:0;" allowfullscreen="" aria-hidden="false" tabindex="0" />
```
Navigate to `/my/activity/rewind`

View File

@ -1,32 +0,0 @@
# frozen_string_literal: true
module ::DiscourseRewind
class RewindsAssetsController < ::ApplicationController
requires_plugin PLUGIN_NAME
skip_before_action :preload_json, :check_xhr, only: %i[show]
skip_before_action :verify_authenticity_token, only: %i[show]
def show
no_cookies
name = params[:name]
path, content_type =
if name == "rewind"
%w[rewind.css text/css]
else
raise Discourse::NotFound
end
content = File.read(DiscourseRewind.public_asset_path("css/#{path}"))
# note, path contains a ":version" which automatically busts the cache
# based on file content, so this is safe
response.headers["Last-Modified"] = 10.years.ago.httpdate
response.headers["Content-Length"] = content.bytesize.to_s
immutable_for 1.year
render plain: content, disposition: :nil, content_type: content_type
end
end
end

View File

@ -4,16 +4,11 @@ module ::DiscourseRewind
class RewindsController < ::ApplicationController
requires_plugin PLUGIN_NAME
skip_before_action :preload_json, :check_xhr, :redirect_to_login_if_required, only: %i[show]
def show
# expires_in 1.minute, public: false
response.headers["X-Robots-Tag"] = "noindex"
DiscourseRewind::Rewind::Fetch.call(service_params) do
on_success do |reports:|
@reports = reports
render "show", layout: false
render json: MultiJson.dump(reports), status: 200
end
end
end

View File

@ -1,25 +0,0 @@
# frozen_string_literal: true
module DiscourseRewind
module RewindsHelper
# keeping it here for caching
def self.rewind_asset_url(asset_name)
if !%w[rewind.css].include?(asset_name)
raise StandardError, "unknown asset type #{asset_name}"
end
@urls ||= {}
url = @urls[asset_name]
return url if url
content = File.read(DiscourseRewind.public_asset_path("css/#{asset_name}"))
sha1 = Digest::SHA1.hexdigest(content)
url = "/rewinds/assets/#{sha1}/#{asset_name}"
@urls[asset_name] = GlobalPath.cdn_path(url)
end
def rewind_asset_url(asset_name)
DiscourseRewind::RewindsHelper.rewind_asset_url(asset_name)
end
end
end

View File

@ -5,11 +5,7 @@ module DiscourseRewind
#
# @example
# ::DiscourseRewind::Rewind::Fetch.call(
# guardian: guardian,
# params: {
# username: "falco",
# year: 2024,
# }
# guardian: guardian
# )
#
class Rewind::Fetch
@ -30,34 +26,26 @@ module DiscourseRewind
CACHE_DURATION = 5.minutes
params do
attribute :year, :integer
attribute :username, :string
validates :year, presence: true
validates :username, presence: true
end
model :user
model :date
model :reports
private
def fetch_user(params:)
User.find_by_username(params.username)
def fetch_user(guardian:)
User.find_by_username(guardian.user.username)
end
def fetch_date(params:)
Date.new(params.year).all_year
Date.new(2024).all_year
end
def fetch_reports(params:, date:, user:, guardian:)
key = "rewind:#{params.username}:#{params.year}"
def fetch_reports(date:, user:, guardian:)
key = "rewind:#{guardian.user.username}:#{2024}"
reports = Discourse.redis.get(key)
if Rails.env.development? || !reports
reports = REPORTS.map { |report| report.call(params:, date:, user:, guardian:) }
reports = REPORTS.map { |report| report.call(date:, user:, guardian:) }
Discourse.redis.setex(key, CACHE_DURATION, MultiJson.dump(reports))
else
reports = MultiJson.load(reports, symbolize_keys: true)

View File

@ -1 +0,0 @@
POSTING CALENDAR

View File

@ -1 +0,0 @@
READING TIME

View File

@ -1,24 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title><%= I18n.t("discourse_rewind.title", title: "RETRO TITLE", site_name: SiteSetting.title) %></title>
<meta property="og:title" content="<%= I18n.t("discourse_rewind.title", title: "RETRO TITLE", site_name: SiteSetting.title) %>">
<meta property="og:description" content="DESC">
<meta property="og:type" content="website">
<meta property="og:url" content="<%= request.original_url %>">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="<%= I18n.t("discourse_rewind.title", title: "RETRO TITLE", site_name: SiteSetting.title) %>">
<meta name="twitter:description" content="DESC">
<meta name="viewport" content="width=device-width">
<link rel="stylesheet" href="<%= rewind_asset_url("rewind.css") %>">
</head>
<body>
<div class="rewind__wrapper">
<div class="rewind">
<%- @reports.each do |report| %>
<%= render report[:identifier] %>
<%- end %>
</div>
</div>
</body>
</html>

View File

@ -0,0 +1,27 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
export default class Rewind extends Component {
@tracked rewind = [];
@action
async loadRewind() {
try {
this.rewind = await ajax("/rewinds");
} catch (e) {
popupAjaxError(e);
}
}
<template>
<div class="rewind" {{didInsert this.loadRewind}}>
{{#each this.rewind as |report|}}
<p>{{report.identifier}}</p>
{{/each}}
</div>
</template>
}

View File

@ -0,0 +1,17 @@
import Component from "@glimmer/component";
import DNavigationItem from "discourse/components/d-navigation-item";
import icon from "discourse-common/helpers/d-icon";
import { i18n } from "discourse-i18n";
export default class RewindTab extends Component {
<template>
<DNavigationItem
@route="userActivity.rewind"
@ariaCurrentContext="subNav"
class="user-nav__activity-rewind"
>
{{icon "repeat"}}
<span>{{i18n "rewind.title"}}</span>
</DNavigationItem>
</template>
}

View File

@ -0,0 +1,11 @@
export default function () {
this.route(
"user",
{ path: "/u/:username", resetNamespace: true },
function () {
this.route("userActivity", function () {
this.route("rewind");
});
}
);
}

View File

@ -0,0 +1,5 @@
import DiscourseRoute from "discourse/routes/discourse";
export default class UserActivityRewind extends DiscourseRoute {
templateName = "user/rewind";
}

View File

@ -0,0 +1 @@
<Rewind />

View File

@ -0,0 +1 @@
@import "rewind";

View File

@ -0,0 +1,6 @@
.rewind {
width: 280px;
height: 400px;
background-color: var(--secondary-high);
border-radius: var(--d-border-radius);
}

View File

View File

View File

@ -1,8 +1,5 @@
# frozen_string_literal: true
DiscourseRewind::Engine.routes.draw do
get "/rewinds" => "rewinds#show"
get "/rewinds/assets/:version/:name" => "rewinds_assets#show"
end
DiscourseRewind::Engine.routes.draw { get "/rewinds" => "rewinds#show" }
Discourse::Application.routes.draw { mount ::DiscourseRewind::Engine, at: "/" }

View File

@ -10,6 +10,12 @@
enabled_site_setting :discourse_rewind_enabled
register_svg_icon "repeat"
register_asset "stylesheets/common/index.scss"
register_asset "stylesheets/desktop/index.scss", :desktop
register_asset "stylesheets/mobile/index.scss", :mobile
module ::DiscourseRewind
PLUGIN_NAME = "discourse-rewind"

View File

@ -1,16 +0,0 @@
/* RESET CSS */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }
ul[role='list'], ol[role='list'] { list-style: none; }
html:focus-within { scroll-behavior: smooth; }
a:not([class]) { text-decoration-skip-ink: auto; }
input, button, textarea, select { font: inherit; }
body, html { height: 100%; scroll-behavior: smooth; }
/* END RESET CSS */
.rewind {
display: flex;
height: 100vh;
background-color: #f5f5f5;
border-radius: 5px;
}