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

Add support for persistent superchats #79

Merged
merged 47 commits into from
Jun 17, 2022
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
2a69054
rework css for pinned message to allow sticky
KentoNishi May 24, 2022
90b978d
add a sticky bar with chips
KentoNishi May 27, 2022
3260a63
parse ticker actions instead
KentoNishi May 29, 2022
fa4a341
progress so far
KentoNishi May 30, 2022
547b5bf
timed superchat appearance
KentoNishi May 30, 2022
bfcce23
superchat ticking progress
KentoNishi May 30, 2022
b1bce68
expand tickers
KentoNishi May 30, 2022
419622e
changes to types
KentoNishi May 30, 2022
5ecec4c
disallow duplicates
KentoNishi May 30, 2022
9db9f09
removed some extra css
KentoNishi May 30, 2022
703a4bf
fix: use smelte dark instead of location dark for stickybar
r2dev2 May 31, 2022
c2b5799
start showing supas immediately on load
KentoNishi Jun 2, 2022
1e8fc0e
Merge branch 'sticky-superchats' of github.com:LiveTL/HyperChat into …
KentoNishi Jun 2, 2022
add3ef2
use fullDurationSec
KentoNishi Jun 2, 2022
1fb0181
add touch and horizontal scrollwheel support
KentoNishi Jun 2, 2022
43dc929
clearer close button
KentoNishi Jun 2, 2022
ea164e3
only update stickySuperchats if items in discard
KentoNishi Jun 2, 2022
7fa40f3
Merge branch 'master' into sticky-superchats
KentoNishi Jun 4, 2022
8a2a0f0
fix small forceTLColor bug
KentoNishi Jun 7, 2022
7f4ee1b
fix disappearing bar
KentoNishi Jun 8, 2022
45503b7
safeguard possibly null runs prop
KentoNishi Jun 8, 2022
a1d6d62
remove messageId prop
KentoNishi Jun 8, 2022
3834d2d
truncate long names
KentoNishi Jun 8, 2022
9757f74
enableStickySuperchatBar setting
KentoNishi Jun 10, 2022
fc8c551
WIP liveChatTickerSponsorItemRenderer
KentoNishi Jun 10, 2022
a2d8b90
parse membership items in parseTickerAction
KentoNishi Jun 10, 2022
e8c1b35
partially implemented sticky bar for members
KentoNishi Jun 11, 2022
f354919
display member items on the bar
KentoNishi Jun 11, 2022
e870f44
expand membership chips on click
KentoNishi Jun 11, 2022
95137bd
thin scrollbars everywhere
KentoNishi Jun 11, 2022
7297a34
5-second leniency for sticky bar
KentoNishi Jun 11, 2022
7b6a084
pixel-perfect vertical centering cuz im a nerd
KentoNishi Jun 11, 2022
adad8e8
evenly padded superchat dialog
KentoNishi Jun 11, 2022
e0759c2
fixed some padding
KentoNishi Jun 11, 2022
1d863b1
fixed bugs + overlapped absolute items
KentoNishi Jun 14, 2022
7759590
workaround for ff
KentoNishi Jun 14, 2022
b6d7852
run superchat bar on 500ms tick
KentoNishi Jun 14, 2022
45efba1
some visual stuff
KentoNishi Jun 14, 2022
1d4a4fc
take ur uncustomizable scrollbar, ff users
KentoNishi Jun 14, 2022
9780564
w-full
KentoNishi Jun 14, 2022
5687d21
remove transition
KentoNishi Jun 14, 2022
77ff141
open, dispatch('resize')
KentoNishi Jun 15, 2022
cd9d63d
changelog
KentoNishi Jun 15, 2022
bae8f36
slightly shorter changelog
KentoNishi Jun 15, 2022
7048db6
forgot to SET stickySuperchats
KentoNishi Jun 15, 2022
ba7bc8d
Un-absolute sticky bar
ChrRubin Jun 16, 2022
ddfeacf
update changelog
KentoNishi Jun 17, 2022
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
73 changes: 47 additions & 26 deletions src/components/Hyperchat.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import '../stylesheets/scrollbar.css';
import { onDestroy, afterUpdate, tick } from 'svelte';
import { fade } from 'svelte/transition';
import dark from 'smelte/src/dark';
Expand All @@ -8,6 +9,8 @@
import PaidMessage from './PaidMessage.svelte';
import MembershipItem from './MembershipItem.svelte';
import ReportBanDialog from './ReportBanDialog.svelte';
import SuperchatViewDialog from './SuperchatViewDialog.svelte';
import StickyBar from './StickyBar.svelte';
import {
paramsTabId,
paramsFrameId,
Expand All @@ -31,7 +34,10 @@
hoveredItem,
port,
selfChannelId,
alertDialog
alertDialog,
stickySuperchats,
currentProgress,
enableStickySuperchatBar
} from '../ts/storage';

