+1
-1
.formatter.exs
+1
-1
.formatter.exs
+1
-34
.gitignore
+1
-34
.gitignore
···
1
1
node_modules
2
-
3
-
# Output
4
2
.output
5
3
.vercel
6
4
.netlify
···
8
6
.svelte-kit
9
7
build
10
8
.elixir_ls
11
-
12
-
# OS
13
9
.DS_Store
14
10
Thumbs.db
15
-
16
-
# Env
17
11
.env
18
12
.env.*
19
13
!.env.example
20
14
!.env.test
21
15
.envrc
22
16
.direnv
23
-
24
-
# Vite
25
17
vite.config.js.timestamp-*
26
18
vite.config.ts.timestamp-*
27
-
28
-
# Nix
29
19
result
30
-
31
-
# The directory Mix will write compiled artifacts to.
32
20
/_build/
33
-
34
-
# If you run "mix test --cover", coverage assets end up here.
35
21
/cover/
36
-
37
-
# The directory Mix downloads your dependencies sources to.
38
22
/deps/
39
-
40
-
# Where 3rd-party dependencies like ExDoc output generated docs.
41
23
/doc/
42
-
43
-
# Ignore .fetch files in case you like to edit your project deps locally.
44
24
/.fetch
45
-
46
-
# If the VM crashes, it generates a dump, let's ignore it too.
47
25
erl_crash.dump
48
-
49
-
# Also ignore archive artifacts (built via "mix archive.build").
50
26
*.ez
51
-
52
-
# Temporary files, for example, from tests.
53
27
/tmp/
54
-
55
-
# Ignore package tarball (built via "mix hex.build").
56
28
comet-*.tar
57
-
58
-
# Ignore assets that are produced by build tools.
59
29
/priv/static/assets/
60
-
61
-
# Ignore digested assets cache.
30
+
/priv/static/hologram/
62
31
/priv/static/cache_manifest.json
63
-
64
-
# In case you use Node.js/npm, you want to ignore these.
65
32
npm-debug.log
66
33
/assets/node_modules/
67
34
+5
-1
.vscode/settings.json
+5
-1
.vscode/settings.json
+1
assets/css/app.css
+1
assets/css/app.css
+16
lib/comet_app/components/post_preview.ex
+16
lib/comet_app/components/post_preview.ex
···
1
+
defmodule CometApp.Components.PostPreview do
2
+
use Hologram.Component
3
+
alias Hologram.UI.Link
4
+
5
+
prop :post, :map
6
+
7
+
def template do
8
+
~HOLO"""
9
+
<article class="post-preview">
10
+
<h2>{@post.title}</h2>
11
+
<p>{@post.excerpt}</p>
12
+
<Link to={CometApp.PostPage, id: @post.id}>Read more</Link>
13
+
</article>
14
+
"""
15
+
end
16
+
end
+6
lib/comet_app/layouts/main.ex
+6
lib/comet_app/layouts/main.ex
+18
lib/comet_app/layouts/main.holo
+18
lib/comet_app/layouts/main.holo
···
1
+
<!DOCTYPE html>
2
+
<html lang="en">
3
+
<head>
4
+
<meta charset="utf-8" />
5
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6
+
<title>Comet App</title>
7
+
<link phx-track-static rel="stylesheet" href="/assets/css/app.css" />
8
+
<Runtime />
9
+
</head>
10
+
<body>
11
+
<nav class="bg-red-500 text-2xl">
12
+
<Link to={CometApp.HomePage}>Home</Link>
13
+
</nav>
14
+
<main>
15
+
<slot />
16
+
</main>
17
+
</body>
18
+
</html>
+30
lib/comet_app/pages/home.ex
+30
lib/comet_app/pages/home.ex
···
1
+
defmodule CometApp.HomePage do
2
+
use Hologram.Page
3
+
alias CometApp.Components.PostPreview
4
+
5
+
route "/"
6
+
7
+
layout CometApp.MainLayout
8
+
9
+
def init(_params, component, _server) do
10
+
# In real app, fetch from database
11
+
posts = [
12
+
%{id: 1, title: "First Post", excerpt: "This is my first post"},
13
+
%{id: 2, title: "Second Post", excerpt: nil}
14
+
]
15
+
16
+
put_state(component, :posts, posts)
17
+
end
18
+
19
+
def template do
20
+
~HOLO"""
21
+
<h1>Welcome to my Blog</h1>
22
+
23
+
<div class="posts">
24
+
{%for post <- @posts}
25
+
<PostPreview post={post} />
26
+
{/for}
27
+
</div>
28
+
"""
29
+
end
30
+
end
+48
lib/comet_app/pages/post_view.ex
+48
lib/comet_app/pages/post_view.ex
···
1
+
defmodule CometApp.PostPage do
2
+
use Hologram.Page
3
+
4
+
route "/posts/:id"
5
+
6
+
param :id, :integer
7
+
8
+
layout CometApp.MainLayout
9
+
10
+
def init(params, component, _server) do
11
+
# In real app, fetch from database
12
+
post = %{
13
+
id: params.id,
14
+
title: "Example Post",
15
+
content: "This is the full content...",
16
+
likes: 0
17
+
}
18
+
19
+
put_state(component, :post, post)
20
+
end
21
+
22
+
def template do
23
+
~HOLO"""
24
+
<article>
25
+
<h1>{@post.title}</h1>
26
+
<p>{@post.content}</p>
27
+
28
+
<div class="likes">
29
+
Likes: {@post.likes}
30
+
<button $click="like_post">Like</button>
31
+
</div>
32
+
</article>
33
+
"""
34
+
end
35
+
36
+
def action(:like_post, _params, component) do
37
+
# Update likes locally first for instant feedback
38
+
component
39
+
|> put_state([:post, :likes], component.state.post.likes + 1)
40
+
|> put_command(:save_like, post_id: component.state.post.id)
41
+
end
42
+
43
+
def command(:save_like, params, server) do
44
+
# In real app, save to database
45
+
IO.puts("Liked post #{params.post_id}")
46
+
server
47
+
end
48
+
end
+2
-1
lib/comet_web/endpoint.ex
+2
-1
lib/comet_web/endpoint.ex
···
24
24
at: "/",
25
25
from: :comet,
26
26
gzip: not code_reloading?,
27
-
only: CometWeb.static_paths(),
27
+
only: ["hologram" | CometWeb.static_paths()],
28
28
raise_on_missing_only: code_reloading?
29
29
30
30
# Code reloading can be explicitly enabled under the
···
51
51
plug Plug.MethodOverride
52
52
plug Plug.Head
53
53
plug Plug.Session, @session_options
54
+
plug Hologram.Router
54
55
plug CometWeb.Router
55
56
end
+3
-2
mix.exs
+3
-2
mix.exs
···
10
10
start_permanent: Mix.env() == :prod,
11
11
aliases: aliases(),
12
12
deps: deps(),
13
-
compilers: [:phoenix_live_view] ++ Mix.compilers(),
13
+
compilers: [:phoenix_live_view, :hologram] ++ Mix.compilers(),
14
14
listeners: [Phoenix.CodeReloader]
15
15
]
16
16
end
···
69
69
{:atex, "~> 0.6"},
70
70
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
71
71
{:drinkup, "~> 0.1"},
72
-
{:typedstruct, "~> 0.5"}
72
+
{:typedstruct, "~> 0.5"},
73
+
{:hologram, "~> 0.6.5"}
73
74
]
74
75
end
75
76
+6
mix.lock
+6
mix.lock
···
1
1
%{
2
2
"atex": {:hex, :atex, "0.6.0", "a02f3c1b3ef04d8cd30243a05fc3629929c66d826e1d6a7e9d4ec6076ac89aea", [:mix], [{:ex_cldr, "~> 2.42", [hex: :ex_cldr, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:jose, "~> 1.11", [hex: :jose, repo: "hexpm", optional: false]}, {:multiformats_ex, "~> 0.2", [hex: :multiformats_ex, repo: "hexpm", optional: false]}, {:peri, "~> 0.6", [hex: :peri, repo: "hexpm", optional: false]}, {:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}, {:recase, "~> 0.5", [hex: :recase, repo: "hexpm", optional: false]}, {:req, "~> 0.5", [hex: :req, repo: "hexpm", optional: false]}, {:typedstruct, "~> 0.5", [hex: :typedstruct, repo: "hexpm", optional: false]}], "hexpm", "a3615e361e1e1b2887910834b3ede88680a02e4d585243ea90d0a6394f688aa2"},
3
3
"bandit": {:hex, :bandit, "1.8.0", "c2e93d7e3c5c794272fa4623124f827c6f24b643acc822be64c826f9447d92fb", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "8458ff4eed20ff2a2ea69d4854883a077c33ea42b51f6811b044ceee0fa15422"},
4
+
"beam_file": {:hex, :beam_file, "0.6.2", "efd54ec60be6a03f0a8f96f72b0353427196613289c46032d3500f0ab6c34d32", [:mix], [], "hexpm", "09a99e8e5aad674edcad7213b0d7602375dfd3c7d02f8e3136e3efae0bcc9c56"},
4
5
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"},
5
6
"car": {:hex, :car, "0.1.1", "a5bc4c5c1be96eab437634b3c0ccad1fe17b5e3d68c22a4031241ae1345aebd4", [:mix], [{:cbor, "~> 1.0.0", [hex: :cbor, repo: "hexpm", optional: false]}, {:typedstruct, "~> 0.5", [hex: :typedstruct, repo: "hexpm", optional: false]}, {:varint, "~> 1.4", [hex: :varint, repo: "hexpm", optional: false]}], "hexpm", "f895dda8123d04dd336db5a2bf0d0b47f4559cd5383f83fcca0700c1b45bfb6a"},
6
7
"cbor": {:hex, :cbor, "1.0.1", "39511158e8ea5a57c1fcb9639aaa7efde67129678fee49ebbda780f6f24959b0", [:mix], [], "hexpm", "5431acbe7a7908f17f6a9cd43311002836a34a8ab01876918d8cfb709cd8b6a2"},
···
23
24
"finch": {:hex, :finch, "0.20.0", "5330aefb6b010f424dcbbc4615d914e9e3deae40095e73ab0c1bb0968933cadf", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "2658131a74d051aabfcba936093c903b8e89da9a1b63e430bee62045fa9b2ee2"},
24
25
"fine": {:hex, :fine, "0.1.4", "b19a89c1476c7c57afb5f9314aed5960b5bc95d5277de4cb5ee8e1d1616ce379", [:mix], [], "hexpm", "be3324cc454a42d80951cf6023b9954e9ff27c6daa255483b3e8d608670303f5"},
25
26
"gettext": {:hex, :gettext, "1.0.2", "5457e1fd3f4abe47b0e13ff85086aabae760497a3497909b8473e0acee57673b", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "eab805501886802071ad290714515c8c4a17196ea76e5afc9d06ca85fb1bfeb3"},
27
+
"gproc": {:hex, :gproc, "1.0.0", "aa9ec57f6c9ff065b16d96924168d7c7157cd1fd457680efe4b1274f456fa500", [:rebar3], [], "hexpm", "109f253c2787de8a371a51179d4973230cbec6239ee673fa12216a5ce7e4f902"},
26
28
"gun": {:hex, :gun, "2.2.0", "b8f6b7d417e277d4c2b0dc3c07dfdf892447b087f1cc1caff9c0f556b884e33d", [:make, :rebar3], [{:cowlib, ">= 2.15.0 and < 3.0.0", [hex: :cowlib, repo: "hexpm", optional: false]}], "hexpm", "76022700c64287feb4df93a1795cff6741b83fb37415c40c34c38d2a4645261a"},
27
29
"heroicons": {:git, "https://github.com/tailwindlabs/heroicons.git", "0435d4ca364a608cc75e2f8683d374e55abbae26", [tag: "v2.2.0", sparse: "optimized", depth: 1]},
30
+
"hologram": {:hex, :hologram, "0.6.5", "355312e414489f590520efa2ccccf1719c415793225a87330407772efcaa0a78", [:mix], [{:beam_file, "0.6.2", [hex: :beam_file, repo: "hexpm", optional: false]}, {:file_system, "~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:gproc, "~> 1.0", [hex: :gproc, repo: "hexpm", optional: false]}, {:html_entities, "~> 0.5", [hex: :html_entities, repo: "hexpm", optional: false]}, {:interceptor, "~> 0.5", [hex: :interceptor, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.7", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:uuid, "~> 1.0", [hex: :uuid, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "8b351690087b9980e60d4a2992cfceb4637e2a2082afdfc78060f569299abdc6"},
28
31
"hpax": {:hex, :hpax, "1.0.3", "ed67ef51ad4df91e75cc6a1494f851850c0bd98ebc0be6e81b026e765ee535aa", [:mix], [], "hexpm", "8eab6e1cfa8d5918c2ce4ba43588e894af35dbd8e91e6e55c817bca5847df34a"},
32
+
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
29
33
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
34
+
"interceptor": {:hex, :interceptor, "0.5.4", "158e019413439714306d52ff5189533b1236ab776b6f7a1ce63ace079f84867c", [:mix], [], "hexpm", "a4fa78a73199832222c4bb47c57e5b7384f7b49d43c09a57c6e731086f219f95"},
30
35
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"},
31
36
"jose": {:hex, :jose, "1.11.12", "06e62b467b61d3726cbc19e9b5489f7549c37993de846dfb3ee8259f9ed208b3", [:mix, :rebar3], [], "hexpm", "31e92b653e9210b696765cdd885437457de1add2a9011d92f8cf63e4641bab7b"},
32
37
"lazy_html": {:hex, :lazy_html, "0.1.8", "677a8642e644eef8de98f3040e2520d42d0f0f8bd6c5cd49db36504e34dffe91", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.9.0", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:fine, "~> 0.1.0", [hex: :fine, repo: "hexpm", optional: false]}], "hexpm", "0d8167d930b704feb94b41414ca7f5779dff9bca7fcf619fcef18de138f08736"},
···
57
62
"thousand_island": {:hex, :thousand_island, "1.4.2", "735fa783005d1703359bbd2d3a5a3a398075ba4456e5afe3c5b7cf4666303d36", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1c7637f16558fc1c35746d5ee0e83b18b8e59e18d28affd1f2fa1645f8bc7473"},
58
63
"typedstruct": {:hex, :typedstruct, "0.5.4", "d1d33d58460a74f413e9c26d55e66fd633abd8ac0fb12639add9a11a60a0462a", [:make, :mix], [], "hexpm", "ffaef36d5dbaebdbf4ed07f7fb2ebd1037b2c1f757db6fb8e7bcbbfabbe608d8"},
59
64
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.1", "a48703a25c170eedadca83b11e88985af08d35f37c6f664d6dcfb106a97782fc", [:rebar3], [], "hexpm", "b3a917854ce3ae233619744ad1e0102e05673136776fb2fa76234f3e03b23642"},
65
+
"uuid": {:hex, :uuid, "1.1.8", "e22fc04499de0de3ed1116b770c7737779f226ceefa0badb3592e64d5cfb4eb9", [:mix], [], "hexpm", "c790593b4c3b601f5dc2378baae7efaf5b3d73c4c6456ba85759905be792f2ac"},
60
66
"varint": {:hex, :varint, "1.5.1", "17160c70d0428c3f8a7585e182468cac10bbf165c2360cf2328aaa39d3fb1795", [:mix], [], "hexpm", "24f3deb61e91cb988056de79d06f01161dd01be5e0acae61d8d936a552f1be73"},
61
67
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
62
68
"websock_adapter": {:hex, :websock_adapter, "0.5.9", "43dc3ba6d89ef5dec5b1d0a39698436a1e856d000d84bf31a3149862b01a287f", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "5534d5c9adad3c18a0f58a9371220d75a803bf0b9a3d87e6fe072faaeed76a08"},