diff --git a/source/tours/exports.ts b/source/tours/exports.ts new file mode 100644 index 0000000..402023b --- /dev/null +++ b/source/tours/exports.ts @@ -0,0 +1,11 @@ +import {homepageSteps, homepageEventHandlers} from "./interface/exports.js"; +import {introductionSteps} from "./introduction.js"; + +export const tourIds = ["introduction", "interface-homepage"] as const; + +export const tourIdsAndSteps: Array< + [TourId, TourStepOptions[], TourStepEventHandler[]] +> = [ + ["introduction", introductionSteps, []], + ["interface-homepage", homepageSteps, homepageEventHandlers], +]; diff --git a/source/tours/interface/exports.ts b/source/tours/interface/exports.ts new file mode 100644 index 0000000..393473b --- /dev/null +++ b/source/tours/interface/exports.ts @@ -0,0 +1,4 @@ +export { + eventHandlers as homepageEventHandlers, + steps as homepageSteps, +} from "./homepage.js"; diff --git a/source/tours/interface/homepage.tsx b/source/tours/interface/homepage.tsx new file mode 100644 index 0000000..a08ee65 --- /dev/null +++ b/source/tours/interface/homepage.tsx @@ -0,0 +1,499 @@ +import type Shepherd from "shepherd.js"; +import { + addDatasetCounter, + encapsulateElements, + removeAllDatasetCounters, + renderInContainer, +} from "../utilities.js"; + +const step01 = renderInContainer( + <> +
+ If you plan on staying a while, this is likely the place you'll see the + most. So let's work our way top to bottom, left to right. +
+ +Starting with...
+ >, +); + +const step02 = renderInContainer( + <> ++ On the left there is the Tildes logo and title, which you can click to get + back to the homepage, or refresh it if you're already there. If you are in + a group, the group name will also be shown. +
+ ++ On the right is the notifications section and your username. When you have + unread messages and/or are mentioned, they will show up next to your + username. If you don't have any notifications right now, you can{" "} + + click here + {" "} + to show a preview of what they look like. +
+ ++ At the moment mentions only work in comments, so if you get mentioned in a + topic's text body and don't get a notification,{" "} + + that's why + + . +
+ >, +); + +// Toggle mock notifications, based on the code in the following link. +// If the logic for this needs to be updated, also update the permalink to the +// actual Tildes HTML code. +// https://gitlab.com/tildes/tildes/-/blob/0dbb031562cd9297968fec0049af4b833ef77301/tildes/tildes/templates/macros/user.jinja2#L9-20 +function toggleMockNotifications(event: Event): void { + // Prevent the click from going through so the anchor isn't removed. + event.preventDefault(); + + const root = document.querySelector("#site-header .logged-in-user-info"); + function toggle(existingSelector: string, href: string, text: string): void { + const existing = + root?.querySelector+ Right below the main header are the topic listing options. These determine + how the topics in the listing are sorted and{" "} + + from what period + {" "} + topics should be shown. +
+ ++ The non-activity sorts are the easiest to explain, so let's start with + them: +
+ ++ Then the first Activity will sort topics by bumping topics up as + they receive comments, however this sort makes use of comment labels. +
+ ++ If you don't know what comment labels are yet, don't worry, there is a + tour that explains them. But in short they are a community tool to + emphasize and de-emphasize comments, similar to votes but with more + specific intention. If you'd like to read more, check out{" "} + + the documentation + + . +
+ ++ And finally the All activity sorts topics the same as Activity, but + without taking into account any comment labels. +
+ ++ If you only want to see topics from a certain period, click on the "from" + dropdown and select your period. Aside from a set of predefined options, + you can also set a custom one by clicking the "other period" option, after + which you'll be prompted for it. +
+ >, +); + +const step04 = renderInContainer( + <> ++ Next up, just below the listing options is the topic listing itself. We've + only highlighted the first topic here, but you can probably see it + continues all the way down the page. +
+ +Here, we've marked the main elements of the topic:
+ +The list continues on the next page.
+ >, +); + +const step05 = renderInContainer( + <> ++ Let's take a look at the sidebar, where the first thing we're greeted with + is the search bar. +
+ ++ A quick note for mobile use, the sidebar can opened via a button that + appears in the very top-right of the page. +
+ ++ When searching from the homepage, topics will be included from any group. + However, searching when inside a group will only include topics from that + group and any sub-groups. +
+ ++ Below the search bar you will also find the title of the page, or name of + the group, and a small description. The sidebar has more elements when in + you're in a group page, but those are touched upon in the groups tour. +
+ >, +); + +const step07 = renderInContainer( + <> ++ Moving on, you'll find the list of groups you are subscribed to and a + button below it to go to the groups listing, where you can find all the + that are available. +
+ ++ To post a topic, subscribe or unsubscribe from any group, go to the group + in question and in the sidebar there will be buttons to do so. +
+ >, +); + +const step08 = renderInContainer( + <> ++ At the bottom of the sidebar you will find some user settings. + Specifically the filtered topics tags you have set and a link to the + settings page. +
+ ++ When you have filtered topics tags set, any topics with any of the tags + present will be removed from your listing. You can read more about it by + going to the dedicated page for it by clicking the "Edit filtered tags" + button. +
+ >, +); + +const step09 = renderInContainer( + <> ++ And finally, the very last part of the homepage is the footer. Here you + will find a theme selector (more on that in a moment) and various links to + places, such as the Tildes Documentation, Contact page, the source code, + etc. We highly recommend reading through the documentation as it explains + a lot of the how and why Tildes does certain things. +
+ ++ As for the theme selector, you can change your theme with a number of + options. When you change it here, it will only change for the current + device, if you'd like to set an account default for all devices, head to + your account settings. +
+ >, +); + +const step10 = renderInContainer( + <> +And that's the end of the Homepage tour!
+ ++ As always, if you find any bugs, have feature requests or simply want to + ask a question. Please send us a message at{" "} + + @Community + + . +
+ +Happy Tildying!~
+ >, +); + +export const steps: Shepherd.Step.StepOptions[] = [ + { + id: "homepage-01", + text: step01, + }, + { + attachTo: { + element: "#site-header", + on: "bottom", + }, + canClickTarget: false, + id: "homepage-02", + scrollTo: true, + text: step02, + }, + { + attachTo: { + element: "main > .listing-options", + on: "bottom", + }, + canClickTarget: false, + id: "homepage-03", + text: step03, + }, + { + attachTo: { + element: ".topic-listing > li:first-child", + on: "bottom", + }, + canClickTarget: false, + id: "homepage-04", + text: step04, + }, + { + attachTo: { + element: ".topic-listing > li:first-child", + on: "bottom", + }, + canClickTarget: false, + id: "homepage-05", + text: step05, + }, + { + attachTo: { + element: '#sidebar [data-tildes-shepherd-encapsulated="homepage-06"]', + on: "left-start", + }, + canClickTarget: false, + id: "homepage-06", + text: step06, + }, + { + attachTo: { + element: '#sidebar [data-tildes-shepherd-encapsulated="homepage-07"]', + on: "left-start", + }, + canClickTarget: false, + id: "homepage-07", + scrollTo: true, + text: step07, + }, + { + attachTo: { + element: "#sidebar .divider + .nav", + on: "left-start", + }, + canClickTarget: false, + id: "homepage-08", + scrollTo: true, + text: step08, + }, + { + attachTo: { + element: "#site-footer", + on: "top", + }, + canClickTarget: false, + id: "homepage-09", + scrollTo: true, + text: step09, + }, + { + canClickTarget: false, + id: "homepage-10", + text: step10, + }, +]; + +export const eventHandlers: TourStepEventHandler[] = [ + [ + "homepage-04", + [ + "show", + () => { + const topic = ".topic-listing > li:first-child"; + const counters = [ + ".topic-title", + ".topic-metadata", + ".topic-info-comments", + ".topic-info-source", + "time", + ".topic-voting", + ".topic-actions", + ]; + + for (const [count, selector] of counters.entries()) { + addDatasetCounter(`${topic} ${selector}`, count + 1); + } + }, + ], + ], + [ + "homepage-05", + [ + "destroy", + () => { + removeAllDatasetCounters(); + }, + ], + ], + [ + "homepage-05", + [ + "show", + () => { + encapsulateElements( + "homepage-06", + "#sidebar .sidebar-controls", + "afterend", + ["#sidebar .form-search", "#sidebar h2", "#sidebar p"], + ); + }, + ], + ], + [ + "homepage-06", + [ + "show", + () => { + encapsulateElements("homepage-07", "#sidebar .divider", "beforebegin", [ + "#sidebar .nav", + '#sidebar [href="/groups"', + ]); + }, + ], + ], + [ + "homepage-08", + [ + "show", + () => { + const filteredTags = + document.querySelector+ Tildes Shepherd is a set of interactive guided tours for Tildes to show + you around and introduce you to the concepts that make this website great. +
+ ++ To see and start the tours that are available, click on the extension icon + to go to the options page or{" "} + + click here now + + . +
+ ++ Each tour will start with a pop-up like this one and have "Continue", + "Back" and "Exit" buttons at the bottom. They will progress the tour + forward, backward or exit it. +
+ >, +); + +const stepTwo = renderInContainer( + <> ++ During the tours, at various points we will want to highlight specific + areas. When that happens you won't be able to click anything inside them, + mainly to prevent you from accidentally going to a different page and + interrupting the tour. But also to prevent you from taking actions you + maybe don't want to take, like voting on something you don't necessarily + want to vote on. +
+ ++ Depending on your selected theme, the highlighted areas will have a yellow + or orange border and some extra added whitespace. As you can see in this + example where the main site header has been highlighted. +
+ >, +); + +const stepThree = renderInContainer( + <> ++ If you find any bugs, have feature requests or simply want to ask a + question. Please send us a message at{" "} + + @Community + + . +
+ ++ Also, big shoutout to the people at{" "} + + Ship Shape + {" "} + for making{" "} + + Shepherd.js + + , the software library making this entire project so much easier to + create. And the namesake of it, too. +
+ ++ Once you click the "I understand" button below, this message won't pop up + again, so remember the extension icon is how you get to the tours. +
+ +Happy Tildying!~
+ >, +); + +export const introductionSteps: Shepherd.Step.StepOptions[] = [ + { + id: "introduction-1", + text: stepOne, + }, + { + attachTo: { + element: "#site-header", + on: "bottom", + }, + canClickTarget: false, + id: "introduction-2", + text: stepTwo, + }, + { + buttons: [ + { + classes: "btn", + text: "I understand", + async action() { + const introductionUnderstood = await createIntroductionUnderstood(); + introductionUnderstood.value = true; + await introductionUnderstood.save(); + this.complete(); + }, + }, + { + classes: "btn", + text: "Back", + action() { + this.back(); + }, + }, + ], + id: "introduction-3", + text: stepThree, + }, +]; diff --git a/source/tours/utilities.ts b/source/tours/utilities.ts new file mode 100644 index 0000000..331f009 --- /dev/null +++ b/source/tours/utilities.ts @@ -0,0 +1,106 @@ +import {type JSX, render} from "preact"; +import browser from "webextension-polyfill"; + +/** + * Adds a `[data-tildes-shepherd-counter]` attribute to a specified element. For + * the associated CSS, see `source/content-scripts/scss/main.scss`. + * + * @param selector The selector of element to apply the counter to, if the + * target element can't be selected an error will be thrown. + * @param count The number to display in the counter. + */ +export function addDatasetCounter(selector: string, count: number) { + const element = document.querySelector