company page displays main companies
This commit is contained in:
parent
468f7184e4
commit
b3ad1df5eb
6 changed files with 90 additions and 6 deletions
|
@ -4,6 +4,9 @@ import numpy as np
|
|||
from scraper.top100_extractor import programming_crime_list
|
||||
COMPANIES_CSV_PATH: str = 'scraper/companies.csv'
|
||||
|
||||
def non_nan(a: list[any]) -> list[any]:
|
||||
return list(filter(lambda a: type(a) == str or not np.isnan(a), a))
|
||||
|
||||
|
||||
def get_companies(root_dir: str) -> list[dict]:
|
||||
"""
|
||||
|
@ -13,4 +16,9 @@ def get_companies(root_dir: str) -> list[dict]:
|
|||
df = pd.read_csv(os.path.join(root_dir, COMPANIES_CSV_PATH), index_col='ticker')
|
||||
tickers = pd.Series(programming_crime_list)
|
||||
df = df.loc[df.index.isin(tickers), :]
|
||||
df['tags'] = df[['tag 1', 'tag 2', 'tag 3']].values.tolist()
|
||||
df['tags'] = df['tags'].apply(non_nan)
|
||||
del df['tag 1']
|
||||
del df['tag 2']
|
||||
del df['tag 3']
|
||||
return df.reset_index().replace({ np.nan: None }).to_dict('records')
|
|
@ -14,7 +14,7 @@
|
|||
"roboto-fontface": "*",
|
||||
"vue": "^3.2.0",
|
||||
"vue-router": "^4.0.0",
|
||||
"vuetify": "^3.0.0",
|
||||
"vuetify": "^3.2.3",
|
||||
"webfontloader": "^1.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
19
stockingly-frontend/src/api/index.ts
Normal file
19
stockingly-frontend/src/api/index.ts
Normal file
|
@ -0,0 +1,19 @@
|
|||
const BACKEND_URL = "http://localhost:5000";
|
||||
|
||||
export interface Company {
|
||||
ceo: string;
|
||||
"company name": string;
|
||||
description: string;
|
||||
exchange: string;
|
||||
industry: string;
|
||||
logo: string;
|
||||
"market cap": number;
|
||||
sector: string;
|
||||
"short name": string;
|
||||
tags: string[];
|
||||
ticker: string;
|
||||
website: string;
|
||||
}
|
||||
|
||||
export const getCompanies = (): Promise<Company[]> =>
|
||||
fetch(BACKEND_URL + '/companies').then(r => r.json())
|
|
@ -10,9 +10,13 @@ import 'vuetify/styles'
|
|||
|
||||
// Composables
|
||||
import { createVuetify } from 'vuetify'
|
||||
import { VSkeletonLoader } from 'vuetify/labs/VSkeletonLoader'
|
||||
|
||||
// https://vuetifyjs.com/en/introduction/why-vuetify/#feature-guides
|
||||
export default createVuetify({
|
||||
components: {
|
||||
VSkeletonLoader
|
||||
},
|
||||
theme: {
|
||||
defaultTheme: 'light',
|
||||
themes: {
|
||||
|
|
|
@ -1,6 +1,59 @@
|
|||
<template>
|
||||
<marquee><h1>Viva Luciano Malusa</h1></marquee>
|
||||
<v-container class="fill-height">
|
||||
<v-row>
|
||||
<template v-if="loading" v-for="i in Array.from({ length: 10 }, (_, i) => i)" :key="i">
|
||||
<v-col cols="12" md="6" lg="4">
|
||||
<v-skeleton-loader class="mx-auto" type="card"></v-skeleton-loader>
|
||||
</v-col>
|
||||
</template>
|
||||
<template v-else v-for="company in companies" :key="company.ticker">
|
||||
<v-col cols="12" md="6" lg="4">
|
||||
<v-card class="ma-1 fill-height">
|
||||
<v-card-item>
|
||||
<v-card-title>{{ company['short name'] }}</v-card-title>
|
||||
<v-card-subtitle>{{ company['company name'] }}</v-card-subtitle>
|
||||
</v-card-item>
|
||||
|
||||
<v-card-text>
|
||||
{{ company.description }}
|
||||
</v-card-text>
|
||||
|
||||
<div class="px-4">
|
||||
<v-chip label color="pink" class="ma-1">
|
||||
<v-icon start icon="mdi-chart-timeline-variant"></v-icon>
|
||||
{{ company.ticker }}
|
||||
</v-chip>
|
||||
<v-chip label color="green" class="ma-1">
|
||||
<v-icon start icon="mdi-currency-usd"></v-icon>
|
||||
{{ formatCurrency(company['market cap']) }}
|
||||
</v-chip>
|
||||
<template v-for="tag in company.tags" :key="tag">
|
||||
<v-chip label class="ma-1">{{ tag }}</v-chip>
|
||||
</template>
|
||||
</div>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</template>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { getCompanies, Company } from '@/api';
|
||||
import { ref, reactive } from 'vue';
|
||||
|
||||
const loading = ref(true);
|
||||
const companies = reactive<Company[]>([]);
|
||||
|
||||
getCompanies().then(cs => {
|
||||
loading.value = false;
|
||||
companies.push(...cs);
|
||||
});
|
||||
|
||||
const formatCurrency = (d: number) => {
|
||||
if (d < 1000) return `${d}`;
|
||||
if (d < 1_000_000) return `${Math.round(d / 1000)} K`;
|
||||
if (d < 1_000_000_000) return `${Math.round(d / 1_000_000)} M`
|
||||
return `${Math.round(d / 1_000_000_000)} B`
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1641,10 +1641,10 @@ vue@^3.2.0:
|
|||
"@vue/server-renderer" "3.2.47"
|
||||
"@vue/shared" "3.2.47"
|
||||
|
||||
vuetify@^3.0.0:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/vuetify/-/vuetify-3.2.2.tgz#a4a39bec15e96b4f9f9be6353e19f156abd91c35"
|
||||
integrity sha512-syFfeZVH6dycltqVCx4tDn68fR3r697+Jt7vJW1l3i9a5ClnwpdRBWtE6dt2bjClS2K/VpWYt+rAsLiG7sGU/g==
|
||||
vuetify@^3.2.3:
|
||||
version "3.2.3"
|
||||
resolved "https://registry.yarnpkg.com/vuetify/-/vuetify-3.2.3.tgz#05767c3d88068654b757d33789b8c249f1d38e00"
|
||||
integrity sha512-o7IJm/P5Ttp9ItF1ytQihsLzv4jxIYVfI4Ypkkqc4A7N2MeTmkDOPGbDNUgJ+G1p2upL00LCbc73A9YM8xYVpg==
|
||||
|
||||
webfontloader@^1.0.0:
|
||||
version "1.6.28"
|
||||
|
|
Reference in a new issue