upsiflu / less-ui

Write your views across several screen regions, and hide all Ui state in the Url.
https://package.elm-lang.org/packages/upsiflu/less-ui/latest
BSD 3-Clause "New" or "Revised" License
6 stars 1 forks source link

Fuzzy Path (Location) matching #50

Closed upsiflu closed 11 months ago

upsiflu commented 11 months ago

Use case: In the Moving across thresholds app, we are re-routing paths to the closest match in a directory.

Invariants: I. The Url is the single source of truth, so a Less.Application will not re-route to the matching route. II. It must remain possible to create routes implicitly by adding pages with GoTo and Bounce without the need to update the matching algorithm. Every page can be reached. III. Two pages with different paths are never shown in parallel -- unless one is the parent "directory" of the other. IV. Every location is a valid location. I.e. the page shown will never depend on the page shown before.

Questions: Where should the provision of the aforementioned directory or matching algorithm happen? (a) In the selection of a Layout (b) At mapDocument with a parameter matchLocation or sanitizePath or the like (c) In the creation of an Application, with a function mapState (+ Link.mapLocation)

How involved should Less be in the pathfinding?

  1. "sanitize path": Path -> Path or "match fuzzy location": Location -> Location
    • Satisfies I and III
    • Violates II if the matching is broad, otherwise violates IV.
  2. "Match Location" approach: String -> Location -> Bool; replaces the default match function Link.stateContainsLocation
    • Satisfies I and IV
    • Violates III if one Url resolves to True for two routes
    • Violates II if an Url resolves to False for every
  3. "Parse" approach: Use a custom Route type instead of a string in the link definitions
    • The default would be the String as implemented now (e.g. "/#f" for home and fragment f; "/p" for path p; "#f" for just the fragment)
    • Can be replaced by elm-app-url easily, which will make route matching easier for the app creator
  4. "Who's closest" approach: When an Url is requested, all GoTos in the Ui are accumulated and folded for the closest match. Edge cases such as "/parent/child" implicitly matching "/parent" (but not "/") must be covered.
    • Pro: No-config, somewhat predictable and expectable default
    • Con: No way to add a custom dictionary for synonyms such as "violet -> lilac".

Api:

{-| Contextualize a Ui to a browser tab with an Html Dom and an Url. -}
mapDocument :
    { toHtml : html -> List (Html (Msg msg)))
    , howToSanitizePath : String -> String
    }
    -> { body : Ui region html wrapper, layout : Layout region narrowHtml_ html narrowWrapper_ wrapper, title : String }
    -> Document msg
mapDocument tabContext  uiDocument =
    \states ->
        { title = uiDocument.title
        , body =
            Ui.view (Ui.applyStates (Link.sanitizePaths tabContext.howToSanitizePath states) uiDocument.layout) uiDocument.body
                |> tabContext.toHtml
        }
upsiflu commented 11 months ago

The API changes in ce5ecd7 represent a minimal and, I assume, most conventional approach. No invariants were enforced though.

If you want to enforce route invariants, combine this library with something like elm-land, elm-pages, elm-app-url etc. -> Future focus.