|
1 | 1 | defmodule CodebattleWeb.Tournament.ImageController do |
2 | 2 | use CodebattleWeb, :controller |
| 3 | + use Gettext, backend: CodebattleWeb.Gettext |
3 | 4 |
|
4 | 5 | alias Codebattle.Tournament |
5 | 6 |
|
6 | 7 | def show(conn, %{"id" => id}) do |
7 | | - # TODO: add ets cache for image |
| 8 | + # TODO: add ETS cache for image |
8 | 9 | case Tournament.Context.get(id) do |
9 | 10 | nil -> |
10 | 11 | send_resp(conn, :ok, "") |
11 | 12 |
|
12 | 13 | tournament -> |
13 | | - {:ok, image} = |
14 | | - tournament |
15 | | - |> render_image() |
16 | | - |> HtmlToImage.convert(width: 777, quality: 100) |
| 14 | + html_content = render_image(tournament) |
| 15 | + {:ok, image} = generate_png(html_content) |
17 | 16 |
|
18 | 17 | conn |
19 | | - |> put_resp_content_type("image/jpeg") |
20 | | - |> send_resp(200, image) |
| 18 | + |> put_resp_content_type("image/png") |
| 19 | + |> send_resp(200, Base.decode64!(image)) |
21 | 20 | end |
22 | 21 | end |
23 | 22 |
|
24 | 23 | defp render_image(tournament) do |
25 | | - ~s(<html style="background-color:#dee2e6;"> |
26 | | - <center style="padding:25px;"> |
27 | | - <img src="https://codebattle.hexlet.io/assets/images/logo.svg" alt="Logo"> |
28 | | - <span>The Codebattle</span> |
29 | | - <h1>Tournament</h1> |
30 | | - #{render_content(tournament)} |
31 | | - <p>Made with <span style="color: #e25555;">♥</span> by CodebattleCoreTeam</p> |
32 | | - <p>Dear frontenders, pls, make it prettier, thx</p> |
33 | | - </center> |
34 | | - </html>) |
| 24 | + """ |
| 25 | + <html> |
| 26 | + <head> |
| 27 | + <meta charset="utf-8"> |
| 28 | + <style> |
| 29 | + html, body { |
| 30 | + margin: 0; |
| 31 | + padding: 0; |
| 32 | + /* Let them expand to the “browser” size (which we'll define via ChromicPDF) */ |
| 33 | + width: 100%; |
| 34 | + height: 100%; |
| 35 | + background: #f5f7fa; |
| 36 | + font-family: 'Helvetica Neue', Arial, sans-serif; /* Change to desired font */ |
| 37 | + } |
| 38 | + .card { |
| 39 | + /* Fill the entire viewport */ |
| 40 | + width: 100%; |
| 41 | + height: 100%; |
| 42 | + background: #ffffff; |
| 43 | + border-radius: 8px; |
| 44 | + box-shadow: 0 4px 12px rgba(0,0,0,0.15); |
| 45 | + overflow: hidden; |
| 46 | + display: flex; |
| 47 | + flex-direction: column; |
| 48 | + } |
| 49 | + .header { |
| 50 | + background: linear-gradient(135deg, #667eea, #764ba2); |
| 51 | + background: #000; /* Dark background */ |
| 52 | + font-family: 'Helvetica Neue', Arial, sans-serif; /* Change to desired font */ |
| 53 | + color: #fff; /* White text */ |
| 54 | + text-align: center; |
| 55 | + } |
| 56 | + .header img { |
| 57 | + width: 60px; |
| 58 | + height: auto; |
| 59 | + } |
| 60 | + .content { |
| 61 | + flex: 1; |
| 62 | + padding: 10px; |
| 63 | + color: #333; |
| 64 | + text-align: center; |
| 65 | + display: flex; |
| 66 | + flex-direction: column; |
| 67 | + justify-content: center; |
| 68 | + } |
| 69 | + .footer { |
| 70 | + text-align: center; |
| 71 | + font-size: 10px; |
| 72 | + color: #aaa; |
| 73 | + padding: 5px; |
| 74 | + background: #f0f0f0; |
| 75 | + } |
| 76 | + </style> |
| 77 | + </head> |
| 78 | + <body> |
| 79 | + <div class="card"> |
| 80 | + <div class="header"> |
| 81 | + <img src="#{logo_url()}" alt="Logo"> |
| 82 | + <h1>#{tournament.name}</h1> |
| 83 | + </div> |
| 84 | + <div class="content"> |
| 85 | + #{render_content(tournament)} |
| 86 | + </div> |
| 87 | + <div class="footer"> |
| 88 | + Made with ♥ by Codebattle |
| 89 | + </div> |
| 90 | + </div> |
| 91 | + </body> |
| 92 | + </html> |
| 93 | + """ |
| 94 | + end |
| 95 | + |
| 96 | + defp logo_url do |
| 97 | + if logo = Application.get_env(:codebattle, :collab_logo) do |
| 98 | + logo |
| 99 | + else |
| 100 | + "https://codebattle.hexlet.io/assets/images/logo.svg" |
| 101 | + end |
35 | 102 | end |
36 | 103 |
|
37 | 104 | defp render_content(tournament) do |
38 | | - ~s( |
39 | | - <h3>#{tournament.name}</h3> |
40 | | - <h4>Type: #{tournament.type}/#{tournament.level}</h4> |
41 | | - <h4></h4> |
42 | | - <h4>State: #{tournament.state}</h4> |
43 | | - <h4>StartsAt: #{tournament.starts_at} UTC</h4> |
44 | | - <p>Creator</p> |
45 | | - <h4>#{render_user(tournament.creator)}</h4> |
46 | | -
|
47 | | - ) |
| 105 | + type = to_string(tournament.type) |
| 106 | + state = to_string(tournament.state) |
| 107 | + |
| 108 | + """ |
| 109 | + <h4>#{gettext("Type: %{type}", type: type)}</h4> |
| 110 | + <h4>#{gettext("State: %{state}", state: state)}</h4> |
| 111 | + <h4>#{gettext("Starts At")}: #{tournament.starts_at} UTC</h4> |
| 112 | + """ |
48 | 113 | end |
49 | 114 |
|
50 | | - defp render_user(u) do |
51 | | - ~s( |
52 | | - <div style="display:inline-block"> |
53 | | - <center> |
54 | | - <img src="https://avatars0.githubusercontent.com/u/#{u.github_id}" style="width:46px; height:46px"> |
55 | | - <p>@#{u.name}\(#{u.lang}\)-#{u.rating}</p> |
56 | | - </center> |
57 | | - </div> |
58 | | - ) |
| 115 | + defp generate_png(html_content) do |
| 116 | + ChromicPDF.capture_screenshot({:html, html_content}, capture_screenshot: %{format: "png"}) |
59 | 117 | end |
60 | 118 | end |
0 commit comments