mirror of
https://github.com/TiddlyWiki/TiddlyWiki5.git
synced 2026-04-25 23:14:35 +00:00
Introduce Tour Plugin and Confetti Plugin, improve Dynannotate Plugin (#7734)
* First commit * Typo * Add support for delay parameter * Add confetti widget * Add tour plugin * Add element spotlight to dynannotate plugin Useful for highlighting on screen elements for the user * More and bigger confetti by default * Use new element spotlight to provide hints * Adjust hint selectors for create tiddler tour step * Include confetti plugin in prerelease * Clarify wording of confetti demo * Don't link TiddlyWiki in the tour panel * Tweaks to tour buttons * Mark dependents of the tour plugin * Add full screen section of tour and tour edition * Remove Anna Freud references from welcome tiddler * Build the tour edition in the preview * Fix typo in build script * Populate tour edition with solar system data From Simple English Wikipedia * Missing tag * Add page control button to start tour Also make the tour controls visible in full screen mode * Refactor to use global procedures to control the tour * Change "startup-actions" field to "enter-actions" to avoid confusion * Add a tour logo * Refactor to allow multiple tours to be loaded at once * Remove wikification from welcome tour step * Update docs * Simplify styles for top bar * Tours should have a $:/tags/Tour tag * Tour should autostart in the tour edition, but not in the main wiki * Better labelling for the main preview * Fix build process We build a separate tour.html wiki, but can include the tour in other wikis too * Remove obsolete text * Add "using tags" as a separate tour * Remove old debugging code * Add tour chooser * Ensure that the current tour isn't listed as an option in the final step * Use whitespace trim Note that the setting is inherited by procedure and widget definitions * Simplify tour step format * Remove obsolete state tiddler Not needed because now we initialise it in startup actions * Fix gap between navigation buttons * Clean up tiddler titles within the introduction tour * Finish allowing the name "TiddlyWiki" to be customised Some of the code was in the previous commit. Next we'll wire up the user interface * Clarify docs * Add a settings pane giving a birds eye view of a tour * Avoid having to embed confetti in the final step * Update docs * Tweak styling of tour chooser dropdown * Add a button to launch tour steps directly, and give them captions * Expose custom tour settings * Use the tour step caption as the heading * Fix initialisation when jumping to a tour step * Introduce step about tags * Improve wording * Improve styling of task call-to-action and nav buttons * Adopt new conditional shortcut syntax * Wording and ordering tweaks * Fix typos Thanks @pmario * Simplify styling of tour overlay * Use custom palette colours Makes it easier for people to use their own colour scheme for the tour * More custom colours * Tour wording tweaks * Extends the tour plugin with a condition field (#7861) * feat: support condition field to determine whether a step should be shown * feat: add support for overriding the hint text using the field 'hint' from the step tiddler * fix: roll back tour display procedure for now until an override mechanism has been discussed * fix: renamed advance-criterion field and associated variables to step-success-filter * fix: renamed hint field to hint-text and selector to hint-selector * refactor: to create function to get all tour tiddlers filtered by their condition field * refactor: rename globals tiddlers to variables and avoid making any of the tour procedures global * fix: also rename globals.tid file to variables.tid * docs: cover all tour steps tiddler fields * fix: improve spacing in Tour HUD * WIP --------- Co-authored-by: Jeremy Ruston <174761+Jermolene@users.noreply.github.com> Co-authored-by: Saq Imtiaz <saq.imtiaz@gmail.com>
This commit is contained in:
136
plugins/tiddlywiki/dynannotate/modules/element-spotlight.js
Normal file
136
plugins/tiddlywiki/dynannotate/modules/element-spotlight.js
Normal file
@@ -0,0 +1,136 @@
|
||||
/*\
|
||||
title: $:/plugins/tiddlywiki/dynannotate/element-spotlight.js
|
||||
type: application/javascript
|
||||
module-type: library
|
||||
|
||||
Manages the element spotlight effect
|
||||
|
||||
\*/
|
||||
(function(){
|
||||
|
||||
/*jslint node: true, browser: true */
|
||||
/*global $tw: false */
|
||||
"use strict";
|
||||
|
||||
function ElementSpotlight() {
|
||||
this.animationStartTime; // Undefined if no animation is in progress
|
||||
// Create DOM nodes
|
||||
this.spotlightElement = $tw.utils.domMaker("div",{
|
||||
"class": "tc-dynannotate-spotlight"
|
||||
});
|
||||
this.spotlightWrapper = $tw.utils.domMaker("div",{
|
||||
"class": "tc-dynannotate-spotlight-wrapper",
|
||||
children: [
|
||||
this.spotlightElement
|
||||
]
|
||||
});
|
||||
document.body.appendChild(this.spotlightWrapper);
|
||||
}
|
||||
|
||||
/*
|
||||
Return the first visible element that matches a selector
|
||||
*/
|
||||
ElementSpotlight.prototype.querySelectorSafe = function(selector) {
|
||||
var targetNodes;
|
||||
// Get the matching elements
|
||||
try {
|
||||
targetNodes = document.querySelectorAll(selector);
|
||||
} catch(e) {
|
||||
console.log("Error with selector: " + selector);
|
||||
}
|
||||
if(!targetNodes) {
|
||||
return undefined;
|
||||
}
|
||||
// Remove any elements from the start of the list that are hidden, or have hidden ancestors
|
||||
var didRemoveFirstEntry;
|
||||
do {
|
||||
didRemoveFirstEntry = false;
|
||||
var hasHiddenAncestor = false,
|
||||
n = targetNodes[0];
|
||||
while(n) {
|
||||
if(n.hidden || (n instanceof Element && window.getComputedStyle(n).display === "none")) {
|
||||
hasHiddenAncestor = true;
|
||||
break;
|
||||
}
|
||||
n = n.parentNode;
|
||||
}
|
||||
if(hasHiddenAncestor) {
|
||||
// Remove first entry from targetNodes array
|
||||
targetNodes = [].slice.call(targetNodes, 1);
|
||||
didRemoveFirstEntry = true;
|
||||
}
|
||||
} while(didRemoveFirstEntry)
|
||||
// Return the first result
|
||||
return targetNodes[0];
|
||||
};
|
||||
|
||||
ElementSpotlight.prototype.positionSpotlight = function(x,y,innerRadius,outerRadius,opacity) {
|
||||
this.spotlightElement.style.display = "block";
|
||||
this.spotlightElement.style.backgroundImage = "radial-gradient(circle at " + (x / window.innerWidth * 100) + "% " + (y / window.innerHeight * 100) + "%, transparent " + innerRadius + "px, rgba(0, 0, 0, " + opacity + ") " + outerRadius + "px)";
|
||||
};
|
||||
|
||||
ElementSpotlight.prototype.easeInOut = function(v) {
|
||||
return (Math.sin((v - 0.5) * Math.PI) + 1) / 2;
|
||||
};
|
||||
|
||||
/*
|
||||
Shine a spotlight on the first element that matches an array of selectors
|
||||
*/
|
||||
ElementSpotlight.prototype.shineSpotlight = function(selectors) {
|
||||
var self = this;
|
||||
function animationLoop(selectors) {
|
||||
// Calculate how far through the animation we are
|
||||
// 0...1 = zoom in
|
||||
// 1...2 = hold
|
||||
// 2...3 = fade out
|
||||
var now = new Date(),
|
||||
t = (now - self.animationStartTime) / ($tw.utils.getAnimationDuration() * 2);
|
||||
t = t >= 3 ? 3 : t;
|
||||
// Query the selector for the target element
|
||||
var targetNode, selectorIndex = 0;
|
||||
while(!targetNode && selectorIndex < selectors.length) {
|
||||
targetNode = self.querySelectorSafe(selectors[selectorIndex]);
|
||||
selectorIndex += 1;
|
||||
}
|
||||
// Position the spotlight if we've got the target
|
||||
if(targetNode) {
|
||||
var rect = targetNode.getBoundingClientRect();
|
||||
var innerRadius, outerRadius, opacity;
|
||||
if(t <= 1) {
|
||||
t = self.easeInOut(t);
|
||||
innerRadius = rect.width / 2 + (window.innerWidth * 2 * (1 - t));
|
||||
outerRadius = rect.width + (window.innerWidth * 3 * (1 - t));
|
||||
opacity = 0.2 + t / 4;
|
||||
} else if(t <= 2) {
|
||||
innerRadius = rect.width / 2;
|
||||
outerRadius = rect.width;
|
||||
opacity = 0.45;
|
||||
} else {
|
||||
t = self.easeInOut(3 - t);
|
||||
innerRadius = rect.width / 2 + (window.innerWidth * 2 * (1 - t));
|
||||
outerRadius = rect.width + (window.innerWidth * 3 * (1 - t));
|
||||
opacity = t / 3;
|
||||
}
|
||||
self.positionSpotlight((rect.left + rect.right) / 2,(rect.top + rect.bottom) / 2,innerRadius,outerRadius,opacity);
|
||||
} else {
|
||||
self.spotlightElement.style.display = "none";
|
||||
}
|
||||
// Call the next frame unless we're at the end
|
||||
if(t <= 3) {
|
||||
window.requestAnimationFrame(function () {
|
||||
animationLoop(selectors);
|
||||
});
|
||||
} else {
|
||||
// End the animation if we've exceeded the time limit
|
||||
self.animationStartTime = undefined;
|
||||
}
|
||||
}
|
||||
this.animationStartTime = new Date();
|
||||
window.requestAnimationFrame(function () {
|
||||
animationLoop(selectors);
|
||||
});
|
||||
};
|
||||
|
||||
exports.ElementSpotlight = ElementSpotlight;
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user