Browse Source

feat(template): Tweaks to get docs on templating.

jackyalcine 6 months ago
parent
commit
da204fcc0b
Signed by: Jacky Alciné <yo@jacky.wtf> GPG Key ID: 537A4F904B15268D

+ 2
- 2
config/dev.exs View File

@@ -1,8 +1,8 @@
1 1
 use Mix.Config
2 2
 
3 3
 config :koype, Koype.Web.Endpoint,
4
-  debug_errors: false,
5
-  code_reloader: false,
4
+  debug_errors: true,
5
+  code_reloader: true,
6 6
   check_origin: false,
7 7
   watchers: [npm: ["run", "parcel:watch"]],
8 8
   reloadable_compilers: [

+ 0
- 27
docs/TEMPLATING.markdown View File

@@ -1,27 +0,0 @@
1
-# Templating
2
-Koype provides each templatable page with a dictionary of values that can be
3
-used to render information. This page documents what pages are intended to be
4
-templated and what information is available to them.
5
-
6
-## Pages
7
-* [`/`](#home) - Home page of the site.
8
-* [`/follow`](#subscribe) - Page for showing subscription information
9
-* [`/post/:id`](#post) - Viewing an individual post
10
-* [`/:slug`](#post) - Viewing an individual post
11
-* [`/tags`](#tagsIndex) - Pagination of categories
12
-* [`/tags/:id`](#tagsView) - Pagination of posts under a category
13
-* [`/stream`](#postIndex) - Pagination of posts
14
-
15
-### Home
16
-This page represents the entry page that someone visiting the site will see.
17
-
18
-| Property Path | Type | Description |
19
-| auth | Object | Holds information about authorize users' authentication status |
20
-| auth.signed_in | Boolean | Determines if a authorized user is signed in. |
21
-| domain | String | Provides the URI representing the root of this site. |
22
-| host | String | Provides the hostname of the site's domain. |
23
-| form | Object | Provides information from rendering forms on the site. |
24
-| form.csrf_token | String | Provides a string used for preventing CSRF. |
25
-| h | Object | Root microformat object representing the site. |
26
-| h.card | Object | Data representing the [representative `h-card`](https://indieweb.org/representative_h-card) of the site. |
27
-| h.feed | Object | Data providing [feed](https://indieweb.org/feed) information of the site. |

docs/RELEASE.markdown → docs/pages/release.md View File


+ 0
- 3
docs/pages/templating.md View File

@@ -1,3 +0,0 @@
1
-# Templating
2
-
3
-Koype provides a

+ 4
- 0
lib/feed.ex View File

@@ -20,6 +20,10 @@ defmodule Koype.Feed do
20 20
   @moduledoc false
21 21
   @semantic_types ~w(all responses content notifications category)a
22 22
 
23
+  def formats() do
24
+    [%{"name" => "JSON Feed", "type" => "json"}, %{"name" => "ATOM 1.0", "type" => "atom"}]
25
+  end
26
+
23 27
   def items(options \\ []) do
24 28
     kind = Keyword.get(options, :kind, :all)
25 29
 

+ 2
- 1
lib/post.ex View File

@@ -17,7 +17,6 @@
17 17
 # You should have received a copy of the GNU Affero General Public License
18 18
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
19 19
 defmodule Koype.Post do
20
-  @moduledoc false
21 20
   alias Phoenix.HTML.SimplifiedHelpers.Truncate, as: T
22 21
   import Inflex
23 22
 
@@ -51,8 +50,10 @@ defmodule Koype.Post do
51 50
     %{type: "rsvp", name: "RSVP", names: "RSVPs"}
52 51
   ]
53 52
 
53
+  @doc "Exposes information about known types."
54 54
   def known_types(), do: @known_types
55 55
 
56
+  @doc "Exposes information about known post types."
56 57
   def known_post_types(), do: known_types() |> Enum.map(&Map.get(&1, :type))
57 58
 
58 59
   # TODO: Allow users to define what types of posts can be exposed in Koype.

+ 29
- 0
lib/repo/entry.ex View File

@@ -17,6 +17,35 @@
17 17
 # You should have received a copy of the GNU Affero General Public License
18 18
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
19 19
 defmodule Koype.Repo.Entry do
20
+  @moduledoc """
21
+  Represents a persisted entry in Koype.
22
+
23
+  ## Data Structure
24
+
25
+  | Field | Type | Description |
26
+  | ---- | ---- | ---- |
27
+  | json | &lt;Content Structure&gt; | _See below_. |
28
+  | uri | `String` | The URI pointing to this entry. |
29
+  | interaction_count | `Integer` | The number of [Webmention](`Koype.Repo.Webmention`)s associated to this entry. |
30
+  | h_type | `String` | The class name for this [entry](`Koype.Repo.Entry`). |
31
+  | replied_to_self | `boolean` | Determines if this [entry](`Koype.Repo.Entry`) is a response to a [entry](`Koype.Repo.Entry`) created by this site. |
32
+  | updated_at | `Calendar.DateTime` | Sets the last time this [entry](`Koype.Repo.Entry`) was updated. |
33
+
34
+  ## Content Structure
35
+  The data structure for entries are very similar to that of what
36
+  [JSON Microformats2][1] would look like. However, you can expect the
37
+  following to be there:
38
+
39
+  | Field | Type | Description |
40
+  | ---- | ---- | ---- |
41
+  | h | `String` | The kind of entry this is.|
42
+  | content.html | `String` | The HTML representation of this post. |
43
+  | content.value | `String` | The internal representation of this post. |
44
+  | content.plain | `String` | A plain-text representation of this post. |
45
+  | x-generator | `Map` | A representation of an [`h-app`](https://indieweb.org/h-app) as a Map. |
46
+
47
+  """
48
+
20 49
   use Arc.Ecto.Schema
21 50
 
22 51
   use Koype.Repo.Base,

+ 21
- 0
lib/repo/webmention.ex View File

@@ -17,6 +17,26 @@
17 17
 # You should have received a copy of the GNU Affero General Public License
18 18
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
19 19
 defmodule Koype.Repo.Webmention do
20
+  @moduledoc """
21
+  Represents a persisted incoming Webmention in Koype.
22
+
23
+  ## Data Structure
24
+  This is the structure that the JSON data is stored as.
25
+  ```elixir
26
+  %{
27
+    "source" => %{
28
+      "published" => Calendar.DateTime,
29
+      "updated" => Calendar.DateTime,
30
+      "title" => String,
31
+      "content" => Map
32
+    },
33
+    "accessed" => Calendar.DateTime,
34
+    "author" => Map, // check IndieWeb.HCard
35
+    "mf2" => Map,
36
+    "url" => String
37
+  }
38
+  ```
39
+  """
20 40
   use Arc.Ecto.Schema
21 41
   require Logger
22 42
 
@@ -45,6 +65,7 @@ defmodule Koype.Repo.Webmention do
45 65
     timestamps()
46 66
   end
47 67
 
68
+  @doc false
48 69
   def transform_data(data: data, record: record) do
49 70
     mf2 = Map.get(data, :mf2, %{}) || %{}
50 71
     author = do_extract_author(record, data)

+ 15
- 2
lib/template.ex View File

@@ -25,10 +25,23 @@ defmodule Koype.Template do
25 25
   of the actual templating system to allow for different solutions to be
26 26
   used.
27 27
 
28
-  TODO: Provide method for fetching all definitions from disk.
29
-  TODO: Allow root directory to be configurable by Confex.
28
+  ## Pages
29
+  Given that `$THEME_ROOT` is the root directory at which the theme's files are defined,
30
+  the following is a mapping of pages that themes are expected to provide:
31
+
32
+  | Theme File Path | Route | Description |
33
+  | ---- | ---- | ---- |
34
+  | `home.html.liquid` | [`/`](`Koype.Web.PageController.index/2`) | Home page of the site |
35
+  | `follow.html.liquid` | [`/follow`](`Koype.Web.FeedController.index/2`) | Page for showing subscription information |
36
+  | `entry/view.html.liquid` | [`/post/:id`](`Koype.Web.EntryController.show/2`) | Viewing an individual post |
37
+  | `stream/page.html.liquid` | [`/stream`](`Koype.Web.TimelineController.sequential/2`) | Pagination of posts |
38
+
30 39
   """
40
+
31 41
   defprotocol Formatter do
42
+    @doc """
43
+    Presents structured data in a templating-friendly `Map`.
44
+    """
32 45
     @fallback_to_any true
33 46
     def format(object)
34 47
   end

+ 68
- 0
lib/template/decorator.ex View File

@@ -0,0 +1,68 @@
1
+defmodule Koype.Template.Decorator do
2
+  @moduledoc """
3
+  Provides metadata for the globally available template object.
4
+
5
+  This module wraps the default data provided to a page with more metadata that can be used
6
+  in templating.
7
+  """
8
+
9
+  @doc """
10
+  Decorates a `Map` with template-friendly metadata.
11
+
12
+  This takes a `Map` and a keyword list expecting the name of a theme and adds
13
+  extra values useful for presenting a theme.
14
+
15
+  ## Form
16
+  This provides fields useful for submitting a form to the site that's protected
17
+  by [CSRF](`Koype.Web.Plug.Client.CSRFInjection`).
18
+
19
+  | Field | Type | Description |
20
+  | ----- | ---- | ----------- |
21
+  | csrf_token | String | A one-time-use string meant to validate requests that demand CSRF protection. |
22
+  """
23
+  def decorate(data, theme: theme) do
24
+    Map.merge(data, %{
25
+      "form" => %{"csrf_token" => Phoenix.Controller.get_csrf_token()},
26
+      "h" => %{"card" => hcard(), "feed" => feed()},
27
+      "auth" => auth(data[:conn]),
28
+      "koype" => system(theme: theme)
29
+    })
30
+    |> Map.drop(:conn)
31
+  end
32
+
33
+  defp system(theme: theme) do
34
+    %{"version" => Koype.version(), "theme" => Koype.Theme.config_for(theme)}
35
+  end
36
+
37
+  defp hcard() do
38
+    %{
39
+      "uri" => Koype.host(),
40
+      "displayed_name" => Koype.Profile.displayed_name(),
41
+      "photo" => Koype.Profile.photo_uri(),
42
+      "note" => Koype.Profile.note(),
43
+      "name" => Koype.Profile.name(),
44
+      "nickname" => Koype.Profile.nickname(),
45
+      "timezone" => Koype.Profile.timezone()
46
+    }
47
+  end
48
+
49
+  # TODO: Add support for custom feeds generated.
50
+  defp feed() do
51
+    Enum.map(Koype.Post.known_types(), fn post_type_info ->
52
+      %{
53
+        "title" => Enum.join([post_type_info.names, "-", Koype.Profile.displayed_name()], " "),
54
+        "href" =>
55
+          Koype.host() <>
56
+            Koype.Web.Router.Helpers.timeline_path(Koype.Web.Endpoint, :sequential,
57
+              type: post_type_info.type
58
+            )
59
+      }
60
+    end)
61
+  end
62
+
63
+  defp auth(conn) do
64
+    %{
65
+      "signed_in" => Koype.Web.AuthenticationHelpers.is_signed_in?(conn, :owner)
66
+    }
67
+  end
68
+end

+ 3
- 0
lib/template/format.ex View File

@@ -18,6 +18,9 @@
18 18
 # along with this program.  If not, see <https://www.gnu.org/licenses/>.
19 19
 
20 20
 defimpl Koype.Template.Formatter, for: Map do
21
+  @doc """
22
+  Takes a `Map` and presents it a stringified form. Any null values are dropped.
23
+  """
21 24
   def format(map) do
22 25
     map
23 26
     |> Enum.map(fn {k, v} -> {to_string(k), Koype.Template.Formatter.format(v)} end)

+ 6
- 73
lib/template/render.ex View File

@@ -27,19 +27,10 @@ defmodule Koype.Template.Renderer do
27 27
         try do
28 28
           with(
29 29
             %Liquid.Template{} = template <- fetch_template(theme_name, file_path <> ".liquid"),
30
-            {:ok, theme_info} <- Koype.Theme.config_for(theme_name),
31 30
             {:ok, rendered_template, _data} =
32 31
               Liquid.Template.render(
33 32
                 template,
34
-                do_decorate(
35
-                  Map.merge(template_data, %{
36
-                    "theme_id" => theme_name,
37
-                    "koype" => %{
38
-                      "version" => Koype.version(),
39
-                      "theme" => theme_info
40
-                    }
41
-                  })
42
-                )
33
+                Koype.Template.Decorator.decorate(template_data, theme: theme_name)
43 34
               )
44 35
           ) do
45 36
             {:ok, rendered_template}
@@ -72,7 +63,11 @@ defmodule Koype.Template.Renderer do
72 63
       :timer.tc(fn ->
73 64
         ["_header", file_path, "_footer"]
74 65
         |> Enum.map(fn template_name ->
75
-          render_partial(theme_name, template_name <> ".html", do_decorate(template_data))
66
+          render_partial(
67
+            theme_name,
68
+            template_name <> ".html",
69
+            Koype.Template.Decorator.decorate(template_data, theme: theme_name)
70
+          )
76 71
         end)
77 72
         |> Enum.reduce_while({:ok, ""}, fn
78 73
           {:ok, template}, {:ok, acc} ->
@@ -107,66 +102,4 @@ defmodule Koype.Template.Renderer do
107 102
          error: :fetch_template_failed, reason: :file.format_error(err), path: theme_file_path}
108 103
     end
109 104
   end
110
-
111
-  defp do_apply_data(type, data)
112
-
113
-  defp do_apply_data(:auth, data) do
114
-    if Map.has_key?(data, :conn) do
115
-      Map.merge(data, %{
116
-        "signed_in" => Koype.Web.AuthenticationHelpers.is_signed_in?(data.conn, :owner)
117
-      })
118
-    else
119
-      data
120
-    end
121
-  end
122
-
123
-  defp do_apply_data(:hcard, data) do
124
-    if !Map.has_key?(data, "h") do
125
-      card = %{
126
-        "uri" => Koype.host(),
127
-        "preferred_name" => Koype.Profile.displayed_name(),
128
-        "displayed_name" => Koype.Profile.displayed_name(),
129
-        "photo" => Koype.Profile.photo_uri(),
130
-        "note" => Koype.Profile.note(),
131
-        "name" => Koype.Profile.name(),
132
-        "nickname" => Koype.Profile.nickname(),
133
-        "timezone" => Koype.Profile.timezone()
134
-      }
135
-
136
-      Map.merge(data, %{
137
-        "domain" => Koype.host(),
138
-        "host" => Koype.host() |> URI.parse() |> Map.get(:host),
139
-        "form" => %{
140
-          "csrf_token" => Phoenix.Controller.get_csrf_token()
141
-        },
142
-        "h" => %{
143
-          "card" => card,
144
-          "feed" =>
145
-            Enum.map(Koype.Post.known_types(), fn post_type_info ->
146
-              %{
147
-                "title" => Enum.join([post_type_info.names, "-", card["preferred_name"]], " "),
148
-                "href" =>
149
-                  Koype.host() <>
150
-                    Koype.Web.Router.Helpers.timeline_path(Koype.Web.Endpoint, :sequential,
151
-                      type: post_type_info.type
152
-                    )
153
-              }
154
-            end)
155
-        }
156
-      })
157
-    else
158
-      data
159
-    end
160
-  end
161
-
162
-  defp do_decorate(template_data) do
163
-    ~w(auth hcard)a
164
-    |> Enum.reduce(template_data, fn data_class, acc -> do_apply_data(data_class, acc) end)
165
-    |> Map.drop([:conn])
166
-    |> Enum.map(fn
167
-      {k, v} when is_atom(k) -> {Atom.to_string(k), v}
168
-      {k, v} -> {k, v}
169
-    end)
170
-    |> Map.new()
171
-  end
172 105
 end

+ 4
- 3
mix.exs View File

@@ -47,14 +47,15 @@ defmodule Koype.Mixfile do
47 47
         vcr: :test,
48 48
         "vcr.delete": :test,
49 49
         "vcr.check": :test,
50
-        "vcr.show": :test
50
+        "vcr.show": :test,
51
+        doc: :dev
51 52
       ],
52 53
       source_url: "https://git.jacky.wtf/indieweb/koype",
53 54
       source_url_pattern: "https://git.jacky.wtf/indieweb/koype/blob/develop/%{path}#L%{line}",
54 55
       homepage_url: "https://koype.net/",
55 56
       docs: [
56
-        extras: Path.wildcard("docs/*.md"),
57
-        main: "koype",
57
+        extras: Path.wildcard("docs/pages/*.md"),
58
+        main: "Koype",
58 59
         output: "priv/static/doc",
59 60
         groups_for_extras: []
60 61
       ]

+ 3
- 3
priv/themes/default/tmpl/entry/view/response.html.liquid View File

@@ -78,9 +78,9 @@
78 78
     </p>
79 79
   </aside>
80 80
   <aside class="order-3 order-2-l self-start w-auto flex-auto flex-grow ma0-l pt3 pt0-l measure-l">
81
-    {% for facepile in webmention.facepile %}
82
-      {% render name=entry/view/facepile.html %}
83
-    {% endfor %}
81
+    {% render name=entry/view/facepile.html facepile=like %}
82
+    {% render name=entry/view/facepile.html facepile=repost %}
83
+    {% render name=entry/view/facepile.html facepile=bookmark %}
84 84
   </aside>
85 85
   {% render name=entry/view/comments.html %}
86 86
   {% render name=entry/view/adhoc-mentions.html %}

+ 4
- 6
priv/themes/default/tmpl/follow.html.liquid View File

@@ -63,17 +63,15 @@
63 63
       <dl class="lh-copy f4 list cb cf center-s center-m ma0 pa0">
64 64
         {% for format in feed.formats %}
65 65
           <dt>
66
-            <small id="format_{{format}}">
67
-              {{ feed.names|map_get:format }}
68
-            </small>
66
+            <small id="format_{{format.type}}">{{ format.name }}</small>
69 67
           </dt>
70 68
           <dd class="measure">
71 69
             <ul class="lh-copy f5 ma0 pa0">
72
-              {% for type in feed.types %}
70
+              {% for content in feed.types %}
73 71
               <li class="lh-copy">
74 72
                 <a class="color-inherit dim" rel="feed"
75
-                  href="/feeds/{{ format }}/{{ type }}">
76
-                  {{ feed.names|map_get:type }}
73
+                  href="/feeds/{{ format.type }}/{{ content.type }}">
74
+                  {{ content.name }}
77 75
                 </a>
78 76
               </li>
79 77
               {% endfor %}

+ 0
- 1
test/support/factory.ex View File

@@ -1,5 +1,4 @@
1 1
 defmodule Koype.Factory do
2
-  @moduledoc false
3 2
   use ExMachina.Ecto, repo: Koype.Repo
4 3
 
5 4
   alias Koype.Repo.{

+ 0
- 1
test/support/steps/authentication.ex View File

@@ -1,5 +1,4 @@
1 1
 defmodule Koype.Feature.Steps.Shared.Authentication do
2
-  @moduledoc false
3 2
   defmacro __using__(_) do
4 3
     quote do
5 4
       alias Koype.Test.Pages.Authentication

+ 0
- 1
test/support/steps/data.ex View File

@@ -1,5 +1,4 @@
1 1
 defmodule Koype.Feature.Steps.Shared.Data do
2
-  @moduledoc false
3 2
   defmacro __using__(_) do
4 3
     quote do
5 4
       import Koype.Factory

+ 0
- 1
test/support/steps/form.ex View File

@@ -1,5 +1,4 @@
1 1
 defmodule Koype.Feature.Steps.Shared.Form do
2
-  @moduledoc false
3 2
   defmacro __using__(_) do
4 3
     quote do
5 4
       alias Koype.Test.Pages.Form

+ 1
- 0
test/support/steps/html.ex View File

@@ -1,5 +1,6 @@
1 1
 defmodule Koype.Feature.Steps.Shared.HTML do
2 2
   @moduledoc false
3
+
3 4
   defmacro __using__(_) do
4 5
     quote do
5 6
       import Koype.Feature.Steps.Shared

+ 1
- 0
test/support/steps/shared.ex View File

@@ -1,5 +1,6 @@
1 1
 defmodule Koype.Feature.Steps.Shared do
2 2
   @moduledoc false
3
+
3 4
   alias Koype.Test.Page
4 5
   alias Koype.Test.Pages.Navigation
5 6
 

+ 29
- 2
web/controllers/entry_controller.ex View File

@@ -21,6 +21,7 @@ defmodule Koype.Web.EntryController do
21 21
   alias Koype.Repo.Entry
22 22
   require Logger
23 23
 
24
+  @doc false
24 25
   def reparse(conn, %{"id" => id, "action" => "rename"}) do
25 26
     Logger.info("Beginning the renaming of Webmentions for #{id}...")
26 27
 
@@ -42,6 +43,7 @@ defmodule Koype.Web.EntryController do
42 43
     end
43 44
   end
44 45
 
46
+  @doc false
45 47
   def reparse(conn, %{"id" => id, "action" => "webmention"}) do
46 48
     Logger.info("Beginning the resending of Webmentions for #{id}...")
47 49
 
@@ -63,6 +65,7 @@ defmodule Koype.Web.EntryController do
63 65
     end
64 66
   end
65 67
 
68
+  @doc false
66 69
   def reparse(conn, %{"id" => id, "action" => "mp-action"}) do
67 70
     Logger.info("Beginning the re-invoking of Micropub actions for #{id}...")
68 71
 
@@ -84,6 +87,7 @@ defmodule Koype.Web.EntryController do
84 87
     end
85 88
   end
86 89
 
90
+  @doc false
87 91
   def reparse(conn, %{"id" => id, "action" => "reply-context"}) do
88 92
     Logger.info("Beginning the refetching of reply contexts")
89 93
 
@@ -106,6 +110,7 @@ defmodule Koype.Web.EntryController do
106 110
     end
107 111
   end
108 112
 
113
+  @doc false
109 114
   def generate_entry_view_template_data(entry) do
110 115
     case Koype.Template.format(entry) do
111 116
       template_entry when is_map(template_entry) ->
@@ -120,7 +125,6 @@ defmodule Koype.Web.EntryController do
120 125
                   "count" => Koype.Repo.Webmention.count_of(Koype.Repo.Entry.get_uri(entry), type)
121 126
                 }
122 127
               end),
123
-            "facepile" => ~w(like repost bookmark),
124 128
             "of" =>
125 129
               Enum.map(~w(like repost bookmark reply), fn type ->
126 130
                 {type, Koype.Webmention.fetch_for(entry, type)}
@@ -138,7 +142,29 @@ defmodule Koype.Web.EntryController do
138 142
     end
139 143
   end
140 144
 
141
-  # TODO: Do check against format and default to 'html'
145
+  @doc """
146
+  Presents an entry to the viewer.
147
+
148
+  This page renders the template page that shows a entry from `Koype.Template`.
149
+  It adds the following extra fields to the page's template data:
150
+
151
+  | Field | Type | Description |
152
+  | ----- | ---- | ---- |
153
+  | entry | `Koype.Repo.Entry` | Represents the entry in JSON. |
154
+  | webmention.uri | String | A URI to the administrative view of Webmentions for this entry. |
155
+  | webmention.counts| List[ReplyCount] | Provides a list of ReplyCount entries. |
156
+  | webmention.of | Map<Type, List[`Koype.Repo.Webmention`]> | A type to a list of approved received Webmentions that have interacted with this entry. |
157
+
158
+  **ReplyCount** is represented as such:
159
+  ```javascript
160
+  {
161
+    "type": "", // will be one of ["reply", "like", "repost", "bookmark"]
162
+    "count": Number
163
+  }
164
+  ```
165
+
166
+  The map defined by `webmention.of` has the keys `~w(reply like repost bookmark mention)`.
167
+  """
142 168
   def show(conn, %{"id" => id} = params) do
143 169
     format = Map.get(params, "format", "html")
144 170
     Logger.metadata(entry_id: id)
@@ -178,6 +204,7 @@ defmodule Koype.Web.EntryController do
178 204
           end
179 205
 
180 206
           # TODO: Generate JF2 format of page.
207
+          # TODO: Generate AS2 format of page.
181 208
       end
182 209
     else
183 210
       {:ok, %Koype.Repo.Entry{deleted_at: date}} when not is_nil(date) ->

+ 28
- 8
web/controllers/feed_controller.ex View File

@@ -60,31 +60,49 @@ defmodule Koype.Web.FeedController do
60 60
     end
61 61
   end
62 62
 
63
+  @doc """
64
+  Renders a page to assist in allowing remote users to follow this site.
65
+
66
+  This page renders the default page that represents the home page from
67
+  `Koype.Template`. It adds the following extra fields to the page's
68
+  template data:
69
+
70
+  | Field | Type | Description |
71
+  | ---- | ---- | ---- |
72
+  | feed.formats | List[Descriptor] | A list of the available feed formats. |
73
+  | feed.types | List[Descriptor] | A list of the type of feeds. |
74
+
75
+  `Descriptor` is a map that is the following:
76
+  ```json
77
+  {
78
+    "name": "Human friendly name",
79
+    "type": "Machine-specific name."
80
+  }
81
+  ```
82
+  """
63 83
   def index(conn, _) do
64 84
     render_template_page(conn, "follow", %{
65 85
       "feed" => %{
66
-        "formats" => ~w(json atom),
67
-        "types" => ~w(all responses content notifications) ++ Koype.Post.known_post_types(),
68
-        "names" =>
86
+        "formats" => Koype.Feed.formats(),
87
+        "types" =>
69 88
           Map.merge(
70 89
             %{
71 90
               "all" => "Everything",
72 91
               "responses" => "Outgoing Responses",
73 92
               "content" => "Longer Form Content",
74
-              "notifications" => "Notifications",
75
-              "json" => "JSON Feed",
76
-              "atom" => "ATOM 1.0"
93
+              "notifications" => "Notifications"
77 94
             },
78 95
             Koype.Post.known_types()
79
-            |> Enum.map(fn info -> {info[:type], info[:names]} end)
80
-            |> Map.new()
96
+            |> Enum.map(fn info -> %{"type" => info[:type], "name" => info[:names]} end)
81 97
           )
82 98
       }
83 99
     })
84 100
   end
85 101
 
102
+  @doc false
86 103
   def render(conn, assigns)
87 104
 
105
+  @doc false
88 106
   def render(conn, %{"format" => format, "type" => type} = assigns) when format in ~w(atom json) do
89 107
     options = [
90 108
       description: do_get_title(type),
@@ -116,10 +134,12 @@ defmodule Koype.Web.FeedController do
116 134
     end
117 135
   end
118 136
 
137
+  @doc false
119 138
   def render(conn, _) do
120 139
     conn
121 140
     |> Explode.bad_request("Koype doesn't support this feed type.")
122 141
   end
123 142
 
143
+  @doc false
124 144
   def subscribe(conn, _), do: Explode.not_found(conn)
125 145
 end

+ 10
- 0
web/controllers/page_controller.ex View File

@@ -19,6 +19,12 @@
19 19
 defmodule Koype.Web.PageController do
20 20
   use Koype.Web, :controller
21 21
 
22
+  @doc """
23
+  Renders the home page.
24
+
25
+  This page renders the default page that represents the home page from
26
+  `Koype.Template`. It adds _no_ extra fields to the template body.
27
+  """
22 28
   def index(conn, _params) do
23 29
     if !Koype.Setup.complete?() do
24 30
       conn
@@ -29,8 +35,10 @@ defmodule Koype.Web.PageController do
29 35
     end
30 36
   end
31 37
 
38
+  @doc false
32 39
   def mf2(conn, params)
33 40
 
41
+  @doc false
34 42
   def mf2(conn, %{"uri" => uri} = _params) do
35 43
     case IndieWeb.MF2.Remote.refresh(uri) do
36 44
       {:error, error} ->
@@ -43,10 +51,12 @@ defmodule Koype.Web.PageController do
43 51
     end
44 52
   end
45 53
 
54
+  @doc false
46 55
   def mf2(conn, _params) do
47 56
     render(conn, "mf2.html")
48 57
   end
49 58
 
59
+  @doc false
50 60
   def rep_hcard(conn, %{"uri" => uri} = _params) do
51 61
     case IndieWeb.HCard.resolve(uri) do
52 62
       {:error, error} ->

+ 20
- 0
web/controllers/timeline_controller.ex View File

@@ -43,6 +43,26 @@ defmodule Koype.Web.TimelineController do
43 43
     |> Enum.reject(&is_nil/1)
44 44
   end
45 45
 
46
+  @doc """
47
+  Presents a page of items.
48
+
49
+  This page renders the template page that shows a entry from `Koype.Template`.
50
+  It adds the following extra fields to the page's template data:
51
+
52
+  | Field | Type | Description |
53
+  | ----- | ---- | ---- |
54
+  | type | String | The feed type (see [`Koype.Post.known_post_types/0`](`Koype.Post.known_post_types/0`)) |
55
+  | paginator.page_number | Integer | The page number this feed is on. |
56
+  | paginator.page_size | Integer | The size of the page. |
57
+  | paginator.total_pages | Integer | The number of pages available. |
58
+  | paginator.total_entries | Integer | The number of entries available. |
59
+  | paginator.page.next | String | The URL to the next page. |
60
+  | paginator.page.previous | String | The URL to the previous page. |
61
+  | paginator.page.first | String | The URL to the first page. |
62
+  | paginator.page.last | String | The URL to the last page. |
63
+  | paginator.entries | List<[Entry](`Koype.Repo.Entry`)> | A slice of the entries visible on this page. |
64
+
65
+  """
46 66
   def sequential(conn, params) do
47 67
     results =
48 68
       Koype.Timeline.sequential(

+ 11
- 9
web/templates/layout/_meta.html.eex View File

@@ -2,13 +2,15 @@
2 2
 <meta charset="utf-8">
3 3
 <meta name="viewport" content="initial-scale=1.0,user-scalable=yes,width=device-width" />
4 4
 <%= Koype.Web.LayoutView.header_tags(:meta, assigns) %>
5
-<%= Koype.Web.LayoutView.header_tags(:link, assigns) %><%= if Map.get(assigns || %{}, "theme_id", "default") == "default" do %><link rel="icon" href="<%= Koype.Profile.photo_uri %>" />
6
-<link rel="preload" href="<%= asset_path_for(:core, "fonts.css") %>" as="style" />
7
-<link rel="preload" href="<%= asset_path_for(:core, "koype.css") %>" as="style" />
8
-<link rel="preload" href="<%= asset_path_for(:core, "vendor.css") %>" as="style" />
9
-<link rel="stylesheet" href="<%= asset_path_for(:core, "koype.css") %>" />
10
-<link rel="stylesheet" href="<%= asset_path_for(:core, "vendor.css") %>" />
11
-<noscript>
12
-<link rel="stylesheet" href="<%= asset_path_for(:core, "fonts.css") %>" />
13
-</noscript>
5
+<%= Koype.Web.LayoutView.header_tags(:link, assigns) %>
6
+<%= if Koype.Web.LayoutView.current_theme(assigns) == "default" do %>
7
+  <link rel="icon" href="<%= Koype.Profile.photo_uri %>" />
8
+  <link rel="preload" href="<%= asset_path_for(:core, "fonts.css") %>" as="style" />
9
+  <link rel="preload" href="<%= asset_path_for(:core, "koype.css") %>" as="style" />
10
+  <link rel="preload" href="<%= asset_path_for(:core, "vendor.css") %>" as="style" />
11
+  <link rel="stylesheet" href="<%= asset_path_for(:core, "koype.css") %>" />
12
+  <link rel="stylesheet" href="<%= asset_path_for(:core, "vendor.css") %>" />
13
+  <noscript>
14
+  <link rel="stylesheet" href="<%= asset_path_for(:core, "fonts.css") %>" />
15
+  </noscript>
14 16
 <% end %>

+ 8
- 0
web/views/layout_view.ex View File

@@ -106,4 +106,12 @@ defmodule Koype.Web.LayoutView do
106 106
     end)
107 107
     |> Enum.map(&Map.new/1)
108 108
   end
109
+
110
+  def current_theme(assigns)
111
+
112
+  def current_theme(%{"koype" => %{"theme" => theme}}) do
113
+    theme["name"]
114
+  end
115
+
116
+  def current_theme(_), do: "default"
109 117
 end

Loading…
Cancel
Save