load senate images from s3 bucket instead of vercel static folder to be cost efficient
This commit is contained in:
parent
33a89e216d
commit
94bf05a9f3
@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { displayCompanyName, numberOfUnreadNotification, cryptoTicker } from '$lib/store';
|
||||
import defaultAvatar from '$lib/images/senator/default-avatar.png';
|
||||
import republicanBackground from "$lib/images/bg-republican.png";
|
||||
import democraticBackground from "$lib/images/bg-democratic.png";
|
||||
import otherBackground from "$lib/images/bg-other.png";
|
||||
@ -20,6 +19,9 @@
|
||||
let isLoaded = false;
|
||||
let images = {};
|
||||
|
||||
let cloudFrontUrl = import.meta.env.VITE_IMAGE_URL;
|
||||
|
||||
|
||||
function backToTop() {
|
||||
window.scrollTo({
|
||||
top: 0,
|
||||
@ -36,17 +38,6 @@ function changeStructure() {
|
||||
}
|
||||
|
||||
|
||||
const replacements = {
|
||||
'Thomas_Tuberville': 'Tommy_Tuberville',
|
||||
'Patrick_Toomey': 'Pat_Toomey',
|
||||
'Thomas_Carper': 'Tom_Carper',
|
||||
'Shelley_Moore_Capito': 'Shelley_Capito',
|
||||
'Christopher_Coons': 'Chris_Coons',
|
||||
'Daniel_Sullivan': 'Dan_Sullivan',
|
||||
'William_Cassidy': 'Bill_Cassidy',
|
||||
'Angus_King_.': 'Angus_King',
|
||||
};
|
||||
|
||||
const district = {
|
||||
'Tommy_Tuberville': 'Alabama',
|
||||
'Sheldon_Whitehouse': 'Rhode Island',
|
||||
@ -64,15 +55,7 @@ const district = {
|
||||
'Bill_Cassidy': 'Louisiana',
|
||||
}
|
||||
|
||||
function replaceMultipleStrings(inputString, replacements) {
|
||||
// Create a regular expression pattern by joining the keys of the replacements object with '|'
|
||||
const pattern = new RegExp(Object?.keys(replacements)?.join('|'), 'gi');
|
||||
|
||||
// Replace occurrences of the pattern with the corresponding values in the replacements object
|
||||
const resultString = inputString.replace(pattern, match => replacements[match]);
|
||||
|
||||
return resultString;
|
||||
}
|
||||
|
||||
async function infiniteHandler({ detail: { loaded, complete } })
|
||||
{
|
||||
@ -86,69 +69,42 @@ async function infiniteHandler({ detail: { loaded, complete } })
|
||||
}
|
||||
}
|
||||
|
||||
// Function to load images only when they are viewed
|
||||
async function loadImages() {
|
||||
const imageFiles = import.meta.glob('$lib/images/senator/*.png');
|
||||
const imagesPromises = [];
|
||||
|
||||
for (const [path, resolver] of Object?.entries(imageFiles)) {
|
||||
const imageNameMatch = path.match(/\/([^/]+)\.png$/);
|
||||
if (imageNameMatch && imageNameMatch[1] !== 'default-avatar') {
|
||||
imagesPromises?.push(resolver()?.then(module => {
|
||||
images[imageNameMatch[1]] = module.default;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
await Promise?.all(imagesPromises);
|
||||
}
|
||||
|
||||
|
||||
let fullName;
|
||||
|
||||
onMount(async () => {
|
||||
isLoaded = false;
|
||||
await loadImages();
|
||||
|
||||
rawData?.forEach(item => {
|
||||
let representative = item?.representative || '';
|
||||
|
||||
representative = representative?.replace('Jr', '')
|
||||
.replace(/Dr./g, '')
|
||||
.replace(/Dr_/g, '')
|
||||
|
||||
const fullName = representative?.replace(/(\s(?:Dr\s)?\w(?:\.|(?=\s)))?\s/g, '_').trim();
|
||||
item.image = images[fullName] || defaultAvatar;
|
||||
item.representative = fullName?.replace(/_/g, ' ');
|
||||
});
|
||||
|
||||
rawData = rawData?.map(item => {
|
||||
const party = getPartyForPoliticians(item?.representative);
|
||||
return {
|
||||
...item,
|
||||
party: party
|
||||
};
|
||||
});
|
||||
rawData.forEach(item => {
|
||||
const representative = item?.representative || '';
|
||||
const fullName = representative.replace(/(\s(?:Dr\s)?\w(?:\.|(?=\s)))?\s/g, '_').trim();
|
||||
item.representative = fullName.replace(/_/g, ' ');
|
||||
});
|
||||
|
||||
// Count the occurrences of "Republican" and "Democrat"
|
||||
const partyCounts = rawData?.reduce((counts, item) => {
|
||||
counts[item?.party] = (counts[item?.party] || 0) + 1;
|
||||
return counts;
|
||||
}, {});
|
||||
rawData = rawData?.map(item => {
|
||||
const party = getPartyForPoliticians(item?.representative);
|
||||
return {
|
||||
...item,
|
||||
party: party
|
||||
};
|
||||
});
|
||||
|
||||
const typeCounts = rawData?.reduce((counts, item) => {
|
||||
counts[item?.type] = (counts[item?.type ] || 0) + 1;
|
||||
return counts;
|
||||
}, {});
|
||||
// Count the occurrences of "Republican" and "Democrat"
|
||||
const partyCounts = rawData.reduce((counts, item) => {
|
||||
counts[item?.party] = (counts[item?.party] || 0) + 1;
|
||||
return counts;
|
||||
}, {});
|
||||
|
||||
partyRatio = partyCounts['Democratic'] > 0 && partyCounts['Republican'] === undefined ? 1 : partyCounts['Democratic'] === undefined ? 0 : partyCounts["Democratic"]/partyCounts["Republican"];
|
||||
buySellRatio = typeCounts['Bought'] > 0 && typeCounts['Sold'] === undefined ? 1 : typeCounts['Bought'] === undefined ? 0 : typeCounts["Bought"]/typeCounts["Sold"];
|
||||
const typeCounts = rawData.reduce((counts, item) => {
|
||||
counts[item?.type] = (counts[item?.type ] || 0) + 1;
|
||||
return counts;
|
||||
}, {});
|
||||
|
||||
senateTradingList = rawData?.slice(0,20) ?? [];
|
||||
partyRatio = partyCounts['Democratic'] > 0 && partyCounts['Republican'] === undefined ? 1 : partyCounts['Democratic'] === undefined ? 0 : partyCounts["Democratic"] / partyCounts["Republican"];
|
||||
buySellRatio = typeCounts['Bought'] > 0 && typeCounts['Sold'] === undefined ? 1 : typeCounts['Bought'] === undefined ? 0 : typeCounts["Bought"] / typeCounts["Sold"];
|
||||
|
||||
senateTradingList = rawData.slice(0, 20) ?? [];
|
||||
|
||||
isLoaded = true;
|
||||
|
||||
isLoaded = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -215,7 +171,7 @@ isLoaded = true;
|
||||
<!--Start Buy/Sell-->
|
||||
<div class="flex flex-row items-center flex-wrap w-full px-3 sm:px-4 bg-[#262626] shadow-lg rounded-2xl h-20">
|
||||
<div class="flex flex-col items-start">
|
||||
<span class="font-semibold text-gray-200 text-sm sm:text-[1rem] ">Buy/Sell</span>
|
||||
<span class="font-semibold text-gray-200 text-sm sm:text-[1rem]">Buy/Sell</span>
|
||||
<span class="text-start text-sm sm:text-[1rem] font-medium text-white">
|
||||
{buySellRatio?.toFixed(3)}
|
||||
</span>
|
||||
@ -232,7 +188,7 @@ isLoaded = true;
|
||||
</svg>
|
||||
<!-- Percentage Text -->
|
||||
<div class="absolute top-1/2 start-1/2 transform -translate-y-1/2 -translate-x-1/2">
|
||||
<span class="text-center text-white text-sm">{buySellRatio?.toFixed(2)}</span>
|
||||
<span class="text-center text-white text-sm sm:text-[1rem]">{buySellRatio?.toFixed(2)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Circular Progress -->
|
||||
@ -242,7 +198,7 @@ isLoaded = true;
|
||||
<!--Start Dem/Rep-->
|
||||
<div class="flex flex-row items-center flex-wrap w-full px-3 sm:px-4 bg-[#262626] shadow-lg rounded-2xl h-20">
|
||||
<div class="flex flex-col items-start">
|
||||
<span class="font-semibold text-gray-200 text-sm sm:text-[rem] ">Dem/Rep</span>
|
||||
<span class="font-semibold text-gray-200 text-sm sm:text-[1rem]">Dem/Rep</span>
|
||||
<span class="text-start text-sm sm:text-[1rem] font-medium text-white">
|
||||
{partyRatio?.toFixed(3)}
|
||||
</span>
|
||||
@ -259,7 +215,7 @@ isLoaded = true;
|
||||
</svg>
|
||||
<!-- Percentage Text -->
|
||||
<div class="absolute top-1/2 start-1/2 transform -translate-y-1/2 -translate-x-1/2">
|
||||
<span class="text-center text-white text-sm">{partyRatio?.toFixed(2)}</span>
|
||||
<span class="text-center text-white text-sm sm:text-[1rem]">{partyRatio?.toFixed(2)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Circular Progress -->
|
||||
@ -271,7 +227,7 @@ isLoaded = true;
|
||||
<!--End Widget-->
|
||||
|
||||
|
||||
<label on:click={changeStructure} class="sm:hidden w-24 sm:ml-3 mr-2 sm:mr-0 cursor-pointer bg-[#09090B] sm:hover:bg-[#09090B] duration-100 transition ease-in-out px-4 py-2 rounded-lg shadow-md">
|
||||
<label on:click={changeStructure} class="sm:hidden w-24 sm:ml-3 mr-2 sm:mr-0 cursor-pointer bg-[#27272A] px-4 py-2 rounded-lg shadow-md">
|
||||
<span class="m-auto mr-0.5 text-white text-sm">
|
||||
Switch To: {displayStructure}
|
||||
</span>
|
||||
@ -279,17 +235,17 @@ isLoaded = true;
|
||||
|
||||
|
||||
{#if displayStructure === 'Card'}
|
||||
<div class="mt-6 flex justify-start items-center w-full m-auto rounded-none sm:rounded-lg mb-4">
|
||||
<div class="mt-6 flex justify-start items-center w-full m-auto rounded-none sm:rounded-lg mb-4 overflow-x-scroll">
|
||||
<table class="table table-sm sm:table-md table-compact rounded-none sm:rounded-md w-full bg-[#09090B] border-bg-[#09090B] m-auto">
|
||||
<thead>
|
||||
<tr class="bg-[#09090B]">
|
||||
<th class="shadow-md text-start bg-[#09090B] text-white text-sm font-semibold">
|
||||
Person
|
||||
</th>
|
||||
<th class="shadow-md text-end bg-[#09090B] hidden sm:table-cell text-white text-sm font-semibold">
|
||||
<th class="shadow-md text-end bg-[#09090B] text-white text-sm font-semibold">
|
||||
Transaction Date
|
||||
</th>
|
||||
<th class="shadow-md text-end bg-[#09090B] text-white text-sm font-semibold">
|
||||
<th class="shadow-md text-end bg-[#09090B] text-white text-sm font-semibold">
|
||||
Amount
|
||||
</th>
|
||||
<th class="shadow-md text-white font-semibold text-end text-sm">Type</th>
|
||||
@ -299,27 +255,28 @@ isLoaded = true;
|
||||
{#each senateTradingList as item}
|
||||
<tr on:click={() => goto(`/politicians/${item?.id}`)} class="odd:bg-[#27272A] sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] bg-[#09090B] border-b-[#09090B] cursor-pointer">
|
||||
|
||||
<td class="text-gray-200 pb-3 border-b border-b-[#09090B]">
|
||||
<td class="text-white text-sm sm:text-[1rem] whitespace-nowrap pb-3 border-b border-b-[#09090B]">
|
||||
<div class="flex flex-row items-center">
|
||||
<div class="flex-shrink-0 rounded-full border border-slate-700 w-10 h-10 sm:w-12 sm:h-12 relative {item?.party === 'Republican' ? 'bg-[#98272B]' : item?.party === 'Democratic' ? 'bg-[#295AC7]' : 'bg-[#4E2153]'} flex items-center justify-center">
|
||||
<img style="clip-path: circle(50%);" class="avatar rounded-full w-7 sm:w-9" src={item?.image} loading="lazy"/>
|
||||
|
||||
<img style="clip-path: circle(50%);" class="avatar rounded-full w-7 sm:w-9" src={`${cloudFrontUrl}/assets/senator/${item?.representative?.replace(/\s+/g, "_")}.png`} loading="lazy"/>
|
||||
</div>
|
||||
<div class="flex flex-col ml-3">
|
||||
<span class="text-white">{item?.representative?.replace('_',' ')}</span>
|
||||
<span class="text-white text-opacity-60">{item?.party}</span>
|
||||
<span class="">{item?.representative?.replace('_',' ')}</span>
|
||||
<span class="">{item?.party}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!--{item?.firstName} {item?.lastName}-->
|
||||
</td>
|
||||
|
||||
<td class="text-end hidden sm:table-cell text-xs sm:text-sm text-white border-b border-b-[#09090B]">
|
||||
<td class="text-end text-sm sm:text-[1rem] whitespace-nowrap text-white border-b border-b-[#09090B]">
|
||||
{new Date(item?.transactionDate)?.toLocaleString('en-US', { month: 'short', day: 'numeric', year: 'numeric', daySuffix: '2-digit' })}
|
||||
</td>
|
||||
|
||||
<td class="text-end text-xs sm:text-sm text-white border-b border-b-[#09090B]">
|
||||
<td class="text-end text-sm sm:text-[1rem] whitespace-nowrap text-white border-b border-b-[#09090B]">
|
||||
{item?.amount}
|
||||
</td>
|
||||
<td class="text-start text-end text-sm text-white border-b border-b-[#09090B]">
|
||||
<td class="text-end text-sm sm:text-[1rem] whitespace-nowrap text-white border-b border-b-[#09090B]">
|
||||
{#if item?.type === 'Bought'}
|
||||
<span class="text-[#10DB06]">Bought</span>
|
||||
{:else if item?.type === 'Sold'}
|
||||
@ -355,7 +312,7 @@ isLoaded = true;
|
||||
|
||||
|
||||
<div class="-mt-3 shadow-lg rounded-full border border-slate-600 w-20 h-20 relative {item?.party === 'Republican' ? 'bg-[#98272B]' : item?.party === 'Democratic' ? 'bg-[#295AC7]' : 'bg-[#20202E]'} flex items-center justify-center">
|
||||
<img style="clip-path: circle(50%);" class="rounded-full w-16" src={item?.image} loading="lazy"/>
|
||||
<img style="clip-path: circle(50%);" class="rounded-full w-16" src={`${cloudFrontUrl}/assets/senator/${item?.representative?.replace(/\s+/g, "_")}.png`} loading="lazy"/>
|
||||
</div>
|
||||
<span class="text-white text-lg font-medium mt-2 mb-2">
|
||||
{item?.representative?.replace('_',' ')}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { displayCompanyName, numberOfUnreadNotification, etfTicker } from '$lib/store';
|
||||
import defaultAvatar from '$lib/images/senator/default-avatar.png';
|
||||
import republicanBackground from "$lib/images/bg-republican.png";
|
||||
import democraticBackground from "$lib/images/bg-democratic.png";
|
||||
import otherBackground from "$lib/images/bg-other.png";
|
||||
@ -9,6 +8,7 @@
|
||||
import { getPartyForPoliticians } from '$lib/utils';
|
||||
import { goto } from '$app/navigation';
|
||||
|
||||
|
||||
export let data;
|
||||
|
||||
let rawData = data?.getSenateTrading;
|
||||
@ -17,7 +17,9 @@
|
||||
let senateTradingList = [];
|
||||
let displayStructure = 'Card';
|
||||
let isLoaded = false;
|
||||
let images = {};
|
||||
|
||||
let cloudFrontUrl = import.meta.env.VITE_IMAGE_URL;
|
||||
|
||||
|
||||
function backToTop() {
|
||||
window.scrollTo({
|
||||
@ -35,17 +37,6 @@ function changeStructure() {
|
||||
}
|
||||
|
||||
|
||||
const replacements = {
|
||||
'Thomas_Tuberville': 'Tommy_Tuberville',
|
||||
'Patrick_Toomey': 'Pat_Toomey',
|
||||
'Thomas_Carper': 'Tom_Carper',
|
||||
'Shelley_Moore_Capito': 'Shelley_Capito',
|
||||
'Christopher_Coons': 'Chris_Coons',
|
||||
'Daniel_Sullivan': 'Dan_Sullivan',
|
||||
'William_Cassidy': 'Bill_Cassidy',
|
||||
'Angus_King_.': 'Angus_King',
|
||||
};
|
||||
|
||||
const district = {
|
||||
'Tommy_Tuberville': 'Alabama',
|
||||
'Sheldon_Whitehouse': 'Rhode Island',
|
||||
@ -63,15 +54,7 @@ const district = {
|
||||
'Bill_Cassidy': 'Louisiana',
|
||||
}
|
||||
|
||||
function replaceMultipleStrings(inputString, replacements) {
|
||||
// Create a regular expression pattern by joining the keys of the replacements object with '|'
|
||||
const pattern = new RegExp(Object.keys(replacements).join('|'), 'gi');
|
||||
|
||||
// Replace occurrences of the pattern with the corresponding values in the replacements object
|
||||
const resultString = inputString.replace(pattern, match => replacements[match]);
|
||||
|
||||
return resultString;
|
||||
}
|
||||
|
||||
async function infiniteHandler({ detail: { loaded, complete } })
|
||||
{
|
||||
@ -79,74 +62,48 @@ async function infiniteHandler({ detail: { loaded, complete } })
|
||||
complete();
|
||||
} else {
|
||||
const nextIndex = senateTradingList?.length;
|
||||
const newArticles = rawData?.slice(nextIndex, nextIndex + 5);
|
||||
const newArticles = rawData?.slice(nextIndex, nextIndex + 20);
|
||||
senateTradingList = [...senateTradingList, ...newArticles];
|
||||
loaded();
|
||||
}
|
||||
}
|
||||
|
||||
// Function to load images only when they are viewed
|
||||
async function loadImages() {
|
||||
const imageFiles = import.meta.glob('$lib/images/senator/*.png');
|
||||
const imagesPromises = [];
|
||||
|
||||
for (const [path, resolver] of Object?.entries(imageFiles)) {
|
||||
const imageNameMatch = path.match(/\/([^/]+)\.png$/);
|
||||
if (imageNameMatch && imageNameMatch[1] !== 'default-avatar') {
|
||||
imagesPromises?.push(resolver()?.then(module => {
|
||||
images[imageNameMatch[1]] = module.default;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
await Promise?.all(imagesPromises);
|
||||
}
|
||||
|
||||
|
||||
let fullName;
|
||||
|
||||
onMount(async () => {
|
||||
isLoaded = false;
|
||||
await loadImages();
|
||||
|
||||
rawData?.forEach(item => {
|
||||
let representative = item?.representative || '';
|
||||
|
||||
representative = representative?.replace('Jr', '')
|
||||
.replace(/Dr./g, '')
|
||||
.replace(/Dr_/g, '')
|
||||
|
||||
const fullName = representative?.replace(/(\s(?:Dr\s)?\w(?:\.|(?=\s)))?\s/g, '_').trim();
|
||||
item.image = images[fullName] || defaultAvatar;
|
||||
item.representative = fullName?.replace(/_/g, ' ');
|
||||
});
|
||||
|
||||
rawData = rawData?.map(item => {
|
||||
const party = getPartyForPoliticians(item?.representative);
|
||||
return {
|
||||
...item,
|
||||
party: party
|
||||
};
|
||||
});
|
||||
rawData.forEach(item => {
|
||||
const representative = item?.representative || '';
|
||||
const fullName = representative.replace(/(\s(?:Dr\s)?\w(?:\.|(?=\s)))?\s/g, '_').trim();
|
||||
item.representative = fullName.replace(/_/g, ' ');
|
||||
});
|
||||
|
||||
// Count the occurrences of "Republican" and "Democrat"
|
||||
const partyCounts = rawData?.reduce((counts, item) => {
|
||||
counts[item?.party] = (counts[item?.party] || 0) + 1;
|
||||
return counts;
|
||||
}, {});
|
||||
rawData = rawData?.map(item => {
|
||||
const party = getPartyForPoliticians(item?.representative);
|
||||
return {
|
||||
...item,
|
||||
party: party
|
||||
};
|
||||
});
|
||||
|
||||
const typeCounts = rawData?.reduce((counts, item) => {
|
||||
counts[item?.type] = (counts[item?.type ] || 0) + 1;
|
||||
return counts;
|
||||
}, {});
|
||||
// Count the occurrences of "Republican" and "Democrat"
|
||||
const partyCounts = rawData.reduce((counts, item) => {
|
||||
counts[item?.party] = (counts[item?.party] || 0) + 1;
|
||||
return counts;
|
||||
}, {});
|
||||
|
||||
partyRatio = partyCounts['Democratic'] > 0 && partyCounts['Republican'] === undefined ? 1 : partyCounts['Democratic'] === undefined ? 0 : partyCounts["Democratic"]/partyCounts["Republican"];
|
||||
buySellRatio = typeCounts['Bought']/typeCounts['Sold'];
|
||||
const typeCounts = rawData.reduce((counts, item) => {
|
||||
counts[item?.type] = (counts[item?.type ] || 0) + 1;
|
||||
return counts;
|
||||
}, {});
|
||||
|
||||
senateTradingList = rawData?.slice(0,20) ?? [];
|
||||
partyRatio = partyCounts['Democratic'] > 0 && partyCounts['Republican'] === undefined ? 1 : partyCounts['Democratic'] === undefined ? 0 : partyCounts["Democratic"] / partyCounts["Republican"];
|
||||
buySellRatio = typeCounts['Bought'] > 0 && typeCounts['Sold'] === undefined ? 1 : typeCounts['Bought'] === undefined ? 0 : typeCounts["Bought"] / typeCounts["Sold"];
|
||||
|
||||
senateTradingList = rawData.slice(0, 20) ?? [];
|
||||
|
||||
isLoaded = true;
|
||||
isLoaded = true;
|
||||
});
|
||||
</script>
|
||||
|
||||
@ -179,14 +136,14 @@ isLoaded = true;
|
||||
|
||||
|
||||
|
||||
<section class="bg-[#09090B] overflow-hidden text-white h-full mb-40 sm:mb-0">
|
||||
<div class="flex justify-center w-fit m-auto h-full overflow-hidden">
|
||||
<div class="relative flex justify-center items-center overflow-hidden">
|
||||
<div class="sm:p-7 w-full m-auto mt-5 sm:mt-0">
|
||||
<div class="mb-6">
|
||||
<h1 class="text-2xl sm:text-3xl text-gray-200 font-bold mb-4">
|
||||
Congress Trading
|
||||
</h1>
|
||||
<section class="w-full bg-[#09090B] overflow-hidden text-white h-full mb-40 sm:mb-0">
|
||||
<div class="h-full overflow-hidden">
|
||||
<div class="relative flex justify-center items-center overflow-hidden">
|
||||
<div class="sm:p-7 w-full mt-2 sm:mt-0">
|
||||
<div class="mb-6">
|
||||
<h1 class="text-2xl sm:text-3xl text-gray-200 font-bold mb-4">
|
||||
Congress Trading
|
||||
</h1>
|
||||
|
||||
|
||||
<div class="text-white p-3 sm:p-5 mb-10 rounded-lg sm:flex sm:flex-row sm:items-center border border-slate-800 text-sm sm:text-[1rem]">
|
||||
@ -213,7 +170,7 @@ isLoaded = true;
|
||||
<!--Start Buy/Sell-->
|
||||
<div class="flex flex-row items-center flex-wrap w-full px-3 sm:px-4 bg-[#262626] shadow-lg rounded-2xl h-20">
|
||||
<div class="flex flex-col items-start">
|
||||
<span class="font-semibold text-gray-200 text-sm sm:text-[1rem] ">Buy/Sell</span>
|
||||
<span class="font-semibold text-gray-200 text-sm sm:text-[1rem]">Buy/Sell</span>
|
||||
<span class="text-start text-sm sm:text-[1rem] font-medium text-white">
|
||||
{buySellRatio?.toFixed(3)}
|
||||
</span>
|
||||
@ -230,7 +187,7 @@ isLoaded = true;
|
||||
</svg>
|
||||
<!-- Percentage Text -->
|
||||
<div class="absolute top-1/2 start-1/2 transform -translate-y-1/2 -translate-x-1/2">
|
||||
<span class="text-center text-white text-sm">{buySellRatio?.toFixed(2)}</span>
|
||||
<span class="text-center text-white text-sm sm:text-[1rem]">{buySellRatio?.toFixed(2)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Circular Progress -->
|
||||
@ -240,7 +197,7 @@ isLoaded = true;
|
||||
<!--Start Dem/Rep-->
|
||||
<div class="flex flex-row items-center flex-wrap w-full px-3 sm:px-4 bg-[#262626] shadow-lg rounded-2xl h-20">
|
||||
<div class="flex flex-col items-start">
|
||||
<span class="font-semibold text-gray-200 text-sm sm:text-[rem] ">Dem/Rep</span>
|
||||
<span class="font-semibold text-gray-200 text-sm sm:text-[1rem]">Dem/Rep</span>
|
||||
<span class="text-start text-sm sm:text-[1rem] font-medium text-white">
|
||||
{partyRatio?.toFixed(3)}
|
||||
</span>
|
||||
@ -257,7 +214,7 @@ isLoaded = true;
|
||||
</svg>
|
||||
<!-- Percentage Text -->
|
||||
<div class="absolute top-1/2 start-1/2 transform -translate-y-1/2 -translate-x-1/2">
|
||||
<span class="text-center text-white text-sm">{partyRatio?.toFixed(2)}</span>
|
||||
<span class="text-center text-white text-sm sm:text-[1rem]">{partyRatio?.toFixed(2)}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- End Circular Progress -->
|
||||
@ -269,7 +226,7 @@ isLoaded = true;
|
||||
<!--End Widget-->
|
||||
|
||||
|
||||
<label on:click={changeStructure} class="sm:hidden w-24 sm:ml-3 mr-2 sm:mr-0 cursor-pointer bg-[#18181B] sm:hover:bg-[#09090B] duration-100 transition ease-in-out px-4 py-2 rounded-lg shadow-md">
|
||||
<label on:click={changeStructure} class="sm:hidden w-24 sm:ml-3 mr-2 sm:mr-0 cursor-pointer bg-[#27272A] px-4 py-2 rounded-lg shadow-md">
|
||||
<span class="m-auto mr-0.5 text-white text-sm">
|
||||
Switch To: {displayStructure}
|
||||
</span>
|
||||
@ -277,17 +234,17 @@ isLoaded = true;
|
||||
|
||||
|
||||
{#if displayStructure === 'Card'}
|
||||
<div class="mt-6 flex justify-start items-center w-full m-auto rounded-none sm:rounded-lg mb-4">
|
||||
<div class="mt-6 flex justify-start items-center w-full m-auto rounded-none sm:rounded-lg mb-4 overflow-x-scroll">
|
||||
<table class="table table-sm sm:table-md table-compact rounded-none sm:rounded-md w-full bg-[#09090B] border-bg-[#09090B] m-auto">
|
||||
<thead>
|
||||
<tr class="bg-[#09090B]">
|
||||
<th class="shadow-md text-start bg-[#09090B] text-white text-sm font-semibold">
|
||||
Person
|
||||
</th>
|
||||
<th class="shadow-md text-end bg-[#09090B] hidden sm:table-cell text-white text-sm font-semibold">
|
||||
<th class="shadow-md text-end bg-[#09090B] text-white text-sm font-semibold">
|
||||
Transaction Date
|
||||
</th>
|
||||
<th class="shadow-md text-end bg-[#09090B] text-white text-sm font-semibold">
|
||||
<th class="shadow-md text-end bg-[#09090B] text-white text-sm font-semibold">
|
||||
Amount
|
||||
</th>
|
||||
<th class="shadow-md text-white font-semibold text-end text-sm">Type</th>
|
||||
@ -297,27 +254,28 @@ isLoaded = true;
|
||||
{#each senateTradingList as item}
|
||||
<tr on:click={() => goto(`/politicians/${item?.id}`)} class="odd:bg-[#27272A] sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] bg-[#09090B] border-b-[#09090B] cursor-pointer">
|
||||
|
||||
<td class="text-gray-200 pb-3 border-b border-b-[#09090B]">
|
||||
<td class="text-white text-sm sm:text-[1rem] whitespace-nowrap pb-3 border-b border-b-[#09090B]">
|
||||
<div class="flex flex-row items-center">
|
||||
<div class="flex-shrink-0 rounded-full border border-slate-700 w-10 h-10 sm:w-12 sm:h-12 relative {item?.party === 'Republican' ? 'bg-[#98272B]' : item?.party === 'Democratic' ? 'bg-[#295AC7]' : 'bg-[#4E2153]'} flex items-center justify-center">
|
||||
<img style="clip-path: circle(50%);" class="avatar rounded-full w-7 sm:w-9" src={item?.image} loading="lazy"/>
|
||||
|
||||
<img style="clip-path: circle(50%);" class="avatar rounded-full w-7 sm:w-9" src={`${cloudFrontUrl}/assets/senator/${item?.representative?.replace(/\s+/g, "_")}.png`} loading="lazy"/>
|
||||
</div>
|
||||
<div class="flex flex-col ml-3">
|
||||
<span class="text-white">{item?.representative?.replace('_',' ')}</span>
|
||||
<span class="text-white text-opacity-60">{item?.party}</span>
|
||||
<span class="">{item?.representative?.replace('_',' ')}</span>
|
||||
<span class="">{item?.party}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!--{item?.firstName} {item?.lastName}-->
|
||||
</td>
|
||||
|
||||
<td class="text-end hidden sm:table-cell text-xs sm:text-sm text-white border-b border-b-[#09090B]">
|
||||
<td class="text-end text-sm sm:text-[1rem] whitespace-nowrap text-white border-b border-b-[#09090B]">
|
||||
{new Date(item?.transactionDate)?.toLocaleString('en-US', { month: 'short', day: 'numeric', year: 'numeric', daySuffix: '2-digit' })}
|
||||
</td>
|
||||
|
||||
<td class="text-end text-xs sm:text-sm text-white border-b border-b-[#09090B]">
|
||||
<td class="text-end text-sm sm:text-[1rem] whitespace-nowrap text-white border-b border-b-[#09090B]">
|
||||
{item?.amount}
|
||||
</td>
|
||||
<td class="text-start text-end text-sm text-white border-b border-b-[#09090B]">
|
||||
<td class="text-end text-sm sm:text-[1rem] whitespace-nowrap text-white border-b border-b-[#09090B]">
|
||||
{#if item?.type === 'Bought'}
|
||||
<span class="text-[#10DB06]">Bought</span>
|
||||
{:else if item?.type === 'Sold'}
|
||||
@ -328,11 +286,14 @@ isLoaded = true;
|
||||
</td>
|
||||
</tr>
|
||||
{/each}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<InfiniteLoading on:infinite={infiniteHandler} />
|
||||
<InfiniteLoading on:infinite={infiniteHandler} />
|
||||
|
||||
{:else}
|
||||
<div class="relative w-full mt-10">
|
||||
@ -350,7 +311,7 @@ isLoaded = true;
|
||||
|
||||
|
||||
<div class="-mt-3 shadow-lg rounded-full border border-slate-600 w-20 h-20 relative {item?.party === 'Republican' ? 'bg-[#98272B]' : item?.party === 'Democratic' ? 'bg-[#295AC7]' : 'bg-[#20202E]'} flex items-center justify-center">
|
||||
<img style="clip-path: circle(50%);" class="rounded-full w-16" src={item?.image} loading="lazy"/>
|
||||
<img style="clip-path: circle(50%);" class="rounded-full w-16" src={`${cloudFrontUrl}/assets/senator/${item?.representative?.replace(/\s+/g, "_")}.png`} loading="lazy"/>
|
||||
</div>
|
||||
<span class="text-white text-lg font-medium mt-2 mb-2">
|
||||
{item?.representative?.replace('_',' ')}
|
||||
|
||||
@ -23,7 +23,7 @@
|
||||
let filterList = [];
|
||||
|
||||
let changeRuleFilter = false;
|
||||
|
||||
|
||||
|
||||
async function handleScroll() {
|
||||
const scrollThreshold = document.body.offsetHeight * 0.8; // 80% of the website height
|
||||
@ -143,19 +143,7 @@ onMount(async () => {
|
||||
}
|
||||
|
||||
|
||||
let charNumber = 40;
|
||||
$: {
|
||||
if ($screenWidth < 640)
|
||||
{
|
||||
charNumber = 20;
|
||||
}
|
||||
else {
|
||||
charNumber = 40;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
$: {
|
||||
if(filterList && changeRuleFilter === true)
|
||||
@ -180,7 +168,6 @@ onMount(async () => {
|
||||
<!-- Other meta tags -->
|
||||
<meta property="og:title" content="US Politician Stock Trade Tracker · stocknear"/>
|
||||
<meta property="og:description" content="What are US Politicians trading? Filter by Senate or House, Party, Committee, State and more - get detailed infomation about it.">
|
||||
<meta property="og:image" content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"/>
|
||||
<meta property="og:type" content="website"/>
|
||||
<!-- Add more Open Graph meta tags as needed -->
|
||||
|
||||
@ -188,7 +175,6 @@ onMount(async () => {
|
||||
<meta name="twitter:card" content="summary_large_image"/>
|
||||
<meta name="twitter:title" content="US Politician Stock Trade Tracker · stocknear"/>
|
||||
<meta name="twitter:description" content="What are US Politicians trading? Filter by Senate or House, Party, Committee, State and more - get detailed infomation about it.">
|
||||
<meta name="twitter:image" content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"/>
|
||||
<!-- Add more Twitter meta tags as needed -->
|
||||
</svelte:head>
|
||||
|
||||
@ -267,7 +253,7 @@ onMount(async () => {
|
||||
|
||||
|
||||
<div class="-mt-3 shadow-lg rounded-full border border-slate-600 w-20 h-20 relative {item?.party === 'Republican' ? 'republican-striped bg-[#98272B]' : item?.party === 'Democratic' ? 'democratic-striped bg-[#295AC7]' : 'other-striped bg-[#20202E]'} flex items-center justify-center">
|
||||
<img style="clip-path: circle(50%);" class="rounded-full w-16" src={item?.image} loading="lazy"/>
|
||||
<img style="clip-path: circle(50%);" class="rounded-full w-16" src={`${cloudFrontUrl}/assets/senator/${item?.representative?.replace(/\s+/g, "_")}.png`} loading="lazy"/>
|
||||
</div>
|
||||
<span class="text-white text-lg font-medium mt-2 mb-2">
|
||||
{item?.representative}
|
||||
|
||||
@ -1,27 +1,8 @@
|
||||
import { getCache, setCache } from '$lib/store';
|
||||
import defaultAvatar from '$lib/images/senator/default-avatar.png';
|
||||
import { getPartyForPoliticians } from '$lib/utils';
|
||||
|
||||
|
||||
|
||||
let images = {};
|
||||
// Function to load images only when they are viewed
|
||||
async function loadImages() {
|
||||
const imageFiles = import.meta.glob('$lib/images/senator/*.png');
|
||||
const imagesPromises = [];
|
||||
|
||||
for (const [path, resolver] of Object?.entries(imageFiles)) {
|
||||
const imageNameMatch = path.match(/\/([^/]+)\.png$/);
|
||||
if (imageNameMatch && imageNameMatch[1] !== 'default-avatar') {
|
||||
imagesPromises?.push(resolver()?.then(module => {
|
||||
images[imageNameMatch[1]] = module.default;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(imagesPromises);
|
||||
}
|
||||
|
||||
|
||||
export const load = async ({parent}) => {
|
||||
const getAllPolitician = async () => {
|
||||
@ -47,7 +28,6 @@ export const load = async ({parent}) => {
|
||||
|
||||
// Cache the data for this specific tickerID with a specific name 'getAllPolitician'
|
||||
|
||||
await loadImages();
|
||||
output?.forEach(item => {
|
||||
let representative = item?.representative || '';
|
||||
|
||||
@ -56,7 +36,6 @@ export const load = async ({parent}) => {
|
||||
.replace(/Dr_/g, '')
|
||||
|
||||
const fullName = representative?.replace(/(\s(?:Dr\s)?\w(?:\.|(?=\s)))?\s/g, '_').trim();
|
||||
item.image = images[fullName] || defaultAvatar;
|
||||
item.representative = fullName?.replace(/_/g, ' ');
|
||||
});
|
||||
|
||||
@ -73,9 +52,6 @@ export const load = async ({parent}) => {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
|
||||
@ -17,6 +17,9 @@ use([BarChart, GridComponent, CanvasRenderer])
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
export let data;
|
||||
let cloudFrontUrl = import.meta.env.VITE_IMAGE_URL;
|
||||
|
||||
|
||||
let isLoaded = false;
|
||||
let rawData = data?.getPolitician?.output;
|
||||
let displayList = [];
|
||||
@ -188,7 +191,6 @@ use([BarChart, GridComponent, CanvasRenderer])
|
||||
}
|
||||
|
||||
onMount(async () => {
|
||||
isLoaded = false;
|
||||
optionsData = await getPlotOptions();
|
||||
|
||||
const typeCounts = rawData?.reduce((counts, item) => {
|
||||
@ -207,17 +209,6 @@ use([BarChart, GridComponent, CanvasRenderer])
|
||||
|
||||
|
||||
|
||||
let charNumber = 40;
|
||||
$: {
|
||||
if ($screenWidth < 640)
|
||||
{
|
||||
charNumber = 15;
|
||||
}
|
||||
else {
|
||||
charNumber = 40;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
@ -278,7 +269,7 @@ use([BarChart, GridComponent, CanvasRenderer])
|
||||
|
||||
|
||||
<div class="mt-10 rounded-full border border-slate-600 w-24 h-24 relative {politicianParty === 'Republican' ? 'republican-striped bg-[#98272B]' : politicianParty === 'Democratic' ? 'democratic-striped bg-[#295AC7]' : 'other-striped bg-[#20202E]'} flex items-center justify-center">
|
||||
<img style="clip-path: circle(50%);" class="rounded-full w-20" src={politicianImage} loading="lazy"/>
|
||||
<img style="clip-path: circle(50%);" class="rounded-full w-20" src={`${cloudFrontUrl}/assets/senator/${name?.replace(/\s+/g, "_")}.png`} loading="lazy"/>
|
||||
</div>
|
||||
<span class="text-white text-lg sm:text-xl font-medium mt-6 mb-2">
|
||||
{name?.replace('Dr','')}
|
||||
|
||||
@ -3,27 +3,11 @@ import defaultAvatar from '$lib/images/senator/default-avatar.png';
|
||||
import { getPartyForPoliticians } from '$lib/utils';
|
||||
|
||||
|
||||
let images = {};
|
||||
let politicianImage;
|
||||
let politicianDistrict;
|
||||
let politicianCongress;
|
||||
let politicianParty = 'n/a';
|
||||
// Function to load images only when they are viewed
|
||||
async function loadImages() {
|
||||
const imageFiles = import.meta.glob('$lib/images/senator/*.png');
|
||||
const imagesPromises = [];
|
||||
|
||||
for (const [path, resolver] of Object?.entries(imageFiles)) {
|
||||
const imageNameMatch = path.match(/\/([^/]+)\.png$/);
|
||||
if (imageNameMatch && imageNameMatch[1] !== 'default-avatar') {
|
||||
imagesPromises?.push(resolver()?.then(module => {
|
||||
images[imageNameMatch[1]] = module.default;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
await Promise?.all(imagesPromises);
|
||||
}
|
||||
|
||||
|
||||
export const load = async ({parent, params}) => {
|
||||
@ -48,7 +32,6 @@ export const load = async ({parent, params}) => {
|
||||
});
|
||||
|
||||
const output = await response.json();
|
||||
await loadImages();
|
||||
|
||||
// Cache the data for this specific tickerID with a specific name 'getPolitician'
|
||||
|
||||
@ -61,19 +44,17 @@ export const load = async ({parent, params}) => {
|
||||
?.replace(/Dr_/g, '');
|
||||
|
||||
const fullName = representative?.replace(/(\s(?:Dr\s)?\w(?:\.|(?=\s)))?\s/g, '_')?.trim();
|
||||
firstItem.image = images[fullName] || defaultAvatar;
|
||||
firstItem.representative = fullName?.replace(/_/g, ' ');
|
||||
|
||||
const party = getPartyForPoliticians(firstItem?.representative);
|
||||
firstItem.party = party;
|
||||
|
||||
politicianImage = firstItem?.image;
|
||||
politicianParty = firstItem?.party;
|
||||
politicianDistrict = firstItem?.district;
|
||||
politicianCongress = firstItem?.congress;
|
||||
}
|
||||
|
||||
res = {output, politicianImage, politicianParty, politicianDistrict, politicianCongress};
|
||||
res = {output, politicianParty, politicianDistrict, politicianCongress};
|
||||
setCache(params.slug, res, 'getPolitician');
|
||||
}
|
||||
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
import { getPartyForPoliticians } from '$lib/utils';
|
||||
import { stockTicker, etfTicker, cryptoTicker, screenWidth, numberOfUnreadNotification } from '$lib/store';
|
||||
import { onMount } from 'svelte';
|
||||
import defaultAvatar from '$lib/images/senator/default-avatar.png';
|
||||
import defaultLogo from '$lib/images/stocks/logo/default_logo.png';
|
||||
import UpgradeToPro from '$lib/components/UpgradeToPro.svelte';
|
||||
// import * as XLSX from 'xlsx';
|
||||
@ -21,7 +20,7 @@
|
||||
let rawData = data?.getPoliticianRSS;
|
||||
let slicedRawData = [];
|
||||
let displayList = [];
|
||||
let images = {};
|
||||
|
||||
let isLoaded = false;
|
||||
let displayStructure = 'Table';
|
||||
let displayRows = 100;
|
||||
@ -57,23 +56,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Function to load images only when they are viewed
|
||||
async function loadImages() {
|
||||
const imageFiles = import.meta.glob('$lib/images/senator/*.png');
|
||||
const imagesPromises = [];
|
||||
|
||||
for (const [path, resolver] of Object?.entries(imageFiles)) {
|
||||
const imageNameMatch = path.match(/\/([^/]+)\.png$/);
|
||||
if (imageNameMatch && imageNameMatch[1] !== 'default-avatar') {
|
||||
imagesPromises?.push(resolver()?.then(module => {
|
||||
images[imageNameMatch[1]] = module.default;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(imagesPromises);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -101,7 +84,6 @@
|
||||
|
||||
|
||||
onMount(async () => {
|
||||
await loadImages();
|
||||
rawData?.forEach(item => {
|
||||
let representative = item?.representative || '';
|
||||
|
||||
@ -110,7 +92,6 @@
|
||||
.replace(/Dr_/g, '')
|
||||
|
||||
const fullName = representative?.replace(/(\s(?:Dr\s)?\w(?:\.|(?=\s)))?\s/g, '_').trim();
|
||||
item.image = images[fullName] || defaultAvatar;
|
||||
item.representative = fullName?.replace(/_/g, ' ');
|
||||
});
|
||||
|
||||
@ -513,7 +494,7 @@
|
||||
|
||||
|
||||
<div class="-mt-3 shadow-lg rounded-full border border-slate-600 w-20 h-20 relative {item?.party === 'Republican' ? 'republican-striped bg-[#98272B]' : item?.party === 'Democratic' ? 'democratic-striped bg-[#295AC7]' : 'bg-[#20202E]'} flex items-center justify-center">
|
||||
<img style="clip-path: circle(50%);" class="rounded-full w-16" src={item?.image} loading="lazy"/>
|
||||
<img style="clip-path: circle(50%);" class="rounded-full w-16" src={`${cloudFrontUrl}/assets/senator/${item?.representative?.replace(/\s+/g, "_")}.png`} loading="lazy"/>
|
||||
</div>
|
||||
<span class="text-white text-lg font-medium mt-2 mb-2">
|
||||
{item?.representative?.replace('Dr','')}
|
||||
@ -620,7 +601,7 @@
|
||||
<th class="{index % 2 ? 'bg-[#09090B]' : 'bg-[#27272A]'} text-white text-sm sm:text-[1rem] whitespace-nowrap">
|
||||
<div class="flex flex-row items-center">
|
||||
<div class="flex-shrink-0 rounded-full border border-slate-700 w-9 h-9 relative {item?.party === 'Republican' ? 'bg-[#98272B]' : item?.party === 'Democratic' ? 'bg-[#295AC7]' : 'bg-[#4E2153]'} flex items-center justify-center">
|
||||
<img style="clip-path: circle(50%);" class="rounded-full w-7" src={item?.image} loading="lazy"/>
|
||||
<img style="clip-path: circle(50%);" class="rounded-full w-7" src={`${cloudFrontUrl}/assets/senator/${item?.representative?.replace(/\s+/g, "_")}.png`} loading="lazy"/>
|
||||
</div>
|
||||
<div class="flex flex-col ml-3 font-normal">
|
||||
<span class="text-white">{getAbbreviatedName(item?.representative?.replace('_',' '))}</span>
|
||||
|
||||
@ -1,28 +1,8 @@
|
||||
import { getCache, setCache } from '$lib/store';
|
||||
import defaultAvatar from '$lib/images/senator/default-avatar.png';
|
||||
import { getPartyForPoliticians } from '$lib/utils';
|
||||
|
||||
|
||||
|
||||
let images = {};
|
||||
// Function to load images only when they are viewed
|
||||
async function loadImages() {
|
||||
const imageFiles = import.meta.glob('$lib/images/senator/*.png');
|
||||
const imagesPromises = [];
|
||||
|
||||
for (const [path, resolver] of Object?.entries(imageFiles)) {
|
||||
const imageNameMatch = path?.match(/\/([^/]+)\.png$/);
|
||||
if (imageNameMatch && imageNameMatch[1] !== 'default-avatar') {
|
||||
imagesPromises?.push(resolver()?.then(module => {
|
||||
images[imageNameMatch[1]] = module.default;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
await Promise?.all(imagesPromises);
|
||||
}
|
||||
|
||||
|
||||
export const load = async ({parent}) => {
|
||||
const getPoliticianRSS = async () => {
|
||||
let output;
|
||||
@ -46,7 +26,6 @@ export const load = async ({parent}) => {
|
||||
|
||||
// Cache the data for this specific tickerID with a specific name 'getPoliticianRSS'
|
||||
|
||||
await loadImages();
|
||||
output?.forEach(item => {
|
||||
let representative = item?.representative || '';
|
||||
|
||||
@ -55,7 +34,6 @@ export const load = async ({parent}) => {
|
||||
.replace(/Dr_/g, '')
|
||||
|
||||
const fullName = representative?.replace(/(\s(?:Dr\s)?\w(?:\.|(?=\s)))?\s/g, '_').trim();
|
||||
item.image = images[fullName] || defaultAvatar;
|
||||
item.representative = fullName?.replace(/_/g, ' ');
|
||||
});
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { displayCompanyName, numberOfUnreadNotification, stockTicker } from '$lib/store';
|
||||
import defaultAvatar from '$lib/images/senator/default-avatar.png';
|
||||
import republicanBackground from "$lib/images/bg-republican.png";
|
||||
import democraticBackground from "$lib/images/bg-democratic.png";
|
||||
import otherBackground from "$lib/images/bg-other.png";
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user