From 329e7039da1d7948aac8169468db04897fb1d32c Mon Sep 17 00:00:00 2001 From: waikoo Date: Wed, 31 May 2023 15:42:48 +0300 Subject: [PATCH 1/2] Add timestamps under introductory video --- docs/_static/timestamps.css | 99 +++++++++++++++ docs/_static/timestamps.js | 197 ++++++++++++++++++++++++++++++ docs/_static/timestamps_source.js | 110 +++++++++++++++++ docs/conf.py | 4 +- 4 files changed, 408 insertions(+), 2 deletions(-) create mode 100644 docs/_static/timestamps.css create mode 100644 docs/_static/timestamps.js create mode 100644 docs/_static/timestamps_source.js diff --git a/docs/_static/timestamps.css b/docs/_static/timestamps.css new file mode 100644 index 00000000000..752d1595d80 --- /dev/null +++ b/docs/_static/timestamps.css @@ -0,0 +1,99 @@ +:root { + --border-radius: 5.5px; +} + +body[data-theme="dark"] { +--kbd-bg: #ed9d13; +--code-bg: #3c3c3c; +--code-fg: var(--kbd-bg); +--span-fg: #a6aaa7; +} + +body[data-theme="light"] { +--kbd-bg: #ed9d13; +--code-bg: #3c3c3c; +--code-fg: #ffffff; +--code-bg: #888888; +} + +* { + box-sizing: border-box; +} + +#timestamps { + font-family: inherit; + width: 100%; + display: grid; + max-width: 900px; + grid-auto-rows: 2rem; + line-height: 1.2; + font-size: 16px; +} + +#timestamps .row { + display: flex; + align-items: center; + gap: 1rem .5rem; +} + +#timestamps time:hover { + text-decoration: underline; + padding-bottom: .2rem; +} +#timestamps time { + color: var(--color-link); +} +#timestamps time:hover { + cursor:pointer; +} +#timestamps time:focus { + text-decoration: underline; +} +#timestamps span { + margin: 0; +} +#timestamps p { + margin: 0.5rem; + line-height: 1.2; + display: flex; + align-items: center; +} +#timestamps kbd { + border-radius: var(--border-radius); + padding: .2rem; + padding-top: 0.4rem; + background: var(--kbd-bg); + color: black; + font-size: 0.9rem; + display: flex; + align-items: center; + justify-content: center; + border: none; + box-shadow: none; +} +@-moz-document url-prefix() { + #timestamps kbd { + padding: 0.2rem; + } +} + +#timestamps span { + color: var(--tabs--label-text); +} +#timestamps strong { + font-weight: normal; + min-width: max-content; +} +#timestamps code { + background: var(--code-bg); + color: var(--code-fg); + padding: 0.2rem 0.3rem; + margin-left: .2rem; + border-radius: var(--border-radius); + min-width: max-content; + font-size: 0.9rem; + display: grid; + place-items: center; + padding-top: 0.4rem; + +} diff --git a/docs/_static/timestamps.js b/docs/_static/timestamps.js new file mode 100644 index 00000000000..0a55f0b4ede --- /dev/null +++ b/docs/_static/timestamps.js @@ -0,0 +1,197 @@ +// NOTE: After updating timestamps_source.js, please update the term in the ARRAY object as well, +// so it can have the right styling +import timestamps from './timestamps_source.js' + +const ARRAY = { + SPAN: null, + KBD: ['Ctrl+Shift+g', "Ctrl+Shift+Left-click", 'y', 'Ctrl+Shift+F7', 'Ctrl+Shift+', 'Ctrl+Shift+Esc', 'Ctrl+Shift+'], + CODE: ['ls --hyperlink=auto', 'launch --allow-remote-control kitty +kitten broadcast', 'kitty +kitten themes -h', 'kitty +kitten themes [options] [theme_name]'] +} + +function init_timestamps() { + const timestamps_element = get_timestamps_container(timestamps) + timestamps_element.addEventListener('click', handle_timestamp_click) + + document.querySelector('.caption-text').insertAdjacentElement('afterend', timestamps_element) +} + +function handle_timestamp_click(e) { + if (e.target.tagName === 'TIME') { + const timestamp = e.target.getAttribute('datetime') + if (timestamp) { + const [minutes, seconds] = timestamp.split(':') + const totalSeconds = parseInt(minutes) * 60 + parseInt(seconds) + const video = document.querySelector('video') + video.currentTime = totalSeconds + video.play() + } + } +} + +function get_timestamps_container(file) { + const timestamps_container = document.createElement('section') + + const rows_array = file.map(entry => { + const [row_element, timestamp_element, description_element] + = get_timestamp_elements(entry) + + row_element.append(timestamp_element, description_element) + + return row_element + }) + rows_array.forEach(row => timestamps_container.appendChild(row)) + + timestamps_container.id = 'timestamps' + return timestamps_container +} + +function get_timestamp_elements(entry) { + return [ + get_simple_element('div', null, 'row'), + get_simple_element('time', entry.time), + get_updated_description_element(entry.description) + ] +} + +function get_simple_element(element, text_content = null, class_name = null) { + const new_element = document.createElement(element) + if (element === 'time') { + new_element.dateTime = new_element.textContent = text_content + return new_element + } + if (element === 'kbd' && !text_content) { + return + } + if (text_content) { + new_element.textContent = text_content + } + if (class_name) new_element.className = class_name + return new_element +} + +function get_updated_description_element(description) { + const span_content_array = [] + + const strong = get_strong_object(span_content_array, description) + const kbd = get_kbd_object(span_content_array, description) + const code = get_code_object(span_content_array, description) + const span_element = get_span_element(span_content_array, description) + + const array_of_elements = [strong.element, span_element, kbd.element, code.element].filter(Boolean) + + const description_element = get_simple_element('p') + description_element.append(...array_of_elements) + + return description_element +} + +function get_strong_object(span_content_array, description) { + const strong = { + element: null, + updated_description: null + } + set_strong_values(description, strong) + + if (strong.element) { + span_content_array.push(strong.updated_description) + } + return strong +} + +function set_strong_values(description, strong) { + const matches = description.match(/^[^:]+/) + strong.element = get_simple_element('strong', matches) + strong.updated_description = delete_keywords_from_description(matches, description) +} + +function get_kbd_object(span_content_array, description) { + const kbd = { + element: null, + updated_description: null + } + + set_kbd_values(span_content_array, description, kbd) + + if (kbd.updated_description) { + span_content_array[0] = kbd.updated_description + } + + return kbd +} + +function set_kbd_values(span_content_array, description, kbd) { + const last_updated_description = span_content_array.length > 0 ? span_content_array[0] : description + + const matching_words = get_matched_keyword(ARRAY.KBD, last_updated_description); + const has_matches = matching_words?.length > 0 + + if (!has_matches) return + + kbd.element = get_simple_element('kbd', matching_words) + kbd.updated_description = + delete_keywords_from_description( + matching_words, + last_updated_description + ) +} + +function get_span_element(span_content_array, description) { + let span_text_content = span_content_array.length < 1 ? description : span_content_array[0] + span_content_array.push(span_text_content) + + return get_simple_element('span', span_text_content) +} + +function get_code_object(span_content_array, description) { + const code = { + element: null, + updated_description: null + } + set_code_values(span_content_array, description, code) + + if (code.updated_description) { + span_content_array[0] = code.updated_description + } + return code +} + +function set_code_values(span_content_array, description, code) { + const last_updated_description = span_content_array.length > 0 ? span_content_array[0] : description + + const matching_words = get_matched_keyword(ARRAY.CODE, last_updated_description); + + const has_matches = matching_words?.length > 0 + + if (!has_matches) return + + code.element = get_simple_element('code', matching_words) + code.updated_description = + delete_keywords_from_description( + matching_words, + last_updated_description + ) +} + +function get_matched_keyword(substrings, updated_description) { + if (typeof updated_description !== 'string') return null + + const matches = substrings.filter(substring => { + return updated_description.includes(substring) + }) + if (matches.length < 1) return + + return matches +} + +function delete_keywords_from_description(matches, description) { + if (typeof matches === 'string') { + return description.replace(matches, '') + } + const combined_regex = new RegExp(matches.map(escape_regex).join('|'), 'g') + return description.replace(combined_regex, '') +} + +function escape_regex(string) { + return string.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&'); +} +window.onload = init_timestamps diff --git a/docs/_static/timestamps_source.js b/docs/_static/timestamps_source.js new file mode 100644 index 00000000000..fa2114467d4 --- /dev/null +++ b/docs/_static/timestamps_source.js @@ -0,0 +1,110 @@ +export default [ + { + time: "00:00", + description: "Intro" + }, + { + time: "00:39", + description: "Pager: View command output in same window: Ctrl+Shift+g" + }, + { + time: "01:43", + description: "Pager: View command output in a separate window" + }, + { + time: "02:14", + description: "Pager: Uses shell integration in kitty" + }, + { + time: "02:27", + description: "Tab text: The output of cwd and last cmd " + }, + { + time: "03:03", + description: "Open files from ls output with mouse: Ctrl+Shift+Left-click" + }, + { + time: "04:04", + description: "Open files from ls output with keyboard: y" + }, + { + time: "04:26", + description: "Open files on click: ls --hyperlink=auto" + }, + { + time: "05:03", + description: "Open files on click: Filetype settings in open-actions.conf" + }, + { + time: "05:45", + description: "Hyperlinked-grep kitten: Open grep output in editor" + }, + { + time: "07:18", + description: "Remote-file kitten: View remote files locally" + }, + { + time: "08:31", + description: "Remote-file kitten: Edit remote files locally" + }, + { + time: "10:01", + description: "Icat kitten: View images directly" + }, + { + time: "10:36", + description: "Icat kitten: Download & display image/gif from internet" + }, + { + time: "11:03", + description: "Kitty Graphics Protocol: Live image preview in ranger" + }, + { + time: "11:25", + description: "Icat kitten: Display image from remote server" + }, + { + time: "12:04", + description: "Unicode-input kitten: Emojis in terminal " + }, + { + time: "12:54", + description: "Windows: Intro" + }, + { + time: "13:36", + description: "Windows: Switch focus: Ctrl+Shift+" + }, + { + time: "13:48", + description: "Windows: Visual selection: Ctrl+Shift+F7" + }, + { + time: "13:58", + description: "Windows: Simultaneous input" + }, + { + time: "14:15", + description: "Interactive Kitty Shell: Ctrl+Shift+Esc" + }, + { + time: "14:36", + description: "Broadcast text: launch --allow-remote-control kitty +kitten broadcast" + }, + { + time: "15:18", + description: "Kitty Remote Control Protocol" + }, + { + time: "15:52", + description: "Interactive Kitty Shell: Help" + }, + { + time: "16:34", + description: "Choose theme interactively: kitty +kitten themes -h" + }, + { + time: "17:23", + description: "Choose theme by name: kitty +kitten themes [options] [theme_name]" + } +] diff --git a/docs/conf.py b/docs/conf.py index 721ce7d6070..b3ac238dd06 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -156,8 +156,8 @@ def go_version(go_mod_path: str) -> str: # {{{ # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] html_favicon = html_logo = '../logo/kitty.svg' -html_css_files = ['custom.css'] -html_js_files = ['custom.js'] +html_css_files = ['custom.css', 'style.css'] +html_js_files = ['custom.js', ('timestamps.js', {'type': 'module'})] # Custom sidebar templates, must be a dictionary that maps document names # to template names. From 9409fff163f6b0724ee986b2acde21e9ae36ff09 Mon Sep 17 00:00:00 2001 From: waikoo <74474701+waikoo@users.noreply.github.com> Date: Wed, 31 May 2023 15:45:56 +0300 Subject: [PATCH 2/2] Correct css filename --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index b3ac238dd06..ad94eb2f669 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -156,7 +156,7 @@ def go_version(go_mod_path: str) -> str: # {{{ # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] html_favicon = html_logo = '../logo/kitty.svg' -html_css_files = ['custom.css', 'style.css'] +html_css_files = ['custom.css', 'timestamps.css'] html_js_files = ['custom.js', ('timestamps.js', {'type': 'module'})] # Custom sidebar templates, must be a dictionary that maps document names