purescript / trypurescript

PureScript in the browser
https://try.purescript.org
BSD 3-Clause "New" or "Revised" License
119 stars 50 forks source link

Embed editor state in URL; remove session storage #299

Closed pete-murphy closed 2 years ago

pete-murphy commented 2 years ago

Description of the change

Relates to #118

This removes the session storage in localStorage and persists editor state in the URL using lz-string. https://github.com/purescript/trypurescript/pull/299/commits/2d5c9bd354f8992105c6fe931a0c1109801f04f2 adds a Share URL button (not actually a button, just a clickable <li>) that copies the URL to clipboard, and gives feedback that the URL has successfully been copied to the clipboard.

Example URL For the default editor state of ```haskell module Main where import Prelude import Data.Foldable (fold) import Effect (Effect) import TryPureScript (h1, h2, p, text, list, indent, link, render, code) main :: Effect Unit main = render $ fold [ h1 (text "Try PureScript!") , p (text "Try out the examples below, or create your own!") , h2 (text "Examples") , list (map fromExample examples) , h2 (text "Share Your Code") , p (text "A PureScript file can be loaded from GitHub from a gist or a repository. To share code using a gist, simply include the gist ID in the URL as follows:") , indent (p (code (text " try.purescript.org?gist="))) , p (fold [ text "The gist should contain PureScript module named " , code (text "Main") , text " in a file named " , code (text "Main.purs") , text " containing your PureScript code." ]) , p (text "To share code from a repository, include the path to the source file as follows:") , indent (p (code (text " try.purescript.org?github=////.purs"))) , p (fold [ text "The file should be a PureScript module named " , code (text "Main") , text " containing your PureScript code." ]) ] where fromExample { title, source } = link ("https://github.com/purescript/trypurescript/master/client/examples/" <> source) (text title) examples = [ { title: "Algebraic Data Types" , source: "ADTs.purs" } , { title: "Loops" , source: "Loops.purs" } , { title: "Operators" , source: "Operators.purs" } , { title: "Records" , source: "Records.purs" } , { title: "Recursion" , source: "Recursion.purs" } , { title: "Do Notation" , source: "DoNotation.purs" } , { title: "Type Classes" , source: "TypeClasses.purs" } , { title: "Generic Programming" , source: "Generic.purs" } , { title: "QuickCheck" , source: "QuickCheck.purs" } ] ``` the URL looks like http://localhost:8080/?purs=LYewJgrgNgpgBAWQIYEsB2cDuALGAnGAKEJWAAcQ8AXOABQKgjCJPMpoBEkqkA6AMRBQwSAEaw4ACgBmQsAEpWFanACi06TADGNSes07FpZTQAqeAJ60IBAMpa8KMruwBGADRxsAJk9lPVDAAHlSeUCgAzqFw6Mxo0eFoANaeBGjMeJ5a4DCKhMCoGABcRWoa2jQAqmgoVPmFcAC8hHBwaRlwACRwssItrXAA2l6uUoEhcABE5hZ0NjD2js4AhJOKA3B%2BY8E005ZwIBA0VLhwwUjksBFwojBQIJielHAOMNzwFod4B5hoq%2BsDTw%2BbYTSaqIIXMhXNb9VphSK6ApkHp4EDAcGQiTnS4wCIAuFebwg3a2bBIAhwACaXzgAGEcjCNltJONdgBBOZ2BxOGjSFASLRIDC3OD3JDMMAotFwADitQAEhBRFLgHAkHAAOYIg7fdUECgRWqUCy8OCmEBwCJkinZZhwCCGtAatWahGeQ2XWboLSMO0neBaqJwACSHBiGH9cEqACUADJq669e6YCJFRmA8NxXTIyS2%2BAsnZTVpUSy8MjzCLc5y8SgagD8gaojQAPI2YmAAHxreT4zZwHO9MCwjZDOCsqamU5tq2HYQvEDxBrWLlLGigSASNAXGCSybDpnzu0F0HIdDpkd98eTcMuvmb7e7-cZvPEqantBlmwRc8jgKF6-ZIu6DoM6nw2JyCxVjQea8HuF6tAAur2zJXualrWvAL7SKiqp6jABpGpYnjer68CRmQ3DYGOFqRhEXxaPAd7wEgiZCMmqY-sR6QwPEUg5i%2Bx67MWpblgQlarjWeD1lqJxKo0AD0zYPGg%2BAdop%2BogGpzaiHgQpaFRzw8BqWlMR2n54N%2BPbIf2UiDk%2BrTDKhpxMehs6SiK6rLpBq5wOu0DwFuwA7lM9l9gJV7vj%2BB5XvOQE1E6cBgd8XmLDyh4wLBoVIcOCH9Dg%2BBEK02FohiOJwAA3mOtSwO69HwAAvk0w6JEkUiTNgVBUGQqbyfJMnYEqvDZMA8mibiUHySWFhjeJPLyQUUT4PJPooDxVDydiUK4vJ17Nh2lp1fIr5UNVuTEK0m1XE1GzDJVJ1ULApSTGyUAajAOmoFocBcDwZrTbicG-gdNgMU9bIcKYETmd%2BT71cOnh3adT2xiAIDdYDB50SDMDI6j3XQxjAxwweiMPTjUwAPJkPg3CUDDF61djT1UzTVB0wTsPwxVVVk090baJQYD00DWN4KDUz89keBCxzF7ExmpOPRL2hfigC6EwSovi5MkuqwussjvLBKK%2BTkwcBaAByIA8Cd6tPozYum%2BbVs22rH6icLGxG32JtPaY-10lALERAD9vA47fv-bSQcRCHUMexrcDewjPNK5MMo8fgKBffQIAarpwDACBicO9rGcqY4WgG17XO%2B1MACKEDZ0ktK4FoSQl%2BH2uN83rfaEk1dEzlhBAA

