From 9014d66299bee2f31bc666479f2c5d65c671e021 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20H=C3=B8jberg?= Date: Thu, 25 Jul 2024 17:20:45 -0400 Subject: [PATCH] improve syntax hovers and doc underlines --- src/Code/Definition/Doc.elm | 10 +- src/Code/Syntax/SyntaxSegment.elm | 110 ++-- src/css/code/definition-doc.css | 2 +- src/css/code/syntax.css | 17 +- storybook/static/cloud_config_def.json | 599 +++++++++++++++++++ storybook/stories/Stories/Code/Workspace.elm | 3 +- 6 files changed, 689 insertions(+), 52 deletions(-) create mode 100644 storybook/static/cloud_config_def.json diff --git a/src/Code/Definition/Doc.elm b/src/Code/Definition/Doc.elm index 8726b079..5f544c14 100644 --- a/src/Code/Definition/Doc.elm +++ b/src/Code/Definition/Doc.elm @@ -465,10 +465,12 @@ view linkedCfg toggleFoldMsg docFoldToggles document = hr [ class "divider" ] [] Tooltip triggerContent tooltipContent -> - Tooltip.tooltip - (Tooltip.rich (viewAtCurrentSectionLevel tooltipContent)) - |> Tooltip.withArrow Tooltip.Start - |> Tooltip.view (viewAtCurrentSectionLevel triggerContent) + span [ class "doc-tooltip" ] + [ Tooltip.tooltip + (Tooltip.rich (viewAtCurrentSectionLevel tooltipContent)) + |> Tooltip.withArrow Tooltip.Start + |> Tooltip.view (viewAtCurrentSectionLevel triggerContent) + ] Aside d -> span [ class "doc_aside-anchor" ] diff --git a/src/Code/Syntax/SyntaxSegment.elm b/src/Code/Syntax/SyntaxSegment.elm index af07718f..4a57bfcd 100644 --- a/src/Code/Syntax/SyntaxSegment.elm +++ b/src/Code/Syntax/SyntaxSegment.elm @@ -259,62 +259,86 @@ view linked ((SyntaxSegment sType sText) as segment) = className = syntaxTypeToClassName sType - content = + content view_ = if String.contains "->" sText then - span [ class "arrow" ] [ text sText ] + view_ (span [ class "arrow" ] [ text sText ]) else if isFQN then - viewFQN (FQN.fromString sText) + view_ (viewFQN (FQN.fromString sText)) + + else if sText /= " " && (String.startsWith " " sText || String.endsWith " " sText) then + -- If the text is not the empty string and is either prefixed + -- or suffixed with a space, we want that to not be part of a + -- hover background, so it gets separate to another dom node. + -- This results in cleaner looking hovers and tooltip + -- positionings + if String.startsWith " " sText && String.endsWith " " sText then + span [] [ text " ", view_ (text (String.trim sText)), text " " ] + + else if String.startsWith " " sText then + span [] [ text " ", view_ (text (String.trim sText)) ] + + else + span [] [ view_ (text (String.trim sText)), text " " ] else - text sText + view_ (text sText) in case ( linked, ref ) of ( Linked click, Just r ) -> - Click.view - [ class className ] - [ content ] - (click r) + content + (\c -> + Click.view + [ class className ] + [ c ] + (click r) + ) ( LinkedWithTooltip l, Just r ) -> - let - content_ = - case l.tooltip.toTooltip r of - Just t -> - Tooltip.view content t - - Nothing -> - content - in - Click.view - [ class className - , onMouseEnter (l.tooltip.toHoverStart r) - , onMouseLeave (l.tooltip.toHoverEnd r) - ] - [ content_ ] - (l.toClick r) - - _ -> - case helpForSegment segment of - Just help -> + content + (\c -> let - tooltip = - Tooltip.rich help - |> Tooltip.tooltip - |> Tooltip.withArrow Tooltip.Start - |> Tooltip.withPosition Tooltip.Below + content_ = + case l.tooltip.toTooltip r of + Just t -> + Tooltip.view c t + + Nothing -> + c in - Tooltip.view - (span - [ class "syntax-help", class className ] - [ content ] - ) - tooltip + Click.view + [ class className + , onMouseEnter (l.tooltip.toHoverStart r) + , onMouseLeave (l.tooltip.toHoverEnd r) + ] + [ content_ ] + (l.toClick r) + ) - _ -> - span - [ class className ] - [ content ] + _ -> + content + (\c -> + case helpForSegment segment of + Just help -> + let + tooltip = + Tooltip.rich help + |> Tooltip.tooltip + |> Tooltip.withArrow Tooltip.Start + |> Tooltip.withPosition Tooltip.Below + in + Tooltip.view + (span + [ class "syntax-help", class className ] + [ c ] + ) + tooltip + + _ -> + span + [ class className ] + [ c ] + ) helpForSegment : SyntaxSegment -> Maybe (Html msg) diff --git a/src/css/code/definition-doc.css b/src/css/code/definition-doc.css index e168a10d..a52be5bf 100644 --- a/src/css/code/definition-doc.css +++ b/src/css/code/definition-doc.css @@ -240,7 +240,7 @@ margin: 1.5rem 0; } -.definition-doc :not(code) .tooltip-trigger { +.definition-doc .doc-tooltip .tooltip-trigger { text-decoration: underline dotted var(--color-doc-subtle-text); text-underline-offset: 2px; /* Other tooltip styling is handled by elements/tooltip */ diff --git a/src/css/code/syntax.css b/src/css/code/syntax.css index 39968141..5d0cbbac 100644 --- a/src/css/code/syntax.css +++ b/src/css/code/syntax.css @@ -18,8 +18,8 @@ code { code a { display: inline-block; - padding: 0 0.25rem; - margin: 0 -0.25rem; + padding: 0 0.125rem; + margin: 0 -0.125rem; border-radius: var(--border-radius-base); line-height: 1.4; } @@ -37,8 +37,19 @@ code a:active .tooltip-trigger.tooltip_show .tooltip { display: none; } +.syntax-help:hover { + color: var(--color-orange-1) !important; + cursor: help; + display: inline-block; + padding: 0 0.125rem; + margin: 0 -0.125rem; + border-radius: var(--border-radius-base); + line-height: 1.4; + background: var(--color-orange-5); +} + .tooltip-trigger:has(> .syntax-help) .tooltip { - margin-left: -0.5rem; + margin-left: -1rem; } .tooltip-trigger:has(> .syntax-help) .tooltip code { diff --git a/storybook/static/cloud_config_def.json b/storybook/static/cloud_config_def.json new file mode 100644 index 00000000..e9a87870 --- /dev/null +++ b/storybook/static/cloud_config_def.json @@ -0,0 +1,599 @@ +{ + "missingDefinitions": [], + "termDefinitions": {}, + "typeDefinitions": { + "#3j6045jl1ngsop8a3m7va0pib6lp67bq503b76rkb62f4ku38eiud1i7pi47aet1kiahgim16bu8dkcufv8s1de7rcoa761steht9p0": { + "bestTypeName": "Config", + "defnTypeTag": "Ability", + "typeDefinition": { + "contents": [ + { + "annotation": { + "tag": "DataTypeKeyword" + }, + "segment": "ability" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "Config", + "tag": "HashQualifier" + }, + "segment": "Config" + }, + { + "annotation": { + "tag": "ControlKeyword" + }, + "segment": " where" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#3j6045jl1ngsop8a3m7va0pib6lp67bq503b76rkb62f4ku38eiud1i7pi47aet1kiahgim16bu8dkcufv8s1de7rcoa761steht9p0#a0", + "tag": "TermReference" + }, + "segment": "lookup" + }, + { + "annotation": { + "tag": "TypeAscriptionColon" + }, + "segment": " :" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "##Text", + "tag": "TypeReference" + }, + "segment": "Text" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "TypeOperator" + }, + "segment": "->" + }, + { + "annotation": { + "tag": "AbilityBraces" + }, + "segment": "{" + }, + { + "annotation": { + "contents": "#3j6045jl1ngsop8a3m7va0pib6lp67bq503b76rkb62f4ku38eiud1i7pi47aet1kiahgim16bu8dkcufv8s1de7rcoa761steht9p0", + "tag": "TypeReference" + }, + "segment": "Config" + }, + { + "annotation": { + "tag": "AbilityBraces" + }, + "segment": "}" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#nirp5os0q69o4e1u9p3t6mmq6l6otluefi3ksm7dhm0diidjvkkgl8o9bvnflbj0sanuvdusf34f1qrins3ktcaglpcqv9oums2slsg", + "tag": "TypeReference" + }, + "segment": "Optional" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "##Text", + "tag": "TypeReference" + }, + "segment": "Text" + } + ], + "tag": "UserObject" + }, + "typeDocs": [ + [ + "Config.doc", + "#6dm3jle5g06psdrmgide8dtq3ai31s8bbvpalq3hcihciedl85imj2po3rar7ba6jhlsirthaaifo2ji4lilbu0mfihmtjs3l66ufj8", + { + "contents": [ + { + "contents": [ + { + "contents": "A", + "tag": "Word" + }, + { + "contents": "simple", + "tag": "Word" + }, + { + "contents": "ability", + "tag": "Word" + }, + { + "contents": "for", + "tag": "Word" + }, + { + "contents": "accessing", + "tag": "Word" + }, + { + "contents": "dynamic", + "tag": "Word" + }, + { + "contents": "configuration", + "tag": "Word" + }, + { + "contents": "of", + "tag": "Word" + }, + { + "contents": "a", + "tag": "Word" + }, + { + "contents": "service", + "tag": "Word" + }, + { + "contents": "or", + "tag": "Word" + }, + { + "contents": "batch", + "tag": "Word" + }, + { + "contents": "job.", + "tag": "Word" + }, + { + "contents": "Config", + "tag": "Word" + }, + { + "contents": "values", + "tag": "Word" + }, + { + "contents": "are", + "tag": "Word" + }, + { + "contents": "set", + "tag": "Word" + }, + { + "contents": "using", + "tag": "Word" + }, + { + "contents": { + "contents": [ + { + "annotation": { + "contents": "#560fdeg8gav3ivknchekjfq0hvvkk6mpvoef6oids40s8f44n5l6q4shhe1n4dhpkg4c43tejpqs4lo52nf6t8ijo9kahksr3bu2tq0", + "tag": "TermReference" + }, + "segment": "setValue" + } + ], + "tag": "Link" + }, + "tag": "Special" + }, + { + "contents": "and", + "tag": "Word" + }, + { + "contents": "unset", + "tag": "Word" + }, + { + "contents": "using", + "tag": "Word" + }, + { + "contents": { + "contents": [ + { + "contents": { + "contents": [ + { + "annotation": { + "contents": "#ga99u34gdupednjk592ibu5qcte4lnm9qqpla99icna7b3qar74jilp48dlt0ijjfbe4ja3vf5q3a6pvv0b5ed2tsobim3pq5t8sc5o", + "tag": "TermReference" + }, + "segment": "deleteValue" + } + ], + "tag": "Link" + }, + "tag": "Special" + }, + { + "contents": ".", + "tag": "Word" + } + ], + "tag": "Join" + }, + "tag": "Group" + } + ], + "tag": "Paragraph" + }, + { + "contents": { + "contents": [ + { + "annotation": { + "contents": "env", + "tag": "HashQualifier" + }, + "segment": "env" + }, + { + "annotation": { + "tag": "BindingEquals" + }, + "segment": " =" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#757qudsft61ajvie9iulg36i94225i7n7qel0tm5qjtes5vtujl38kb4lrakirohm5h1fi1fburnmga3bh21prp191ek5kvtrt0ipgg", + "tag": "TermReference" + }, + "segment": "Environment.create" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "TextLiteral" + }, + "segment": "\"my-env\"" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": { + "contents": "#560fdeg8gav3ivknchekjfq0hvvkk6mpvoef6oids40s8f44n5l6q4shhe1n4dhpkg4c43tejpqs4lo52nf6t8ijo9kahksr3bu2tq0", + "tag": "TermReference" + }, + "segment": "setValue" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "env" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "TextLiteral" + }, + "segment": "\"api-key\"" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Parenthesis" + }, + "segment": "(" + }, + { + "annotation": { + "contents": "#lln30o1n6in87rdja6e9hmc8hd23egkueblnq033mslem41tmv8a5gdrauqi836ab5qc40od0i6n4buba9ia77thj16glib0elmedg0", + "tag": "TermReference" + }, + "segment": "getEnv" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "TextLiteral" + }, + "segment": "\"SECRET_API_KEY\"" + }, + { + "annotation": { + "tag": "Parenthesis" + }, + "segment": ")" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": { + "contents": "#jkuqt8djouerug9c6o08ukss9vk2cqnds2q76plsjorotdqc7fuiu0anepk0g1j2on29nvu58pq8j7s2e5np3bn330v9li9pd7vip6g", + "tag": "TermReference" + }, + "segment": "Cloud.submit" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "Var" + }, + "segment": "env" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "ControlKeyword" + }, + "segment": "do" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "key", + "tag": "HashQualifier" + }, + "segment": "key" + }, + { + "annotation": { + "tag": "BindingEquals" + }, + "segment": " =" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#3j6045jl1ngsop8a3m7va0pib6lp67bq503b76rkb62f4ku38eiud1i7pi47aet1kiahgim16bu8dkcufv8s1de7rcoa761steht9p0#a0", + "tag": "TermReference" + }, + "segment": "Config.lookup" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "TextLiteral" + }, + "segment": "\"api-key\"" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#ur2tossvhrmfo8h1o5ertf0dqn5mrprfsfca3fsal7ljm36am48k0un4bhsqr387s3v5s7vad74spmluikdo5pj0kt30dk76pmev5ko", + "tag": "TermReference" + }, + "segment": "|>" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "#74doikmgakdqto28tickaavqapviejn2uhtvgd2nncmd0gk2ait4avnj7uicjcvo968h1eo4bvfihq8l1gj7ehl2ilbjte367rveabg", + "tag": "TermReference" + }, + "segment": "getOrBug" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "TextLiteral" + }, + "segment": "\"expected api-key in config\"" + }, + { + "annotation": null, + "segment": "\n" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "contents": "##todo", + "tag": "TermReference" + }, + "segment": "todo" + }, + { + "annotation": null, + "segment": " " + }, + { + "annotation": { + "tag": "TextLiteral" + }, + "segment": "\"do service logic using api-key\"" + } + ], + "tag": "ExampleBlock" + }, + "tag": "Special" + }, + { + "contents": [ + { + "contents": "Config", + "tag": "Word" + }, + { + "contents": "values", + "tag": "Word" + }, + { + "contents": "are", + "tag": "Word" + }, + { + "contents": "stored", + "tag": "Word" + }, + { + "contents": "encrypted", + "tag": "Word" + }, + { + "contents": "on", + "tag": "Word" + }, + { + "contents": "Unison", + "tag": "Word" + }, + { + "contents": "Cloud", + "tag": "Word" + }, + { + "contents": "and", + "tag": "Word" + }, + { + "contents": "only", + "tag": "Word" + }, + { + "contents": "exist", + "tag": "Word" + }, + { + "contents": "unencrypted", + "tag": "Word" + }, + { + "contents": "in", + "tag": "Word" + }, + { + "contents": "memory", + "tag": "Word" + }, + { + "contents": "while", + "tag": "Word" + }, + { + "contents": "the", + "tag": "Word" + }, + { + "contents": "service", + "tag": "Word" + }, + { + "contents": "or", + "tag": "Word" + }, + { + "contents": "batch", + "tag": "Word" + }, + { + "contents": "job", + "tag": "Word" + }, + { + "contents": "is", + "tag": "Word" + }, + { + "contents": "running.", + "tag": "Word" + } + ], + "tag": "Paragraph" + } + ], + "tag": "UntitledSection" + } + ] + ], + "typeNames": [ + "Config" + ] + } + } +} diff --git a/storybook/stories/Stories/Code/Workspace.elm b/storybook/stories/Stories/Code/Workspace.elm index c2f1c409..298d28e9 100644 --- a/storybook/stories/Stories/Code/Workspace.elm +++ b/storybook/stories/Stories/Code/Workspace.elm @@ -45,6 +45,7 @@ init _ = , getSampleResponse 1 "/nat_gt_term_def.json" "nat_gt" , getSampleResponse 2 "/base_readme.json" "base_readme" , getSampleResponse 3 "/long.json" "assets.indexHtml" + , getSampleResponse 4 "/cloud_config_def.json" "Config" ] ) @@ -107,7 +108,7 @@ update message model = GotItem _ reference result -> case result of Err error -> - ( model, Cmd.none ) + ( model, Cmd.none ) Ok item -> let