update potus tracker
This commit is contained in:
parent
b3e96b68b2
commit
4c558fa4ac
131
src/lib/components/VideoPlayer.svelte
Normal file
131
src/lib/components/VideoPlayer.svelte
Normal file
@ -0,0 +1,131 @@
|
||||
<script lang="ts">
|
||||
import { onMount, onDestroy } from "svelte";
|
||||
import { browser } from "$app/environment";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
let id = uuidv4();
|
||||
|
||||
export let src;
|
||||
export let hideProgressbar = false;
|
||||
|
||||
let container; // container div reference
|
||||
let video; // video element reference
|
||||
let observer;
|
||||
let progress = -1;
|
||||
let isPlaying = false;
|
||||
|
||||
onMount(() => {
|
||||
// Set up IntersectionObserver to auto-play/pause when in/out of view
|
||||
if (browser) {
|
||||
const handleIntersect = (entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (!entry?.isIntersecting) {
|
||||
pauseVideo();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const options = { threshold: 0.4, rootMargin: "0px" };
|
||||
observer = new IntersectionObserver(handleIntersect, options);
|
||||
|
||||
if (container) {
|
||||
observer.observe(container);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function updateProgress() {
|
||||
if (video && video.duration && !video.paused) {
|
||||
progress = (video.currentTime / video.duration) * 100;
|
||||
progress = parseFloat(progress.toFixed(2));
|
||||
}
|
||||
}
|
||||
|
||||
// Update progress on time update
|
||||
$: {
|
||||
if (video) {
|
||||
video.ontimeupdate = updateProgress;
|
||||
}
|
||||
}
|
||||
|
||||
onDestroy(() => {
|
||||
if (observer) {
|
||||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
|
||||
function playVideo() {
|
||||
if (video) {
|
||||
video.play();
|
||||
video.muted = false;
|
||||
isPlaying = true;
|
||||
}
|
||||
}
|
||||
|
||||
function pauseVideo() {
|
||||
if (video) {
|
||||
video.pause();
|
||||
video.muted = true;
|
||||
isPlaying = false;
|
||||
}
|
||||
}
|
||||
|
||||
function togglePlayback(event) {
|
||||
// Prevent click event from bubbling to the container if needed
|
||||
event.stopPropagation();
|
||||
if (video.paused) {
|
||||
playVideo();
|
||||
} else {
|
||||
pauseVideo();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="video-container" bind:this={container} on:click={togglePlayback}>
|
||||
<video
|
||||
{id}
|
||||
playsinline
|
||||
loop
|
||||
class="w-full max-w-96 rounded"
|
||||
{src}
|
||||
bind:this={video}
|
||||
on:loadedmetadata={updateProgress}
|
||||
></video>
|
||||
<div class="play-pause-icon" on:click|stopPropagation={togglePlayback}>
|
||||
{#if isPlaying}
|
||||
<!-- Pause icon: two vertical bars -->
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
|
||||
</svg>
|
||||
{:else}
|
||||
<!-- Play icon: triangle -->
|
||||
<svg viewBox="0 0 24 24">
|
||||
<path d="M8 5v14l11-7z" />
|
||||
</svg>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.video-container {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
.play-pause-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
cursor: pointer;
|
||||
z-index: 10;
|
||||
/* Optional: style the icon's background and appearance */
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
border-radius: 50%;
|
||||
padding: 0.5rem;
|
||||
}
|
||||
.play-pause-icon svg {
|
||||
fill: white;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
</style>
|
||||
@ -12,6 +12,7 @@
|
||||
const updatedSectorList = ["S&P500", ...sectorList];
|
||||
|
||||
let rawData = data?.getData?.history || [];
|
||||
let posts = data?.getData?.posts || [];
|
||||
let executiveOrders = data?.getData?.executiveOrders || [];
|
||||
let selectedSector = "S&P500";
|
||||
const sectorDict = {
|
||||
@ -35,14 +36,14 @@
|
||||
month: "short",
|
||||
year: "numeric",
|
||||
timeZone: "UTC",
|
||||
}).format(new Date(item.date));
|
||||
}).format(new Date(item?.date));
|
||||
|
||||
if (!acc[dateKey]) acc[dateKey] = [];
|
||||
acc[dateKey].push(item);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
let groupedOrders = executiveOrders.reduce((acc, item) => {
|
||||
let groupedOrders = executiveOrders?.reduce((acc, item) => {
|
||||
const dateKey = new Intl.DateTimeFormat("en-US", {
|
||||
day: "2-digit",
|
||||
month: "short",
|
||||
@ -62,6 +63,9 @@
|
||||
{
|
||||
title: "Executive Orders",
|
||||
},
|
||||
{
|
||||
title: "Truth Social Post",
|
||||
},
|
||||
];
|
||||
|
||||
let activeIdx = 0;
|
||||
@ -424,7 +428,7 @@
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
{:else if activeIdx === 1}
|
||||
<h3
|
||||
class="text-white text-lg sm:text-xl font-semibold mb-2 mt-6 border-y border-gray-800 pt-2 pb-2"
|
||||
>
|
||||
@ -483,7 +487,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="text-sm ml-14 pt-2">
|
||||
<span class="text-md ml-14 pt-2">
|
||||
{#if item.description.length > 150}
|
||||
{expandedDescriptions[item.title]
|
||||
? item.description
|
||||
@ -592,6 +596,166 @@
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{:else if activeIdx === 2}
|
||||
<div
|
||||
class="flex flex-row items-center mb-2 mt-6 border-y border-gray-800 pt-2 pb-2"
|
||||
>
|
||||
<svg
|
||||
class="w-7 h-7 rounded-full inline-block"
|
||||
fill="none"
|
||||
viewBox="0 0 92 92"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
><path d="m0 .438202h91.56v91.56h-91.56z" fill="#5448ee" /><g
|
||||
fill="#fff"
|
||||
><path d="m67.9385 54.0751h-11.5057v9.3631h11.5057z" /><path
|
||||
d="m63.4377 37.8944v-9.4562h-23.4446v34.9084h11.9665v-25.4522z"
|
||||
/><path d="m24 28.4382h11.4878v9.4539h-11.4878z" /></g
|
||||
></svg
|
||||
>
|
||||
<h3 class="ml-2 text-white text-lg sm:text-xl font-semibold">
|
||||
Truth Social Posts
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="max-h-[600px] overflow-y-auto border border-gray-800 rounded-md p-4 no-scrollbar"
|
||||
>
|
||||
<div class="space-y-4">
|
||||
{#each posts as item}
|
||||
<div class="my-4">
|
||||
<div
|
||||
class="flex flex-col items-start space-y-1 mb-6 border-b border-gray-800 pb-4"
|
||||
>
|
||||
<div class="flex items-start space-x-3">
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
href="https://truthsocial.com/@realDonaldTrump"
|
||||
class="avatar w-10 h-10 rounded-full flex-shrink-0"
|
||||
>
|
||||
<img
|
||||
class="rounded-full"
|
||||
src={avatar}
|
||||
alt="Avatar"
|
||||
loading="lazy"
|
||||
/></a
|
||||
>
|
||||
|
||||
<div class="flex flex-col items-start w-full">
|
||||
<h3 class="text-white font-semibold">
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
href="https://truthsocial.com/@realDonaldTrump"
|
||||
class="sm:hover:text-blue-400"
|
||||
>Donald J. Trump</a
|
||||
>
|
||||
</h3>
|
||||
<h4 class="text-sm text-gray-400">
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
href="https://truthsocial.com/@realDonaldTrump"
|
||||
class="sm:hover:text-blue-400"
|
||||
>@realDonaldTrump</a
|
||||
>
|
||||
· {item?.date}
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="text-md ml-12">
|
||||
{item?.content}
|
||||
</span>
|
||||
|
||||
<a
|
||||
href={item?.source}
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
class="ml-12 pt-5 inline-block text-sm text-white sm:hover:underline"
|
||||
>
|
||||
Original Post
|
||||
<svg
|
||||
class="w-4 h-4 sm:w-5 sm:h-5 -mt-0.5 inline-block"
|
||||
fill="#fff"
|
||||
viewBox="0 0 64 64"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xml:space="preserve"
|
||||
xmlns:serif="http://www.serif.com/"
|
||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"
|
||||
><g id="SVGRepo_bgCarrier" stroke-width="0"></g><g
|
||||
id="SVGRepo_tracerCarrier"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
></g><g id="SVGRepo_iconCarrier">
|
||||
<rect
|
||||
id="Icons"
|
||||
x="-896"
|
||||
y="0"
|
||||
width="1280"
|
||||
height="800"
|
||||
style="fill:none;"
|
||||
></rect>
|
||||
<g id="Icons1" serif:id="Icons">
|
||||
<g id="Strike"> </g> <g id="H1"> </g>
|
||||
<g id="H2"> </g> <g id="H3"> </g>
|
||||
<g id="list-ul"> </g>
|
||||
<g id="hamburger-1"> </g>
|
||||
<g id="hamburger-2"> </g>
|
||||
<g id="list-ol"> </g>
|
||||
<g id="list-task"> </g> <g id="trash"> </g>
|
||||
<g id="vertical-menu"> </g>
|
||||
<g id="horizontal-menu"> </g>
|
||||
<g id="sidebar-2"> </g> <g id="Pen"> </g>
|
||||
<g id="Pen1" serif:id="Pen"> </g>
|
||||
<g id="clock"> </g>
|
||||
<g id="external-link">
|
||||
<path
|
||||
d="M36.026,20.058l-21.092,0c-1.65,0 -2.989,1.339 -2.989,2.989l0,25.964c0,1.65 1.339,2.989 2.989,2.989l26.024,0c1.65,0 2.989,-1.339 2.989,-2.989l0,-20.953l3.999,0l0,21.948c0,3.308 -2.686,5.994 -5.995,5.995l-28.01,0c-3.309,0 -5.995,-2.687 -5.995,-5.995l0,-27.954c0,-3.309 2.686,-5.995 5.995,-5.995l22.085,0l0,4.001Z"
|
||||
></path>
|
||||
<path
|
||||
d="M55.925,25.32l-4.005,0l0,-10.481l-27.894,27.893l-2.832,-2.832l27.895,-27.895l-10.484,0l0,-4.005l17.318,0l0.002,0.001l0,17.319Z"
|
||||
></path>
|
||||
</g> <g id="hr"> </g> <g id="info"> </g>
|
||||
<g id="warning"> </g>
|
||||
<g id="plus-circle"> </g>
|
||||
<g id="minus-circle"> </g> <g id="vue"> </g>
|
||||
<g id="cog"> </g> <g id="logo"> </g>
|
||||
<g id="radio-check"> </g>
|
||||
<g id="eye-slash"> </g> <g id="eye"> </g>
|
||||
<g id="toggle-off"> </g>
|
||||
<g id="shredder"> </g>
|
||||
<g
|
||||
id="spinner--loading--dots-"
|
||||
serif:id="spinner [loading, dots]"
|
||||
>
|
||||
</g> <g id="react"> </g>
|
||||
<g id="check-selected"> </g>
|
||||
<g id="turn-off"> </g>
|
||||
<g id="code-block"> </g>
|
||||
<g id="user"> </g> <g id="coffee-bean"> </g>
|
||||
<g id="coffee-beans">
|
||||
<g id="coffee-bean1" serif:id="coffee-bean">
|
||||
</g>
|
||||
</g> <g id="coffee-bean-filled"> </g>
|
||||
<g id="coffee-beans-filled">
|
||||
<g id="coffee-bean2" serif:id="coffee-bean">
|
||||
</g>
|
||||
</g> <g id="clipboard"> </g>
|
||||
<g id="clipboard-paste"> </g>
|
||||
<g id="clipboard-copy"> </g>
|
||||
<g id="Layer1"> </g>
|
||||
</g>
|
||||
</g></svg
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user