#31 Implement unix-style tag display

Zusammengeführt
getty hat 3 Commits von getty/gr/unix-style-tags nach getty/master vor 4 Jahren zusammengeführt
6 geänderte Dateien mit 76 neuen und 10 gelöschten Zeilen
  1. 6 4
      lc/app.py
  2. 1 0
      lc/model.py
  3. 52 0
      lc/view.py
  4. 13 0
      static/main.css
  5. 1 3
      templates/link.mustache
  6. 3 3
      templates/linklist.mustache

+ 6 - 4
lc/app.py

@@ -19,7 +19,7 @@ class Index(Endpoint):
 
         pg = int(flask.request.args.get("page", 1))
         links, pages = m.Link.get_all(as_user=self.user, page=pg)
-        linklist = v.LinkList(links=links, pages=pages, tags=[])
+        linklist = v.LinkList(links=links, pages=pages, user="", tags=[])
 
         return render(
             "main",
@@ -89,7 +89,7 @@ class GetUser(Endpoint):
         pg = int(flask.request.args.get("page", 1))
         tags = u.get_tags()
         links, pages = u.get_links(as_user=self.user, page=pg)
-        linklist = v.LinkList(links=links, pages=pages, tags=tags)
+        linklist = v.LinkList(links=links, user=slug, pages=pages, tags=tags)
         return render(
             "main",
             v.Page(
@@ -190,7 +190,9 @@ class GetLink(Endpoint):
             "main",
             v.Page(
                 title=f"link {l.name}",
-                content=render("linklist", v.LinkList([l.to_view(self.user)], [])),
+                content=render(
+                    "linklist", v.LinkList([l.to_view(self.user)], [], user=user)
+                ),
                 user=self.user,
             ),
         )
@@ -219,7 +221,7 @@ class GetTaggedLinks(Endpoint):
         t = u.get_tag(tag)
         links, pages = t.get_links(as_user=self.user, page=pg)
         tags = u.get_related_tags(t)
-        linklist = v.LinkList(links=links, pages=pages, tags=tags)
+        linklist = v.LinkList(links=links, pages=pages, tags=tags, user=user)
         return render(
             "main",
             v.Page(

+ 1 - 0
lc/model.py

@@ -263,6 +263,7 @@ class Link(Model):
             created=self.created,
             is_mine=self.user.id == as_user.id if as_user else False,
             link_url=self.link_url(),
+            user=self.user.name,
         )
 
     def get_tags_view(self) -> List[v.Tag]:

+ 52 - 0
lc/view.py

@@ -77,6 +77,50 @@ class Tag(View):
     name: str
 
 
+@dataclass
+class HierTagList:
+    user: str
+    tags: List[Tag]
+
+    def render(self) -> str:
+        groups: dict = {}
+
+        for tag in (t.name for t in self.tags):
+            if "/" not in tag:
+                groups[tag] = groups.get(tag, {})
+            else:
+                chunks = tag.split("/")
+                focus = groups[chunks[0]] = groups.get(chunks[0], {})
+                for c in chunks[1:]:
+                    focus[c] = focus = focus.get(c, {})
+
+        return "\n".join(self.render_html(k, v) for k, v in groups.items())
+
+    def render_html(self, prefix: str, values: dict) -> str:
+        link = self._render_html(prefix, values, [])
+        return f'<span class="tag">{link}</span>'
+
+    def _href(self, tag: str, init: List[str]) -> str:
+        link = "/".join(init + [tag])
+        return f'<a href="/u/{self.user}/t/{link}">{tag}</a>'
+
+    def _render_html(self, prefix: str, values: dict, init: List[str]) -> str:
+        if not values:
+            return self._href(prefix, init)
+        if len(values) == 1:
+            k, v = values.popitem()
+            rest = self._render_html(k, v, init + [prefix])
+            prefix_href = self._href(prefix, init)
+            return f"{prefix_href}/{rest}"
+        else:
+            fragments = []
+            for k, v in values.items():
+                fragments.append(self._render_html(k, v, init + [prefix]))
+            items = ", ".join(fragments)
+            prefix_href = self._href(prefix, init)
+            return f"{prefix_href}/{{{items}}}"
+
+
 @dataclass
 class Link(View):
     id: int
@@ -88,14 +132,22 @@ class Link(View):
     created: datetime
     is_mine: bool
     link_url: str
+    user: str
+
+    def hier_tags(self) -> str:
+        return HierTagList(user=self.user, tags=self.tags).render()
 
 
 @dataclass
 class LinkList(View):
     links: List[Any]
     tags: List[Tag]
+    user: str
     pages: Optional[Pagination] = None
 
+    def hier_tags(self) -> str:
+        return HierTagList(user=self.user, tags=self.tags).render()
+
 
 @dataclass
 class SingleLink(View):

+ 13 - 0
static/main.css

@@ -54,6 +54,7 @@ a {
 
 .taglist { display: flex; }
 .tag {
+    color: #555;
     padding-right: 0.4em;
 }
 
@@ -208,3 +209,15 @@ form > div {
     padding: 2em;
     word-spacing: 1em;
 }
+
+.tag_container {
+    display: flex;
+    flex-wrap: wrap;
+}
+
+.tag_container span {
+    display: block;
+    text-indent: -1em;
+    margin-left: 1em;
+    padding-left: 0.3em;
+}

+ 1 - 3
templates/link.mustache

@@ -1,9 +1,7 @@
 <div id="link_{{id}}" class="link{{#private}} private{{/private}}">
   <div class="text"><a href="{{url}}">{{name}}</a></div>
   <div class="url"><a href="{{url}}">{{url}}</a></div>
-  <div class="taglist">{{#tags}}
-    <span class="tag"><a href="{{url}}">{{name}}</a></span>
-  {{/tags}}</div>
+  <div class="taglist">{{{ hier_tags }}}</div>
   <div class="datetime">
     <a href="{{link_url}}">{{created}}</a>
     {{#is_mine}}

+ 3 - 3
templates/linklist.mustache

@@ -5,9 +5,9 @@
     {{/links}}
   </div>
   <div class="tags">
-    {{#tags}}
-      <a href="{{url}}">{{name}}</a>
-    {{/tags}}
+    <div class="tag_container">
+      {{{hier_tags}}}
+    </div>
   </div>
 </div>
 {{#pages}}