Web links: choose the service, with its icon, and check the address against it #305

Closed
opened 2026-09-29 11:26:38 +00:00 by tiagoagueda · 1 comment
Owner

From the interface review of 2026-09-29, for Social profiles, and the same for Code repositories and Websites:

  • The kind comes first, on one line with the address on a wide screen.
  • The kind is chosen in Basecoat's select, each option with its icon (#301).
  • The address is validated against the kind before it is stored.
  • Primary and Remove become icons, and removing asks for confirmation in a dialog (#303).

What is there today

  • There is one block per kind (#189). Each block is a kind, so a row has no kind field: a row is an address, then a free-text Name ("LinkedIn, Codeberg, a blog — what to call it. Left blank, the host is shown.").
  • That was a decision. core/models.py::WebLink says: "The kind is the sort of thing, never the host … a list of brand names ages every time somebody's Forgejo instance or the next network appears." An address is checked for being a web address and for nothing more.
  • #213 already asks for the name before the address. It moves to this milestone with this review.

So what is asked for is, in effect, a service. Under Social profiles that means a choice of LinkedIn, Mastodon, Bluesky, X and the others; under Code repositories, GitHub, GitLab, Codeberg, a Forgejo or Gitea instance, and so on. Each comes with its icon, and the check on the address depends on which one was chosen.

Decisions to take

  1. A list of services, and who keeps it. The identifier schemes are the precedent: a registry supplied by plugins (plugins/identifiers), where each scheme says what a value looks like and where it links (#298). The same shape would work here: a service with a name, an icon, the hosts it answers on and a pattern for its addresses. That keeps the list out of the model, and lets an instance add its own services.
  2. There is always an Other. A Forgejo instance, a personal site, a network nobody has listed: Other takes a free name and gets only the web-address check, so nobody is refused an address because the list does not know it.
  3. Federated services have no fixed host. A Mastodon or a Forgejo address is checked by its shape (https://host/@name, https://host/owner), not by its host.
  4. Rows already stored get their service guessed from the host where it matches a known one, and stay Other where it does not. Nothing is refused retroactively.
  5. Icons for brands, as settled in #301.

Done when

  • The service select sits first in each row, on one line with the address from the sm breakpoint up, and the order in the DOM is the reading order.
  • Every shipped service has its validation, with tests, and so does Other.
  • The export and the API carry the service beside the address.
From the interface review of 2026-09-29, for *Social profiles*, and the same for *Code repositories* and *Websites*: - The kind comes first, on one line with the address on a wide screen. - The kind is chosen in Basecoat's select, each option with its icon (#301). - The address is validated against the kind before it is stored. - *Primary* and *Remove* become icons, and removing asks for confirmation in a dialog (#303). ## What is there today - There is one block per kind (#189). Each block *is* a kind, so a row has no kind field: a row is an address, then a free-text *Name* ("LinkedIn, Codeberg, a blog — what to call it. Left blank, the host is shown."). - **That was a decision.** `core/models.py::WebLink` says: "The kind is the sort of thing, never the host … a list of brand names ages every time somebody's Forgejo instance or the next network appears." An address is checked for being a web address and for nothing more. - #213 already asks for the name before the address. It moves to this milestone with this review. So what is asked for is, in effect, **a service**. Under *Social profiles* that means a choice of LinkedIn, Mastodon, Bluesky, X and the others; under *Code repositories*, GitHub, GitLab, Codeberg, a Forgejo or Gitea instance, and so on. Each comes with its icon, and the check on the address depends on which one was chosen. ## Decisions to take 1. **A list of services, and who keeps it.** The identifier schemes are the precedent: a registry supplied by plugins (`plugins/identifiers`), where each scheme says what a value looks like and where it links (#298). The same shape would work here: a service with a name, an icon, the hosts it answers on and a pattern for its addresses. That keeps the list out of the model, and lets an instance add its own services. 2. **There is always an *Other*.** A Forgejo instance, a personal site, a network nobody has listed: *Other* takes a free name and gets only the web-address check, so nobody is refused an address because the list does not know it. 3. **Federated services have no fixed host.** A Mastodon or a Forgejo address is checked by its shape (`https://host/@name`, `https://host/owner`), not by its host. 4. **Rows already stored** get their service guessed from the host where it matches a known one, and stay *Other* where it does not. Nothing is refused retroactively. 5. **Icons for brands**, as settled in #301. ## Done when - The service select sits first in each row, on one line with the address from the `sm` breakpoint up, and the order in the DOM is the reading order. - Every shipped service has its validation, with tests, and so does *Other*. - The export and the API carry the service beside the address.
tiagoagueda added this to the 0.5.0 milestone 2026-09-29 11:26:38 +00:00
Author
Owner

Three issues from the maintainer's list of 2026-10-02 build on what this issue landed, so they are recorded here.

The service registry is core/link_services.py (Service at :100, registry() at :245), supplied by plugins of the link-service kind (:266) and exposed as LinkService on postulo.plugins.api. #678 (type only the username, with a fixed address prefix) adds a prefix to a service. #654 (brand icons from Simple Icons) lets a service name a mark beside its Lucide icon. #682 (instant-messaging contacts) takes this registry as its model but keeps a registry of its own, since a handle is not a web address.

From the list of improvements of 2026-10-02.

Three issues from the maintainer's list of 2026-10-02 build on what this issue landed, so they are recorded here. The service registry is `core/link_services.py` (`Service` at `:100`, `registry()` at `:245`), supplied by plugins of the `link-service` kind (`:266`) and exposed as `LinkService` on `postulo.plugins.api`. #678 (type only the username, with a fixed address prefix) adds a prefix to a service. #654 (brand icons from Simple Icons) lets a service name a mark beside its Lucide icon. #682 (instant-messaging contacts) takes this registry as its model but keeps a registry of its own, since a handle is not a web address. From the list of improvements of 2026-10-02.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo#305
No description provided.