add industry page v1

This commit is contained in:
MuslemRahimi 2024-09-17 15:45:17 +02:00
parent d1a9114da4
commit d4b574c019
7 changed files with 220 additions and 75 deletions

View File

@ -1,7 +1,22 @@
<script lang="ts">
import { abbreviateNumber } from '$lib/utils';
import { goto } from '$app/navigation';
export let charNumber;
export let industryList
function formatFilename(industryName) {
// Replace spaces with hyphens
let formattedName = industryName?.replace(/ /g, '-');
// Replace "&" with "and"
formattedName = formattedName?.replace(/&/g, 'and');
// Remove any extra hyphens (e.g., from consecutive spaces)
formattedName = formattedName?.replace(/-{2,}/g, '-');
// Convert to lowercase for consistency
goto("/list/industry/"+formattedName?.toLowerCase())
}
</script>
@ -23,7 +38,7 @@
<tbody>
{#each industryList as item}
<!-- row -->
<tr class="cursor-pointer sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] odd:bg-[#27272A] border-b-[#09090B]">
<tr on:click={() => formatFilename(item?.industry)} class="cursor-pointer sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] odd:bg-[#27272A] border-b-[#09090B]">
<td class="hover:sm:text-white text-blue-400 font-medium text-sm sm:text-[1rem] whitespace-nowrap border-b-[#09090B]">
{item?.industry?.length > charNumber ? item?.industry?.slice(0,charNumber) + "..." : item?.industry}
</td>

View File

@ -79,20 +79,19 @@ let activeIdx = 0;
<div class="mt-10 sm:mt-5 w-full m-auto mb-10 bg-[#09090B] px-3 lg:px-10 overflow-hidden">
<div class="mt-10 sm:mt-5 w-full m-auto mb-10 bg-[#09090B] lg:px-10 overflow-hidden">
<!--Start Top Winners/Losers-->
<div class="flex flex-col justify-center items-center">
<div class="ml-2 text-start w-full text-white mb-1 text-3xl font-semibold">
<div class="ml-4 sm:ml-2 text-start w-full text-white mb-1 text-2xl sm:text-3xl font-semibold">
Stock Sectors & Industries
</div>
<div class="border-b mt-2 border-blue-400 w-full mb-7" />
<div class="w-full mb-4">
<div class="bg-[#313131] w-fit relative flex flex-wrap items-center justify-center rounded-lg p-1 -mt-3">
<div class="ml-4 sm:ml-0 w-full mb-4">
<div class="bg-[#313131] w-fit relative mr-auto flex flex-wrap items-center justify-center rounded sm:rounded-lg p-1 -mt-3">
{#each tabs as item, i}
<button
on:click={() => handleMode(i)}

View File

@ -69,6 +69,8 @@ function sectorSelector(sector) {
}
}
$: charNumber = $screenWidth < 640 ? 20 : 30;
</script>

View File

@ -6,69 +6,19 @@ import { goto } from '$app/navigation';
export let data;
let rawData = data?.getIndustryOverview;
const sectorNavigation = [
{
title: 'Financial Services',
link: '/list/financial-sector'
},
{
title: 'Finance',
link: '/list/financial-sector'
},
{
title: 'Healthcare',
link: '/list/healthcare-sector'
},
{
title: 'Technology',
link: '/list/technology-sector'
},
{
title: 'Industrials',
link: '/list/industrials-sector'
},
{
title: 'Energy',
link: '/list/energy-sector'
},
{
title: 'Utilities',
link: '/list/utilities-sector'
},
{
title: 'Consumer Cyclical',
link: '/list/consumer-cyclical-sector'
},
{
title: 'Real Estate',
link: '/list/real-estate-sector'
},
{
title: 'Basic Materials',
link: '/list/basic-materials-sector'
},
{
title: 'Communication Services',
link: '/list/communication-services-sector'
},
{
title: 'Consumer Defensive',
link: '/list/consumer-defensive-sector'
},
]
function sectorSelector(sector) {
const selectedSector = sectorNavigation?.find(item => item?.title === sector);
if (selectedSector) {
goto(selectedSector?.link);
} else {
// Handle the case when the sector is not found
console.error(`Sector not found: ${sector}`);
}
function formatFilename(industryName) {
// Replace spaces with hyphens
let formattedName = industryName?.replace(/ /g, '-');
// Replace "&" with "and"
formattedName = formattedName?.replace(/&/g, 'and');
// Remove any extra hyphens (e.g., from consecutive spaces)
formattedName = formattedName?.replace(/-{2,}/g, '-');
// Convert to lowercase for consistency
goto("/list/industry/"+formattedName?.toLowerCase())
}
$: charNumber = $screenWidth < 640 ? 20 : 30;
</script>
@ -102,7 +52,7 @@ $: charNumber = $screenWidth < 640 ? 20 : 30;
<tbody>
{#each rawData as item}
<!-- row -->
<tr on:click={() => sectorSelector(item?.sector)} class="cursor-pointer sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] odd:bg-[#27272A] border-b-[#09090B]">
<tr on:click={() => formatFilename(item?.industry)} class="cursor-pointer sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] odd:bg-[#27272A] border-b-[#09090B]">
<td class="hover:sm:text-white text-blue-400 font-medium text-sm sm:text-[1rem] whitespace-nowrap border-b-[#09090B]">
{item?.industry?.length > charNumber ? item?.industry?.slice(0,charNumber) + "..." : item?.industry}
</td>

View File

@ -1,11 +1,26 @@
<script lang='ts'>
import { numberOfUnreadNotification } from '$lib/store';
import { page } from '$app/stores';
import { industryList } from '$lib/utils';
import ArrowLogo from "lucide-svelte/icons/move-up-right";
import { goto } from '$app/navigation';
export let data;
function formatFilename(industryName) {
let formattedName = industryName?.replace(/ /g, '-')
.replace(/&/g, 'and')
.replace(/-{2,}/g, '-')
.toLowerCase();
return formattedName;
}
let navigationIndustry = industryList.map(industry => ({
title: industry,
link: `/list/industry/${formatFilename(industry)}`
}));
let navigation = [
{
title: 'Stock Lists',
@ -162,6 +177,7 @@ let navigation = [
];
navigation = [...navigationIndustry, ...navigation];
let updatedNavigation = navigation?.map(item => {
return {
...item,
@ -200,12 +216,16 @@ const combinedNavigation = navigation?.concat(updatedNavigation);
<div class="text-sm sm:text-[1rem] breadcrumbs ml-3 lg:ml-10">
<ul>
<li><a href="/" class="text-gray-300">Home</a></li>
{#if $page.url.pathname.startsWith('/list/industry')}
<li><a href="/industry" class="text-gray-300">Industry</a></li>
{:else}
<li><a href="/list/" class="text-gray-300">Lists</a></li>
{/if}
{#if $page.url.pathname.startsWith('/list/')}
<li>
<a class="text-gray-300">
<span class="text-gray-300">
{combinedNavigation?.find((item) => item?.link === $page.url.pathname)?.title}
</a>
</span>
</li>
{/if}
</ul>
@ -213,10 +233,6 @@ const combinedNavigation = navigation?.concat(updatedNavigation);
<div class="mt-10 sm:mt-5 w-full m-auto mb-10 bg-[#09090B] px-3 lg:px-10 overflow-hidden">

View File

@ -0,0 +1,125 @@
<script lang='ts'>
import { goto } from '$app/navigation';
import { screenWidth } from '$lib/store';
import { abbreviateNumber} from '$lib/utils';
import { onMount } from 'svelte';
export let data;
let isLoaded = false;
let rawData = data?.getIndustryStocks;
let stockList = rawData?.slice(0,50);
async function handleScroll() {
const scrollThreshold = document.body.offsetHeight * 0.8; // 80% of the website height
const isBottom = window.innerHeight + window.scrollY >= scrollThreshold;
if (isBottom && stockList?.length !== rawData?.length) {
const nextIndex = stockList?.length;
const filteredNewResults = rawData?.slice(nextIndex, nextIndex + 50);
stockList = [...stockList, ...filteredNewResults];
}
}
onMount(async () => {
isLoaded = true;
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
})
$: charNumber = $screenWidth < 640 ? 15 : 20;
</script>
<section class="w-full overflow-hidden m-auto">
<!-- Page wrapper -->
<div class="flex justify-center w-full m-auto h-full overflow-hidden">
<!-- Content area -->
<div class="w-full overflow-x-scroll">
<table class="table table-sm table-compact no-scrollbar rounded-none sm:rounded-md w-full bg-[#09090B] border-bg-[#09090B] m-auto">
<thead>
<tr class="bg-[#09090B]">
<th class="text-start bg-[#09090B] text-white text-[1rem] font-semibold">
Symbol
</th>
<th class="text-start bg-[#09090B] text-white text-[1rem] font-semibold">
Name
</th>
<th class="text-end bg-[#09090B] text-white text-[1rem] font-semibold">
Market Cap
</th>
<th class="text-end bg-[#09090B] text-white text-[1rem] font-semibold">
% Change
</th>
<th class="text-end bg-[#09090B] text-white text-[1rem] font-semibold">
Volume
</th>
<th class="hidden xl:table-cell text-end bg-[#09090B] text-white text-[1rem] font-semibold">
Revenue
</th>
</tr>
</thead>
<tbody>
{#each stockList as item}
<tr on:click={() => goto(`/stocks/${item?.symbol}`)} class="sm:hover:bg-[#245073] sm:hover:bg-opacity-[0.2] odd:bg-[#27272A] cursor-pointer">
<td class="text-sm sm:text-[1rem] whitespace-nowrap text-start text-blue-400">
{item?.symbol}
</td>
<td class="hidden sm:table-cell text-white text-sm sm:text-[1rem] whitespace-nowrap text-white text-start">
{item?.name?.length > charNumber ? item?.name?.slice(0,charNumber) + "..." : item?.name}
</td>
<td class="text-end text-sm sm:text-[1rem] whitespace-nowrap text-white">
{abbreviateNumber(item?.marketCap)}
</td>
<td class="text-sm sm:text-[1rem] whitespace-nowrap {item?.changesPercentage >= 0 ? 'text-[#10DB06]' : 'text-[#FF2F1F]'} text-end">
{item?.changesPercentage}
</td>
<td class="text-sm sm:text-[1rem] text-white text-end">
{abbreviateNumber(item?.volume)}
</td>
<td class="text-end text-sm sm:text-[1rem] whitespace-nowrap font-medium text-white">
{item?.revenue === 0 ? '-' : abbreviateNumber(item?.revenue)}
</td>
</tr>
{/each}
</tbody>
</table>
</div>
</div>
</section>

View File

@ -0,0 +1,38 @@
import { getCache, setCache } from "$lib/store";
export const load = async ({ parent, params }) => {
const getIndustryStocks = async () => {
let output;
const { apiKey, apiURL } = await parent();
const cachedData = getCache(params.slug, "getIndustryStocks");
if (cachedData) {
output = cachedData;
} else {
const postData = { ticker: params.slug };
const response = await fetch(apiURL + "/industry-stocks", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-KEY": apiKey,
},
body: JSON.stringify(postData),
});
output = await response.json();
setCache(params.slug, output, "getIndustryStocks");
}
//output = user?.tier !== "Pro" ? output?.slice(0, 5) : output;
//output = data?.user?.tier !== 'Pro' ? output?.slice(0,6) : output;
return output;
};
// Make sure to return a promise
return {
getIndustryStocks: await getIndustryStocks(),
};
};