add industry page v1
This commit is contained in:
parent
d1a9114da4
commit
d4b574c019
@ -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>
|
||||
|
||||
@ -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)}
|
||||
|
||||
@ -69,6 +69,8 @@ function sectorSelector(sector) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
$: charNumber = $screenWidth < 640 ? 20 : 30;
|
||||
|
||||
</script>
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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">
|
||||
|
||||
|
||||
|
||||
125
src/routes/list/industry/[slug]/+page.svelte
Normal file
125
src/routes/list/industry/[slug]/+page.svelte
Normal 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>
|
||||
|
||||
|
||||
|
||||
|
||||
38
src/routes/list/industry/[slug]/+page.ts
Normal file
38
src/routes/list/industry/[slug]/+page.ts
Normal 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(),
|
||||
};
|
||||
};
|
||||
Loading…
x
Reference in New Issue
Block a user