Kapture 2022-08-28 at 02 14 53


Checklist:

JordanMartinez commented 2 years ago

I'll have to try this out locally, but I this looks good to me.

JordanMartinez commented 2 years ago

I've checked this out locally and played with it for a bit. The code works, but there are a few UX things to figure out now. I think these can be solved in a separate PR.

First, if I load a gist, the URL will include the gist in the query param in addition to the purs query param for the lz-compresed code. I think that's useful because it can show you what the original gist was. However, if I modify the code after loading the gist, the URL doesn't drop the gist part. Thus, I can still click on "View > Gist" to open up the original gist. However, there's nothing indicating that the gist I'll be seeing is different from the code being run in the browser due to my previous modification. There should likely be a warning that the gist has been modified since it's original load. This should also apply to the GitHub variant as well.

Second, now that we can share URLs, some may expect the URL to automatically update to whatever options the user chooses. For example, if the user chooses "View > Output", we'll see only the output, but the URL doesn't update to reflect that. If User A sends the URL to User B with the intent of discussing just the output, User B will see the side-by-side view, not the output view. This will likely be a bit confusing to both.

What are your thoughts?

JordanMartinez commented 2 years ago

Oh, one other thing. The readme needs to be updated to drop the part about session storage.

pete-murphy commented 2 years ago

First, if I load a gist, the URL will include the gist in the query param in addition to the purs query param for the lz-compresed code. I think that's useful because it can show you what the original gist was. However, if I modify the code after loading the gist, the URL doesn't drop the gist part. Thus, I can still click on "View > Gist" to open up the original gist. However, there's nothing indicating that the gist I'll be seeing is different from the code being run in the browser due to my previous modification. There should likely be a warning that the gist has been modified since it's original load. This should also apply to the GitHub variant as well.

Hmm, yeah I could see wanting to have a warning about the link to Gist / GitHub being out of sync with the current editor state, but I don't have a clear idea of what that should look like. I also think it's a bit odd to have the link under View Mode in the first place; the other options in that menu actually switch between different view modes within TPS, so the Gist / GitHub link already feels a bit unintuitive lumped in there. I guess we could emphasize that it's a link to the original code with some extra copy (the title already says "Open the original gist ..." on hover), but I don't know that that's actually helping to clarify anything 😄 .

image

Second, now that we can share URLs, some may expect the URL to automatically update to whatever options the user chooses. For example, if the user chooses "View > Output", we'll see only the output, but the URL doesn't update to reflect that. If User A sends the URL to User B with the intent of discussing just the output, User B will see the side-by-side view, not the output view. This will likely be a bit confusing to both.

Agreed 👍 I think the View Mode state could be tracked in the URL too, so that opening a shared URL ends up on the same exact view.

Oh, one other thing. The readme needs to be updated to drop the part about session storage.

Good catch, can do 👍

JordanMartinez commented 2 years ago

What was the reasoning behind using purs as the query parameter rather than something else (e.g. content, code, etc.)? I'm wondering if we should use a different name for that parameter so that purs can be used for something else in the future (e.g. if multiple purs versions were supported simultaneously) without breaking links made in the past.

pete-murphy commented 2 years ago

What was the reasoning behind using purs as the query parameter rather than something else (e.g. content, code, etc.)? I'm wondering if we should use a different name for that parameter so that purs can be used for something else in the future (e.g. if multiple purs versions were supported simultaneously) without breaking links made in the past.

It was an arbitrary choice, I'd be open to change it to whatever. Rust Playground uses code=<uncompressed string>, TypeScript Playground uses #code/<compressed string>, Try Reason uses reason=<compressed string>. code seems like a reasonable choice.

JordanMartinez commented 2 years ago

Yeah, using code sounds good.

pete-murphy commented 2 years ago

Second, now that we can share URLs, some may expect the URL to automatically update to whatever options the user chooses. For example, if the user chooses "View > Output", we'll see only the output, but the URL doesn't update to reflect that. If User A sends the URL to User B with the intent of discussing just the output, User B will see the side-by-side view, not the output view. This will likely be a bit confusing to both.

I have a separate commit for syncing the URL with the local state for Settings, but I don't know if this is the approach we want to use: https://github.com/ptrfrncsmrph/trypurescript/pull/2/commits/d5f291466f030509dc08acd8fc652a11e192ce35. I can include it in this PR if we want.

JordanMartinez commented 2 years ago

:ping_pong: @garyb Can I get an approval on this?

JordanMartinez commented 2 years ago

I've just redeployed TPS with this change. Thanks @ptrfrncsmrph!