Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Review hint mode style #3318

Merged
merged 9 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions source/changelog.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -850,9 +850,9 @@ a scalable icon."))))
(:nsection :title "Features"
(:ul
(:li "Add new slots "
(:nxref :class-name 'nyxt/mode/hint:hint-mode :slot 'nyxt/mode/hint:hints-offset-x)
(:code "nyxt/mode/hint:hints-offset-x")
" and "
(:nxref :class-name 'nyxt/mode/hint:hint-mode :slot 'nyxt/mode/hint:hints-offset-y)
(:code "nyxt/mode/hint:hints-offset-y")
", to change the position of hint overlays.")))
(:nsection :title "Bug fixes"
(:ul
Expand Down Expand Up @@ -995,6 +995,12 @@ allows access to common functions that are defined within the mode."))))

(define-version "4.0.0"
(:ul
(:li "Add slot "
(:nxref :slot 'nyxt/mode/hint:x-placement :class-name 'nyxt/mode/hint:hint-mode)
" to draw hints on the right of the hinted element. By default, they
are drawn on the left.")
(:li "The size of the hints is dynamically set by taking into account the
size of the hinted element.")
(:li "Fix bug that made Nyxt display an out of date version in several places.")
(:li "Add " (:nxref :class-name 'message-buffer) " as a user class, thus
enabling its customization.")
Expand Down
8 changes: 8 additions & 0 deletions source/migration.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,14 @@ major versions."
result)))))

(define-migration "4"
(hints-offset-x)
(:p "Deprecated in favor of "
(:nxref :slot 'nyxt/mode/hint:x-translation :class-name 'nyxt/mode/hint:hint-mode) ".")

(hints-offset-y)
(:p "Deprecated in favor of "
(:nxref :slot 'nyxt/mode/hint:y-translation :class-name 'nyxt/mode/hint:hint-mode) ".")

(message-buffer-height)
(:p "Deprecated in favor of " (:nxref :slot 'height :class-name 'message-buffer) ".")

Expand Down
136 changes: 75 additions & 61 deletions source/mode/hint.lisp
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,6 @@ In :emacs, hints are computed for the whole page, and the usual `prompt-buffer'
facilities are available.
In :vi, the `prompt-buffer' is collapsed to the input area, hints are computed
in viewport only and they're followed when user input matches the hint string.")
(style
(theme:themed-css (theme *browser*)
`(".nyxt-hint"
:background-color ,(cl-colors2:print-hex theme:background- :alpha 0.925)
:color ,theme:on-background
:font-family ,theme:monospace-font-family
:font-size ".85rem"
:padding "0px 0.3em"
:border-color ,(cl-colors2:print-hex theme:primary- :alpha 0.80)
:border-radius "3px"
:border-width "2px"
:border-style "solid"
:z-index #.(1- (expt 2 31)))
`(".nyxt-hint.nyxt-mark-hint"
:background-color ,theme:secondary
:color ,theme:on-secondary
:font-weight "bold")
`(".nyxt-hint.nyxt-select-hint"
:background-color ,theme:action
:color ,theme:on-action)
`(".nyxt-hint.nyxt-match-hint"
:padding "0px"
:border-style "none"
:opacity "0.5")
`(".nyxt-element-hint"
:background-color ,theme:action))
:documentation "The style of the hint overlays.")
(show-hint-scope-p
nil
:type boolean
Expand All @@ -70,16 +43,20 @@ define which elements are picked up by element hinting.
For instance, to include images:

a, button, input, textarea, details, select, img:not([alt=\"\"])")
(hints-offset-x
(x-translation
0
:type integer
:documentation "The number of pixels that hint overlays are horizontally shifted by.
:documentation "The horizontal translation as a percentage of the hint's size.
A positive value shifts to the right.")
(hints-offset-y
(y-translation
0
:type integer
:documentation "The number of pixels that hint overlays are vertically shifted by.
:documentation "The vertical translation as a percentage of the hint's size.
A positive value shifts to the bottom.")
(x-placement
:left
:type keyword
:documentation "The horizontal placement of the hints: either `:left' or `:right'.")
(keyscheme-map
(define-keyscheme-map "hint-mode" ()
keyscheme:cua
Expand Down Expand Up @@ -108,41 +85,79 @@ A positive value shifts to the bottom.")
"g f" 'follow-hint-nosave-buffer
"g F" 'follow-hint-nosave-buffer-focus)))))

(defmethod style ((mode hint-mode))
"The style of the hint overlays."
(theme:themed-css (theme *browser*)
`(".nyxt-hint"
:background-color ,(cl-colors2:print-hex theme:background- :alpha 0.925)
:color ,theme:on-background
:font-family ,theme:monospace-font-family
:font-size ".85rem"
:position "absolute"
:transform ,(format nil "translate(~a%,~a%)"
(+ (x-translation mode)
(if (eq (x-placement mode) :right) -100 0))
aadcg marked this conversation as resolved.
Show resolved Hide resolved
(y-translation mode))
:padding "0px 0.3em"
:border-color ,(cl-colors2:print-hex theme:primary- :alpha 0.80)
:border-radius "3px"
:border-width "2px"
:border-style "solid"
:z-index #.(1- (expt 2 31)))
`(".nyxt-hint.nyxt-mark-hint"
:background-color ,theme:secondary
:color ,theme:on-secondary
:font-weight "bold")
`(".nyxt-hint.nyxt-current-hint"
:background-color ,theme:action
:color ,theme:on-action)
`(".nyxt-hint.nyxt-match-hint"
:padding "0px"
:border-style "none"
:opacity "0.5")
`(".nyxt-element-hint"
:background-color ,theme:action)))

(define-configuration document-buffer
((default-modes (cons 'hint-mode %slot-value%))))

(define-parenscript-async hint-elements (hints)
(defun create-hint-overlay (original-element hint)
(defun create-hint-element (hint)
(let ((hint-element (ps:chain document (create-element "span"))))
(setf (ps:@ hint-element class-name) "nyxt-hint"
(ps:@ hint-element id) (+ "nyxt-hint-" hint)
(ps:@ hint-element text-content) hint)
hint-element))

(defun set-hint-element-style (hint-element hinted-element)
(let ((right-x-alignment-p (eq (ps:lisp (x-placement (find-submode 'hint-mode)))
:right))
(rect (ps:chain hinted-element (get-bounding-client-rect)))
(hinted-element-font-size (ps:@ (ps:chain window (get-computed-style hinted-element))
font-size))
(hint-font-size-lower-bound 5))
(setf (ps:@ hint-element style top) (+ (ps:@ window scroll-y) (ps:@ rect top) "px")
(ps:@ hint-element style left) (+ (ps:@ window scroll-x) (ps:@ rect left)
(when right-x-alignment-p (ps:@ rect width)) "px"))
(when (> (parse-float hinted-element-font-size)
hint-font-size-lower-bound)
(setf (ps:@ hint-element style font-size) hinted-element-font-size))))

(defun create-hint-overlay (hinted-element hint)
"Create a DOM element to be used as a hint."
(ps:let ((user-x-offset (ps:lisp (hints-offset-x (find-submode 'hint-mode))))
(user-y-offset (ps:lisp (hints-offset-y (find-submode 'hint-mode))))
(rect (ps:chain original-element (get-bounding-client-rect)))
(element (ps:chain document (create-element "span"))))
(setf (ps:@ element class-name) "nyxt-hint"
(ps:@ element style position) "absolute"
(ps:@ element style left) (+ (ps:max (+ (ps:@ window page-x-offset)
(ps:@ rect left)
user-x-offset)
0)
"px")
(ps:@ element style top) (+ (ps:max (+ (ps:@ window page-y-offset)
(ps:@ rect top)
user-y-offset)
0)
"px")
(ps:@ element id) (+ "nyxt-hint-" hint)
(ps:@ element text-content) hint)
element))
(let ((hint-element (create-hint-element hint)))
(set-hint-element-style hint-element hinted-element))
hint-element)

(let ((hints-parent (ps:chain document (create-element "div")))
(hints (ps:lisp (list 'quote hints)))
(i 0))
(dolist (element (nyxt/ps:qsa document "[nyxt-hintable]"))
(dolist (hinted-element (nyxt/ps:qsa document "[nyxt-hintable]"))
(let ((hint (aref hints i)))
(ps:chain element (set-attribute "nyxt-hint" hint))
(ps:chain hints-parent (append-child (create-hint-overlay element hint)))
(ps:chain hinted-element (set-attribute "nyxt-hint" hint))
(ps:chain hints-parent (append-child (create-hint-overlay hinted-element hint)))
(when (ps:lisp (show-hint-scope-p (find-submode 'hint-mode)))
(ps:chain element class-list (add "nyxt-element-hint")))
(ps:chain hinted-element class-list (add "nyxt-element-hint")))
(setf i (1+ i))))
(setf (ps:@ hints-parent id) "nyxt-hints"
(ps:@ hints-parent style) "all: unset !important;")
Expand Down Expand Up @@ -222,20 +237,19 @@ A positive value shifts to the bottom.")

(export-always 'highlight-selected-hint)
(define-parenscript highlight-selected-hint (&key element scroll)
;; TODO: Also change border or something else to augment color change.
"Accent the hint for the ELEMENT to be distinguishable from other hints.
If SCROLL (default to NIL), scroll the hint into view."
(let ((%element (nyxt/ps:qs document (ps:lisp (format nil "#nyxt-hint-~a"
(identifier element))))))
(when %element
(unless (ps:chain %element class-list (contains "nyxt-select-hint"))
(unless (ps:chain %element class-list (contains "nyxt-current-hint"))
;; There should be, at most, a unique element with the
;; "nyxt-select-hint" class.
;; "nyxt-current-hint" class.
;; querySelectAll, unlike querySelect, handles the case when none are
;; found.
(ps:dolist (selected-hint (nyxt/ps:qsa document ".nyxt-select-hint"))
(ps:chain selected-hint class-list (remove "nyxt-select-hint"))))
(ps:chain %element class-list (add "nyxt-select-hint"))
(ps:dolist (selected-hint (nyxt/ps:qsa document ".nyxt-current-hint"))
(ps:chain selected-hint class-list (remove "nyxt-current-hint"))))
(ps:chain %element class-list (add "nyxt-current-hint"))
(when (ps:lisp scroll)
(ps:chain %element (scroll-into-view (ps:create block "center")))))))

Expand Down
32 changes: 32 additions & 0 deletions tests/renderer-offline/hint-mode-html-document.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<title>Hint test page</title>
<style>
body { margin:0; }
a { position:absolute; }
a.left { left:1px; }
a.center { left:50%; }
a.right { right:1px; }
a.top { top:1px; }
a.middle { top:50%; }
a.bottom { bottom:1px; }
a.bigger { font-size:24px; }
</style>
</head>

<body>
<a href="https://nyxt-browser.com/" class="left top bigger">left top</a>
<a href="https://nyxt-browser.com/" class="center top">center top</a>
<a href="https://nyxt-browser.com/" class="right top">right top</a>
<a href="https://nyxt-browser.com/" class="left middle">left middle</a>
<a href="https://nyxt-browser.com/" class="center middle bigger">center middle</a>
<a href="https://nyxt-browser.com/" class="right middle">right middle</a>
<a href="https://nyxt-browser.com/" class="left bottom">left bottom</a>
<a href="https://nyxt-browser.com/" class="center bottom">center bottom</a>
<a href="https://nyxt-browser.com/" class="right bottom bigger">right bottom</a>
</body>
</html>