const welcome = { welcome: true, message: { messageId: 'welcome' } };
Expand Down Expand Up @@ -91,11 +97,11 @@
if (!isAtBottom) return;
// On replays' initial data, only show messages with negative timestamp
if (isInitial && isReplay) {
messageActions.push(...messagesAction.messages.filter(
messageActions.push(...filterTickers(messagesAction.messages).filter(
(a) => a.message.timestamp.startsWith('-') && shouldShowMessage(a)
));
} else {
messageActions.push(...messagesAction.messages.filter(shouldShowMessage));
messageActions.push(...filterTickers(messagesAction.messages).filter(shouldShowMessage));
}
if (!isInitial) checkTruncateMessages();
};
Expand All @@ -109,6 +115,25 @@
});
};

const filterTickers = (items: Chat.MessageAction[]): Chat.MessageAction[] => {
const keep: Chat.MessageAction[] = [];
const discard: Ytc.ParsedTicker[] = [];
items.forEach(item => {
if (
'tickerDuration' in item.message &&
!$stickySuperchats.some(sc => sc.messageId === item.message.messageId)
) discard.push(item.message);
else keep.push(item);
});
if ($enableStickySuperchatBar && discard.length) {
$stickySuperchats = [
...discard,
...$stickySuperchats
];
}
return keep;
};

