Skip to content

Commit

Permalink
[twitter] Improve Bolt layout and animations
Browse files Browse the repository at this point in the history
  • Loading branch information
nikicat committed Nov 26, 2022
1 parent 7370c23 commit 15fb19d
Show file tree
Hide file tree
Showing 9 changed files with 166 additions and 32 deletions.
5 changes: 5 additions & 0 deletions extensions/src/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,11 @@ const Options = {
type: "section",
name: "Twitter options",
options: {
enableReply: {
type: "checkbox",
default: true,
description: "Open reply automatically",
},
twitterDefaultReply: {
type: "text",
default: "Absolutely! Here is a %amount% sats tip via @donate4_fun %link%",
Expand Down
138 changes: 117 additions & 21 deletions extensions/src/twitter/Bolt.svelte
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
<script>
import { tick } from "svelte";
import { backIn, expoIn } from "svelte/easing";
import { quintOut } from "svelte/easing";
import { slide, fade } from 'svelte/transition';
import { LottiePlayer } from '@lottiefiles/svelte-lottie-player';
import Bolt from "$lib/Bolt.svelte";
import HoldButton from "$lib/HoldButton.svelte";
import Button from "$lib/Button.svelte";
import { cLog, cInfo } from "$lib/log.js";
import { worker, donate, getStatic, waitElement, pageScript, selectByPattern } from "$extlib/common.js";
import { getCurrentAccountHandle } from "./twitter.js";
Expand All @@ -13,22 +15,24 @@
let donating = false;
let amount = 0;
let confetti = false;
let hasReply = false;
let elem;
let lottiePlayer;
const amountItems = [{value: 100, text: '100'}, {value: 1000, text: '1K'}, {value: 10_000, text: '10K'}];
let holdButton;
async function doDonate(event) {
async function doDonate() {
donating = true;
amount = event.detail.amount || await worker.getConfig('amount');
const amount_ = amount || await worker.getConfig('amount');
amount = 0;
try {
const donation = await donate(amount, tweetUrl, getCurrentAccountHandle());
const donation = await donate(amount_, tweetUrl, getCurrentAccountHandle());
donating = false;
onPaid(donation);
} catch (err) {
donating = false;
cInfo("Payment failed", err);
const rejected = err.message === 'User rejected';
worker.createPopup(`nowebln/${amount}/${rejected}`);
worker.createPopup(`nowebln/${amount_}/${rejected}`);
}
}
Expand All @@ -41,8 +45,7 @@
const lottie = lottiePlayer.getLottie();
lottie.addEventListener("complete", async () => {
confetti = false;
cLog("amount", donation.amount);
if (await worker.getConfig("enableComment") && !hasReply) {
if (await worker.getConfig("enableReply")) {
await postReply(donation);
}
});
Expand All @@ -63,49 +66,93 @@
return;
selectByPattern(textElement, /^.+!/g)
}
function fixAmount(amount_) {
holdButton.pause();
amount = amount_;
}
function resumeIncrease() {
holdButton.resume();
}
function whoosh(node, params) {
const existingTransform = getComputedStyle(node).transform.replace('none', '');
return {
delay: params.delay || 0,
duration: params.duration || 400,
easing: params.easing || elasticOut,
css: (t, u) => `transform: ${existingTransform} scale(${t}) translateY(calc(${u} * 35px))`
};
}
</script>

<div bind:this={elem} class="container">
{#if confetti}
<LottiePlayer
src={getStatic("lottie-bolt.json")}
autoplay={true}
loop={false}
width={30}
height={30}
background=transparent
controls={null}
controlsLayout={[]}
bind:this={lottiePlayer}
/>
<div class="animating-bolt">
<LottiePlayer
src={getStatic("lottie-bolt.json")}
autoplay={true}
loop={false}
width={34}
height={39}
background=transparent
controls={null}
controlsLayout={[]}
bind:this={lottiePlayer}
/>
</div>
{:else if donating}
<div>...</div>
<div class="donating-bolt"><Bolt /></div>
{:else}
<HoldButton bind:amount={amount} on:release={doDonate}>
<HoldButton bind:this={holdButton} bind:amount={amount} on:release={doDonate}>
{#if amount}
<div class="amount-container">
⚡ <span class="amount">{amount.toFixed()}</span> sats
</div>
<div class="select-tooltip" in:whoosh="{{delay: 250, duration: 300, easing: quintOut }}">
{#each amountItems as amount_}
<div
on:mouseenter={() => fixAmount(amount_.value)}
on:mouseleave={resumeIncrease}
on:mouseup={doDonate}
>
<Button
--padding="8px"
selected={amount_.value === amount}
dimmed={amount_.value !== amount}
>⚡{amount_.text}</Button>
</div>
{/each}
</div>
{:else}
<div class="bolt-circle">
<div class="bolt">
<Bolt />
</div>
</div>
<div class="tooltip">
Hold to donate more
</div>
{/if}
</HoldButton>
{/if}
</div>

<style>
.container {
position: relative;
display: flex;
align-self: center;
justify-content: center;
margin: -10px 0;
align-items: center;
color: rgb(83, 100, 113);
cursor: pointer;
font-family: "TwitterChirp";
min-width: 34px;
min-height: 39px;
}
.amount {
font-weight: 700;
Expand All @@ -117,6 +164,8 @@
align-items: center;
justify-content: center;
gap: 0.2em;
min-width: 120px;
user-select: none;
}
.bolt-circle {
display: flex;
Expand All @@ -126,13 +175,26 @@
width: calc(1.25em + 16px);
height: calc(1.25em + 16px);
}
.animating-bolt {
}
.donating-bolt {
width: 10px;
}
@media (prefers-color-scheme: dark) {
.container {
color: rgb(113, 118, 123);
}
.amount {
color: rgb(231, 233, 234);
}
.tooltip {
background-color: rgba(91, 112, 131, 0.8);
}
}
@media (prefers-color-scheme: light) {
.tooltip {
background-color: rgba(0, 0, 0, 0.6);
}
}
.bolt-circle:hover {
background-color: rgba(240, 118, 29, 0.1);
Expand All @@ -145,4 +207,38 @@
width: 1.25em;
height: 1.25em;
}
.tooltip {
position: absolute;
display: none;
top: -20px;
left: -35px;
padding: 2px 4px;
border-radius: 2px;
font-size: 11px;
line-height: 12px;
font-weight: 400;
color: white;
font-family: TwitterChirp, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
white-space: nowrap;
opacity: 0;
}
.bolt-circle:hover + .tooltip {
display: block;
opacity: 1;
transition-property: opacity;
transition-delay: 500ms;
transition-duration: 500ms;
}
.select-tooltip {
position: absolute;
display: flex;
align-items: center;
top: -35px;
left: -30px;
display: flex;
gap: 4px;
}
</style>
2 changes: 1 addition & 1 deletion extensions/src/twitter/contentscript.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ async function patchTweet(tweet) {
else if (isTweetPage())
tweetUrl = getTweetUrl();
else {
cError("Tweet has no url nor this is tweet page", tweet);
cLog("Tweet has no url nor this is tweet page", tweet);
return;
}
cLog("patching tweet", tweet, tweetUrl);
Expand Down
2 changes: 1 addition & 1 deletion extensions/src/twitter/twitter.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export function getCurrentAccountHandle() {
const prefix = 'UserAvatar-Container-';
const avatar = document.querySelector(`[data-testid="SideNav_AccountSwitcher_Button"] [data-testid^="${prefix}"]`)
return avatar.dataset.testid.replace(prefix, '');
return avatar?.dataset.testid.replace(prefix, '');
}

2 changes: 1 addition & 1 deletion frontend/src/lib/Button.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ button.selected {
button.dimmed {
box-shadow: 10px 15px 25px rgba(209, 217, 230, 0.4);
background: linear-gradient(90deg, rgba(249, 240, 62, 0.4) 0%, rgba(157, 237, 162, 0.4) 100%), #FFFFFF;
border: 1px solid rgba(26, 41, 82, 0.05);
border: var(--border-width-secondary) solid rgba(26, 41, 82, 0.05);
}
/* background */
button.white > div,button.blue > div {
Expand Down
9 changes: 8 additions & 1 deletion frontend/src/lib/Donation.svelte
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<script>
import { createEventDispatcher } from 'svelte';
import { link } from "svelte-navigator";
import Button from "$lib/Button.svelte";
import Section from "$lib/Section.svelte";
import Infobox from "$lib/Infobox.svelte";
Expand Down Expand Up @@ -62,12 +64,17 @@
<Button on:click={() => dispatch("close")} class="grey">Back</Button>
{/if}
{:else if donation.twitter_account}
<Donator user={donation.donator} />
{#if donation.donator_twitter_account}
<TwitterAccount account={donation.donator_twitter_account} />
{:else}
<Donator user={donation.donator} />
{/if}
<div class="twitter-donation">
donated <Amount amount={donation.amount} /> to
</div>
<TwitterAccount account={donation.twitter_account} />
<TwitterShare text="Hey @{donation.twitter_account.handle}, I've sent you a donation" />
<a use:link href="/twitter/{donation.twitter_account.id}/owner">Claim</a>
{/if}
{:else}
Unpaid donation
Expand Down
28 changes: 23 additions & 5 deletions frontend/src/lib/HoldButton.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,50 @@
export let amount;
let interval;
let startTimer;
const dispatch = createEventDispatcher();
function onMouseDown() {
amount = 10;
interval = setInterval(() => {
amount = amount * 1.1;
startTimer = setTimeout(() => {
amount = 100;
resume();
}, 100);
}
function onMouseUp() {
if (interval) {
dispatch('release', { amount: Math.round(amount) });
amount = 0;
} else if (startTimer) {
dispatch('release', 0);
}
stopInterval();
}
function onMouseLeave() {
endHold();
stopInterval();
amount = 0;
}
function endHold() {
function stopInterval() {
if (interval) {
clearInterval(interval);
interval = null;
}
if (startTimer) {
clearTimeout(startTimer);
startTimer = null;
}
}
export function pause() {
stopInterval();
}
export function resume() {
interval = setInterval(() => {
amount = amount * 1.1;
}, 100);
}
</script>

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/routes/TwitterAccountOwnerPage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
async function load() {
account = await api.get(baseUrl);
if (!account.is_my)
navigate('/twitter/prove');
navigate('/twitter/prove', {replace: true});
}
async function claim() {
Expand Down
10 changes: 9 additions & 1 deletion frontend/src/routes/TwitterProvePage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
<span><a href="https://twitter.com/messages/compose?recipient_id=1572908920485576704&text={proveMessage}" target=_blank>Send a magic direct message</a> to our account and wait for a reply.</span>
{/await}
</summary>
<div>
<div class="linked-accounts">
{#await loadLinkedTwitterAccounts() then twitter_accounts}
{#if twitter_accounts.length}
<h2>Linked accounts</h2>
Expand All @@ -55,6 +55,7 @@
main {
display: flex;
flex-direction: column;
align-items: center;
gap: 32px;
padding: 36px 85px 40px 85px;
width: 640px;
Expand All @@ -65,6 +66,13 @@ h1 {
text-align: center;
margin: 0;
}
summary {
text-align: center;
width: 300px;
}
.linked-accounts {
align-self: start;
}
h2 {
font-weight: 600;
font-size: 11px;
Expand Down

0 comments on commit 15fb19d

Please sign in to comment.