add info text to screener
This commit is contained in:
parent
a4c23e1381
commit
6f91c112dc
@ -0,0 +1,27 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { LinkPreview as HoverCardPrimitive } from "bits-ui";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = HoverCardPrimitive.ContentProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let align: $$Props["align"] = "center";
|
||||||
|
export let sideOffset: $$Props["sideOffset"] = 4;
|
||||||
|
export let transition: $$Props["transition"] = flyAndScale;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = undefined;
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<HoverCardPrimitive.Content
|
||||||
|
{transition}
|
||||||
|
{transitionConfig}
|
||||||
|
{sideOffset}
|
||||||
|
{align}
|
||||||
|
class={cn(
|
||||||
|
"bg-popover text-popover-foreground z-50 w-64 rounded-md border p-4 shadow-md outline-none",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</HoverCardPrimitive.Content>
|
||||||
14
src/lib/components/shadcn/hover-card/index.ts
Normal file
14
src/lib/components/shadcn/hover-card/index.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { LinkPreview as HoverCardPrimitive } from "bits-ui";
|
||||||
|
|
||||||
|
import Content from "./hover-card-content.svelte";
|
||||||
|
const Root = HoverCardPrimitive.Root;
|
||||||
|
const Trigger = HoverCardPrimitive.Trigger;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Content,
|
||||||
|
Trigger,
|
||||||
|
Root as HoverCard,
|
||||||
|
Content as HoverCardContent,
|
||||||
|
Trigger as HoverCardTrigger,
|
||||||
|
};
|
||||||
@ -1,11 +1,12 @@
|
|||||||
<script lang='ts'>
|
<script lang='ts'>
|
||||||
import { onMount, onDestroy } from 'svelte';
|
import { onMount, onDestroy } from 'svelte';
|
||||||
import { goto} from '$app/navigation';
|
import { goto} from '$app/navigation';
|
||||||
import { screenWidth, numberOfUnreadNotification, strategyId} from '$lib/store';
|
import { clearCache, screenWidth, numberOfUnreadNotification, getCache, setCache} from '$lib/store';
|
||||||
import toast from 'svelte-french-toast';
|
import toast from 'svelte-french-toast';
|
||||||
import { abbreviateNumber, sectorList, industryList, listOfRelevantCountries } from '$lib/utils';
|
import { abbreviateNumber, sectorList, industryList, listOfRelevantCountries } from '$lib/utils';
|
||||||
import * as DropdownMenu from "$lib/components/shadcn/dropdown-menu/index.js";
|
import * as DropdownMenu from "$lib/components/shadcn/dropdown-menu/index.js";
|
||||||
import { Button } from "$lib/components/shadcn/button/index.js";
|
import { Button } from "$lib/components/shadcn/button/index.js";
|
||||||
|
import * as HoverCard from "$lib/components/shadcn/hover-card/index.js";
|
||||||
import Input from '$lib/components/Input.svelte';
|
import Input from '$lib/components/Input.svelte';
|
||||||
|
|
||||||
//const userConfirmation = confirm('Unsaved changes detected. Leaving now will discard your strategy. Continue?');
|
//const userConfirmation = confirm('Unsaved changes detected. Leaving now will discard your strategy. Continue?');
|
||||||
@ -20,6 +21,7 @@
|
|||||||
let syncWorker: Worker | undefined;
|
let syncWorker: Worker | undefined;
|
||||||
let downloadWorker: Worker | undefined;
|
let downloadWorker: Worker | undefined;
|
||||||
let searchQuery = '';
|
let searchQuery = '';
|
||||||
|
let infoText = {};
|
||||||
$: testList = [];
|
$: testList = [];
|
||||||
|
|
||||||
|
|
||||||
@ -43,11 +45,11 @@
|
|||||||
const allRules = {
|
const allRules = {
|
||||||
avgVolume: { label: 'Average Volume', step: ['100M','10M','1M','100K','10K','1K','0'], category: 'fund', defaultCondition: 'over', defaultValue: 0 },
|
avgVolume: { label: 'Average Volume', step: ['100M','10M','1M','100K','10K','1K','0'], category: 'fund', defaultCondition: 'over', defaultValue: 0 },
|
||||||
volume: { label: 'Volume', step: ['100M','10M','1M','100K','10K','1K','0'], category: 'fund', defaultCondition: 'over', defaultValue: 0 },
|
volume: { label: 'Volume', step: ['100M','10M','1M','100K','10K','1K','0'], category: 'fund', defaultCondition: 'over', defaultValue: 0 },
|
||||||
rsi: { label: 'RSI', step: [90,80,70,60,50,40,30,20], category: 'ta', defaultCondition: 'over', defaultValue: 40 },
|
rsi: { label: 'Relative Strength Index', step: [90,80,70,60,50,40,30,20], category: 'ta', defaultCondition: 'over', defaultValue: 40 },
|
||||||
stochRSI: { label: 'Stoch RSI Fast', step: [90,80,70,60,50,40,30,20], category: 'ta', defaultCondition: 'over', defaultValue: 40 },
|
stochRSI: { label: 'Stochastic RSI Fast', step: [90,80,70,60,50,40,30,20], category: 'ta', defaultCondition: 'over', defaultValue: 40 },
|
||||||
mfi: { label: 'MFI', step: [90,80,70,60,50,40,30,20], category: 'ta', defaultCondition: 'over', defaultValue: 40 },
|
mfi: { label: 'Money Flow Index', step: [90,80,70,60,50,40,30,20], category: 'ta', defaultCondition: 'over', defaultValue: 40 },
|
||||||
cci: { label: 'CCI', step: [250,200,100,50,20,0,-20,-50,-100,-200,-250], category: 'ta', defaultCondition: 'over', defaultValue: 0 },
|
cci: { label: 'Commodity Channel Index', step: [250,200,100,50,20,0,-20,-50,-100,-200,-250], category: 'ta', defaultCondition: 'over', defaultValue: 0 },
|
||||||
atr: { label: 'ATR', step: [20,15,10,5,3,1], category: 'ta', defaultCondition: 'over', defaultValue: 10 },
|
atr: { label: 'Average True Range', step: [20,15,10,5,3,1], category: 'ta', defaultCondition: 'over', defaultValue: 10 },
|
||||||
sma20: { label: 'SMA20', step: ['Stock Price > SMA20', 'SMA20 > SMA50', 'SMA20 > SMA100', 'SMA20 > SMA200'], category: 'ta', defaultValue: 'any' },
|
sma20: { label: 'SMA20', step: ['Stock Price > SMA20', 'SMA20 > SMA50', 'SMA20 > SMA100', 'SMA20 > SMA200'], category: 'ta', defaultValue: 'any' },
|
||||||
sma50: { label: 'SMA50', step: ['Stock Price > SMA50', 'SMA50 > SMA20', 'SMA50 > SMA100', 'SMA50 > SMA200'], category: 'ta', defaultValue: 'any' },
|
sma50: { label: 'SMA50', step: ['Stock Price > SMA50', 'SMA50 > SMA20', 'SMA50 > SMA100', 'SMA50 > SMA200'], category: 'ta', defaultValue: 'any' },
|
||||||
sma100: { label: 'SMA100', step: ['Stock Price > SMA100', 'SMA100 > SMA20', 'SMA100 > SMA50', 'SMA100 > SMA200'], category: 'ta', defaultValue: 'any' },
|
sma100: { label: 'SMA100', step: ['Stock Price > SMA100', 'SMA100 > SMA20', 'SMA100 > SMA50', 'SMA100 > SMA200'], category: 'ta', defaultValue: 'any' },
|
||||||
@ -210,6 +212,27 @@ $: allRows = Object?.entries(allRules)
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async function getInfoText(parameter) {
|
||||||
|
const cachedData = getCache(parameter, "getInfoText");
|
||||||
|
if (cachedData) {
|
||||||
|
infoText = cachedData;
|
||||||
|
} else {
|
||||||
|
const postData = { parameter };
|
||||||
|
const response = await fetch(data?.apiURL + "/info-text", {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(postData),
|
||||||
|
});
|
||||||
|
|
||||||
|
infoText = await response.json();
|
||||||
|
setCache(parameter, infoText, "getInfoText");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
async function handleCreateStrategy() {
|
async function handleCreateStrategy() {
|
||||||
if(data?.user?.tier === 'Pro' && !data?.user?.freeTrial) {
|
if(data?.user?.tier === 'Pro' && !data?.user?.freeTrial) {
|
||||||
const closePopup = document.getElementById("addStrategy");
|
const closePopup = document.getElementById("addStrategy");
|
||||||
@ -532,6 +555,7 @@ onMount(async () => {
|
|||||||
onDestroy(() => {
|
onDestroy(() => {
|
||||||
syncWorker?.terminate();
|
syncWorker?.terminate();
|
||||||
syncWorker = undefined;
|
syncWorker = undefined;
|
||||||
|
clearCache();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@ -1011,9 +1035,35 @@ function handleInput(event) {
|
|||||||
{#each displayRules as row (row?.rule)}
|
{#each displayRules as row (row?.rule)}
|
||||||
<!--Start Added Rules-->
|
<!--Start Added Rules-->
|
||||||
<div class="flex items-center justify-between space-x-2 px-1 py-1.5 text-smaller leading-tight text-default">
|
<div class="flex items-center justify-between space-x-2 px-1 py-1.5 text-smaller leading-tight text-default">
|
||||||
<div class="text-white text-[1rem]">
|
<div class="text-white text-[1rem] relative">
|
||||||
{row?.label?.replace('[%]', '')}
|
{row?.label?.replace('[%]', '')}
|
||||||
|
<HoverCard.Root>
|
||||||
|
<HoverCard.Trigger
|
||||||
|
class="rounded-sm underline-offset-4 hover:underline focus-visible:outline-2 focus-visible:outline-offset-8 focus-visible:outline-black">
|
||||||
|
<label on:mouseover={() => getInfoText(row?.rule)} class="relative" role="tooltip">
|
||||||
|
<span class="absolute -right-[15px] -top-[3px] cursor-pointer p-1 text-gray-300 sm:hover:text-white">
|
||||||
|
<svg class="h-[10.5px] w-[10.5px]" viewBox="0 0 4 16" fill="currentColor" style="max-width:20px"><path d="M0 6h4v10h-4v-10zm2-6c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2z"></path></svg>
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
</HoverCard.Trigger>
|
||||||
|
<HoverCard.Content class="w-96">
|
||||||
|
<div class="flex justify-between space-x-4 w-full">
|
||||||
|
<div class="space-y-1 w-full">
|
||||||
|
<h4 class="text-lg font-semibold pb-1 border-b border-gray-400 ">{row?.label?.replace('[%]', '')}</h4>
|
||||||
|
<div class="text-sm w-full pt-2 text-black">
|
||||||
|
{infoText?.text ?? 'n/a'}
|
||||||
</div>
|
</div>
|
||||||
|
{#if infoText?.equation !== undefined}
|
||||||
|
<div class="text-sm w-full pt-2 text-black border-t border-gray-400">
|
||||||
|
{infoText?.equation}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</HoverCard.Content>
|
||||||
|
</HoverCard.Root>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<button on:click={() => handleDeleteRule(row?.rule)} class="mr-1.5 cursor-pointer text-gray-300 sm:hover:text-red-500 focus:outline-none" title="Remove filter">
|
<button on:click={() => handleDeleteRule(row?.rule)} class="mr-1.5 cursor-pointer text-gray-300 sm:hover:text-red-500 focus:outline-none" title="Remove filter">
|
||||||
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="CurrentColor" style="max-width:40px">
|
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke="CurrentColor" style="max-width:40px">
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user