add industry page v1
This commit is contained in:
parent
d1a9114da4
commit
d4b574c019
@ -1,7 +1,22 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { abbreviateNumber } from '$lib/utils';
|
import { abbreviateNumber } from '$lib/utils';
|
||||||
|
import { goto } from '$app/navigation';
|
||||||
export let charNumber;
|
export let charNumber;
|
||||||
export let industryList
|
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>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
@ -23,7 +38,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
{#each industryList as item}
|
{#each industryList as item}
|
||||||
<!-- row -->
|
<!-- 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]">
|
<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}
|
{item?.industry?.length > charNumber ? item?.industry?.slice(0,charNumber) + "..." : item?.industry}
|
||||||
</td>
|
</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-->
|
<!--Start Top Winners/Losers-->
|
||||||
<div class="flex flex-col justify-center items-center">
|
<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
|
Stock Sectors & Industries
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="border-b mt-2 border-blue-400 w-full mb-7" />
|
<div class="border-b mt-2 border-blue-400 w-full mb-7" />
|
||||||
|
<div class="ml-4 sm:ml-0 w-full mb-4">
|
||||||
<div class="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">
|
||||||
<div class="bg-[#313131] w-fit relative flex flex-wrap items-center justify-center rounded-lg p-1 -mt-3">
|
|
||||||
{#each tabs as item, i}
|
{#each tabs as item, i}
|
||||||
<button
|
<button
|
||||||
on:click={() => handleMode(i)}
|
on:click={() => handleMode(i)}
|
||||||
|
|||||||
@ -69,6 +69,8 @@ function sectorSelector(sector) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$: charNumber = $screenWidth < 640 ? 20 : 30;
|
$: charNumber = $screenWidth < 640 ? 20 : 30;
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -6,69 +6,19 @@ import { goto } from '$app/navigation';
|
|||||||
export let data;
|
export let data;
|
||||||
let rawData = data?.getIndustryOverview;
|
let rawData = data?.getIndustryOverview;
|
||||||
|
|
||||||
const sectorNavigation = [
|
function formatFilename(industryName) {
|
||||||
{
|
// Replace spaces with hyphens
|
||||||
title: 'Financial Services',
|
let formattedName = industryName?.replace(/ /g, '-');
|
||||||
link: '/list/financial-sector'
|
// Replace "&" with "and"
|
||||||
},
|
formattedName = formattedName?.replace(/&/g, 'and');
|
||||||
{
|
// Remove any extra hyphens (e.g., from consecutive spaces)
|
||||||
title: 'Finance',
|
formattedName = formattedName?.replace(/-{2,}/g, '-');
|
||||||
link: '/list/financial-sector'
|
// Convert to lowercase for consistency
|
||||||
},
|
goto("/list/industry/"+formattedName?.toLowerCase())
|
||||||
{
|
|
||||||
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}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$: charNumber = $screenWidth < 640 ? 20 : 30;
|
$: charNumber = $screenWidth < 640 ? 20 : 30;
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
@ -102,7 +52,7 @@ $: charNumber = $screenWidth < 640 ? 20 : 30;
|
|||||||
<tbody>
|
<tbody>
|
||||||
{#each rawData as item}
|
{#each rawData as item}
|
||||||
<!-- row -->
|
<!-- 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]">
|
<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}
|
{item?.industry?.length > charNumber ? item?.industry?.slice(0,charNumber) + "..." : item?.industry}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@ -1,11 +1,26 @@
|
|||||||
<script lang='ts'>
|
<script lang='ts'>
|
||||||
import { numberOfUnreadNotification } from '$lib/store';
|
import { numberOfUnreadNotification } from '$lib/store';
|
||||||
import { page } from '$app/stores';
|
import { page } from '$app/stores';
|
||||||
|
import { industryList } from '$lib/utils';
|
||||||
import ArrowLogo from "lucide-svelte/icons/move-up-right";
|
import ArrowLogo from "lucide-svelte/icons/move-up-right";
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
|
|
||||||
export let data;
|
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 = [
|
let navigation = [
|
||||||
{
|
{
|
||||||
title: 'Stock Lists',
|
title: 'Stock Lists',
|
||||||
@ -162,6 +177,7 @@ let navigation = [
|
|||||||
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
navigation = [...navigationIndustry, ...navigation];
|
||||||
let updatedNavigation = navigation?.map(item => {
|
let updatedNavigation = navigation?.map(item => {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@ -200,12 +216,16 @@ const combinedNavigation = navigation?.concat(updatedNavigation);
|
|||||||
<div class="text-sm sm:text-[1rem] breadcrumbs ml-3 lg:ml-10">
|
<div class="text-sm sm:text-[1rem] breadcrumbs ml-3 lg:ml-10">
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="/" class="text-gray-300">Home</a></li>
|
<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>
|
<li><a href="/list/" class="text-gray-300">Lists</a></li>
|
||||||
|
{/if}
|
||||||
{#if $page.url.pathname.startsWith('/list/')}
|
{#if $page.url.pathname.startsWith('/list/')}
|
||||||
<li>
|
<li>
|
||||||
<a class="text-gray-300">
|
<span class="text-gray-300">
|
||||||
{combinedNavigation?.find((item) => item?.link === $page.url.pathname)?.title}
|
{combinedNavigation?.find((item) => item?.link === $page.url.pathname)?.title}
|
||||||
</a>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
{/if}
|
{/if}
|
||||||
</ul>
|
</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">
|
<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