const onDelete = (deletion: Ytc.ParsedDeleted) => {
messageActions.some((action) => {
if (isWelcome(action)) return false;
Expand Down Expand Up @@ -137,6 +162,9 @@
case 'unpin':
pinned = null;
break;
case 'playerProgress':
$currentProgress = action.playerProgress;
break;
case 'forceUpdate':
messageActions = [...action.messages].filter(shouldShowMessage);
if (action.showWelcome) {
Expand Down Expand Up @@ -251,7 +279,6 @@
);

const containerClass = 'h-screen w-screen text-black dark:text-white dark:bg-black dark:bg-opacity-25';
const pinnedClass = 'absolute top-2 inset-x-2';

const isSuperchat = (action: Chat.MessageAction) => (action.message.superChat || action.message.superSticker);
const isMembership = (action: Chat.MessageAction) => (action.message.membership);
Expand All @@ -262,9 +289,15 @@
if (action == null) $hoveredItem = null;
else if (!('welcome' in action)) $hoveredItem = action.message.messageId;
};

const clearStickySuperchats = () => {
$stickySuperchats = [];
};
$: if (!$enableStickySuperchatBar) clearStickySuperchats();
</script>

<ReportBanDialog />
<SuperchatViewDialog />

<svelte:window on:resize={scrollToBottom} on:load={onLoad} />

Expand All @@ -289,18 +322,22 @@
<Message
message={action.message}
deleted={action.deleted}
messageId={action.message.messageId}
/>
{/if}
</div>
{/each}
</div>
</div>
{#if pinned}
<div class={pinnedClass}>
<PinnedMessage pinned={pinned} />
</div>
{/if}
<div class="absolute top-0 w-full">
{#if $enableStickySuperchatBar}
<StickyBar />
{/if}
{#if pinned}
<div class="mx-2 mt-2">
<PinnedMessage pinned={pinned} />
</div>
{/if}
</div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sticky bar blocks the top most message since its in an absolute div:

image

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the same with pinned messages btw.

{#if !isAtBottom}
<div
class="absolute left-1/2 transform -translate-x-1/2 bottom-0 pb-1"
Expand All @@ -312,22 +349,6 @@
</div>

<style>
.content {
scrollbar-width: thin;
scrollbar-color: #888 transparent;
}
.content::-webkit-scrollbar {
width: 4px;
}
.content::-webkit-scrollbar-track {
background: transparent;
}
.content::-webkit-scrollbar-thumb {
background: #888;
}
.content::-webkit-scrollbar-thumb:hover {
background: #555;
}
.hover-highlight {
/* transition: 0.1s; */
background-color: transparent;
Expand Down
51 changes: 34 additions & 17 deletions src/components/MembershipItem.svelte
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
<script lang="ts">
import Message from './Message.svelte';
import MessageRun from './MessageRuns.svelte';
import { showProfileIcons } from '../ts/storage';
import { focusedSuperchat, showProfileIcons } from '../ts/storage';

export let message: Ytc.ParsedMessage;
export let message: Ytc.ParsedTimedItem;
export let chip = false;
export let detailText: string = '';
export let fillPortion = 1;

const classes = 'inline-flex flex-col rounded break-words overflow-hidden w-full text-white';
const classes = `inline-flex flex-col rounded text-white ${chip ? 'w-fit whitespace-nowrap' : 'w-full break-words'}`;

$: membership = message.membership;
$: if (!membership) {
Expand All @@ -15,30 +18,44 @@
</script>

{#if membership}
<div class={classes} style="background-color: #0f9d58;">
<div class={classes} style={chip ? '' : 'background-color: #0f9d58;'}>
<div
class="p-2"
style="{isMilestoneChat ? 'background-color: #107516;' : ''}"
class="relative {chip ? 'rounded-full flex items-center cursor-pointer w-max p-1.5 overflow-hidden' : 'rounded p-2'}"
style="background-color: #{isMilestoneChat ? '107516' : '0f9d58'};"
on:click={() => {
if (chip) $focusedSuperchat = message;
}}
>
{#if $showProfileIcons}
<img
class="h-5 w-5 inline align-middle rounded-full flex-none"
class="h-5 w-5 inline align-middle rounded-full flex-none mr-1"
src={message.author.profileIcon.src}
alt={message.author.profileIcon.alt}
/>
{/if}
<span class="font-bold tracking-wide align-middle mr-3">
{message.author.name}
</span>
{#if membership.headerPrimaryText.length > 0}
<MessageRun
class="font-medium mr-3"
runs={membership.headerPrimaryText}
/>
{#if chip}
<div class="absolute top-0 right-0 h-full" style="
background-color: rgba(0, 0, 0, 0.1);
width: {Math.round(fillPortion * 100)}%;
" />
{/if}
{#if !chip}
<span class="font-bold tracking-wide mr-3 align-middle">
{message.author.name}
</span>
{#if membership.headerPrimaryText.length > 0}
<MessageRun
class="font-medium mr-3 align-middle"
runs={membership.headerPrimaryText}
/>
{/if}
<MessageRun runs={membership.headerSubtext} />
{/if}
{#if chip && detailText}
<span class="font-bold align-middle">{detailText}</span>
{/if}
<MessageRun runs={membership.headerSubtext} />
</div>
{#if isMilestoneChat}
{#if !chip && isMilestoneChat}
<div class="p-2">
<Message message={message} hideName />
</div>
Expand Down
3 changes: 1 addition & 2 deletions src/components/Message.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

export let message: Ytc.ParsedMessage;
export let deleted: Chat.MessageDeletedObj | null = null;
export let messageId: Chat.MessageAction['message']['messageId'];
export let forceDark = false;
export let hideName = false;

Expand Down Expand Up @@ -131,7 +130,7 @@
<MessageRun runs={message.message} {forceDark} deleted={deleted != null} {forceTLColor} />
</div>
{#if message.author.id !== $selfChannelId}
<Menu items={menuItems} visible={$hoveredItem === messageId} class="mr-2 ml-auto context-menu">
<Menu items={menuItems} visible={$hoveredItem === message.messageId} class="mr-2 ml-auto context-menu">
<Icon slot="activator" style="font-size: 1.5em;">more_vert</Icon>
</Menu>
{/if}
Expand Down
88 changes: 51 additions & 37 deletions src/components/MessageRuns.svelte
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<script lang="ts">
import type { Theme } from '../ts/chat-constants';
import { Theme } from '../ts/chat-constants';

import TranslatedMessage from './TranslatedMessage.svelte';
import {
emojiRenderMode, useSystemEmojis
} from '../ts/storage';
import { YoutubeEmojiRenderMode } from '../ts/chat-constants';

export let runs: Ytc.ParsedRun[];
export let runs: Ytc.ParsedRun[] | null;
export let forceDark = false;
export let deleted = false;
export let forceTLColor: Theme;
export let forceTLColor: Theme = Theme.YOUTUBE;

let deletedClass = '';

Expand All @@ -23,39 +23,53 @@
}
</script>

<span
class="cursor-auto align-middle {deletedClass} {$$props.class ?? ''}"
style="word-break: break-word"
>
{#each runs as run}
{#if run.type === 'text'}
{#if deleted}
<span>{run.text}</span>
{:else}
<TranslatedMessage text={run.text} {forceTLColor} />
{/if}
{:else if run.type === 'link'}
<a
class="inline underline align-middle"
href={run.url}
target="_blank"
>
{run.text}
</a>
{:else if run.type === 'emoji' && $emojiRenderMode !== YoutubeEmojiRenderMode.HIDE_ALL}
{#if run.standardEmoji && $useSystemEmojis}
<span
class="cursor-auto align-middle text-base"
<!--
The `runs` prop is supposed to always be an array,
but somewhere, somehow, sometimes, YouTube forgets
to provide us an array.

This is sorta cheap, but the easiest solution is
to safeguard a null prop value with a simple check.

If anyone wants to find a more elegant solution,
see this bug report:
https://discord.com/channels/780938154437640232/788107573755904070/983867679968477215
-->
{#if runs?.length}
<span
class="cursor-auto align-middle {deletedClass} {$$props.class ?? ''}"
style="word-break: break-word"
>
{#each runs as run}
{#if run.type === 'text'}
{#if deleted}
<span>{run.text}</span>
{:else}
<TranslatedMessage text={run.text} {forceTLColor} />
{/if}
{:else if run.type === 'link'}
<a
class="inline underline align-middle"
href={run.url}
target="_blank"
>
{run.alt}
</span>
{:else if run.src}
<img
class="h-5 w-5 inline mx-0.5 align-middle"
src={run.src}
alt={run.alt}
/>
{run.text}
</a>
{:else if run.type === 'emoji' && $emojiRenderMode !== YoutubeEmojiRenderMode.HIDE_ALL}
{#if run.standardEmoji && $useSystemEmojis}
<span
class="cursor-auto align-middle text-base"
>
{run.alt}
</span>
{:else if run.src}
<img
class="h-5 w-5 inline mx-0.5 align-middle"
src={run.src}
alt={run.alt}
/>
{/if}
{/if}
{/if}
{/each}
</span>
{/each}
</span>
{/if}
Loading