mirror of
https://github.com/YouHaveTrouble/youhavetrouble.github.io.git
synced 2026-05-12 06:16:55 +00:00
final fantasy xiv character view
This commit is contained in:
@@ -46,5 +46,6 @@ const { title, description, permalink, current } = Astro.props;
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
container-type: inline-size;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,333 @@
|
|||||||
|
---
|
||||||
|
import BaseLayout from "../../layouts/BaseLayout.astro";
|
||||||
|
|
||||||
|
const title = 'FFXIV';
|
||||||
|
const description = 'My FFXIV character';
|
||||||
|
const permalink = Astro?.site?.href ?? '/gaming/ffxiv';
|
||||||
|
---
|
||||||
|
<BaseLayout title={title} description={description} permalink={permalink}>
|
||||||
|
<div class="character-profile">
|
||||||
|
<div class="portrait">
|
||||||
|
<img src="" alt="Portrait of FFXIV character"/>
|
||||||
|
</div>
|
||||||
|
<div class="description">
|
||||||
|
<div class="info">
|
||||||
|
<span class="name">???</span>
|
||||||
|
<span class="technical">
|
||||||
|
<span class="server">???</span>
|
||||||
|
<span class="datacenter">(???)</span>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<hr style="width:100%; margin: 10px auto;"/>
|
||||||
|
<noscript>Data is fetched live and will not appear with javascript off.</noscript>
|
||||||
|
<div>
|
||||||
|
<span>Disciple of War</span>
|
||||||
|
<div class="jobs">
|
||||||
|
<div class="job" data-job="paladin">
|
||||||
|
<span class="name">Paladin</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="warrior">
|
||||||
|
<span class="name">Warrior</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="dark knight">
|
||||||
|
<span class="name">Dark Knight</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="gunbreaker">
|
||||||
|
<span class="name">Gunbreaker</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="white mage">
|
||||||
|
<span class="name">White mage</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="scholar">
|
||||||
|
<span class="name">Scholar</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="astrologian">
|
||||||
|
<span class="name">Astrologian</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="sage">
|
||||||
|
<span class="name">Sage</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="monk">
|
||||||
|
<span class="name">Monk</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="dragoon">
|
||||||
|
<span class="name">Dragoon</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="ninja">
|
||||||
|
<span class="name">Ninja</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="samurai">
|
||||||
|
<span class="name">Samurai</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="reaper">
|
||||||
|
<span class="name">Reaper</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="viper">
|
||||||
|
<span class="name">Viper</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="bard">
|
||||||
|
<span class="name">Bard</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="machinist">
|
||||||
|
<span class="name">Machinist</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="dancer">
|
||||||
|
<span class="name">Dancer</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="black mage">
|
||||||
|
<span class="name">Black Mage</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="summoner">
|
||||||
|
<span class="name">Summoner</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="red mage">
|
||||||
|
<span class="name">Red Mage</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="pictomancer">
|
||||||
|
<span class="name">Pictomancer</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="blue mage (limited job)">
|
||||||
|
<span class="name">Blue Mage</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<span>Disciple of Land</span>
|
||||||
|
<div class="jobs">
|
||||||
|
<div class="job" data-job="miner">
|
||||||
|
<span class="name">Miner</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="botanist">
|
||||||
|
<span class="name">Botanist</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="fisher">
|
||||||
|
<span class="name">Fisher</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>Disciple of Hand</span>
|
||||||
|
<div class="jobs">
|
||||||
|
<div class="job" data-job="carpenter">
|
||||||
|
<span class="name">Carpenter</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="blacksmith">
|
||||||
|
<span class="name">Blacksmith</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="armorer">
|
||||||
|
<span class="name">Armorer</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="goldsmith">
|
||||||
|
<span class="name">Goldsmith</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="leatherworker">
|
||||||
|
<span class="name">Leatherworker</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="weaver">
|
||||||
|
<span class="name">Weaver</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="alchemist">
|
||||||
|
<span class="name">Alchemist</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
<div class="job" data-job="culinarian">
|
||||||
|
<span class="name">Culinarian</span>
|
||||||
|
<span class="level">??</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</BaseLayout>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
setPlaceholders(loadDataFromLocalStorage())
|
||||||
|
|
||||||
|
const request = await fetch("https://api.youhavetrouble.me/games/ffxiv/").catch(() => null);
|
||||||
|
if (request !== null && request.ok) {
|
||||||
|
const data = await request.json();
|
||||||
|
setPlaceholders(data);
|
||||||
|
saveDataToLocalStorage(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setPlaceholders(data: any) {
|
||||||
|
if (data === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const profilePic = document.querySelector(".character-profile .portrait img") as HTMLImageElement | null;
|
||||||
|
if (profilePic) {
|
||||||
|
profilePic.src = data?.portrait_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nameElem = document.querySelector(".character-profile .description .info .name") as HTMLElement | null;
|
||||||
|
if (nameElem) {
|
||||||
|
nameElem.textContent = data?.name ?? "???";
|
||||||
|
}
|
||||||
|
const serverElem = document.querySelector(".character-profile .description .info .technical .server") as HTMLElement | null;
|
||||||
|
if (serverElem) {
|
||||||
|
serverElem.textContent = data?.server ?? "???";
|
||||||
|
}
|
||||||
|
const datacenterElem = document.querySelector(".character-profile .description .info .technical .datacenter") as HTMLElement | null;
|
||||||
|
if (datacenterElem) {
|
||||||
|
datacenterElem.textContent = `(${data?.datacenter ?? "???"})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const jobs = data?.jobs ?? [];
|
||||||
|
if (Array.isArray(jobs)) {
|
||||||
|
jobs.forEach((job: {name: string, level: number}) => {
|
||||||
|
const name = job.name.toLowerCase().split(" / ")[0];
|
||||||
|
const jobElem = document.querySelector(`.character-profile .description .jobs .job[data-job="${name}"]`);
|
||||||
|
if (jobElem) {
|
||||||
|
const levelElem = jobElem.querySelector(".level") as HTMLElement | null;
|
||||||
|
if (levelElem) {
|
||||||
|
levelElem.textContent = job.level.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveDataToLocalStorage(data: any) {
|
||||||
|
try {
|
||||||
|
localStorage.setItem('ffxivCharacterData', JSON.stringify(data));
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error saving FFXIV character data to localStorage", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadDataFromLocalStorage() {
|
||||||
|
try {
|
||||||
|
const data = localStorage.getItem('ffxivCharacterData');
|
||||||
|
if (data) {
|
||||||
|
return JSON.parse(data);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Error loading FFXIV character data from localStorage", e);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.character-profile {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 2rem;
|
||||||
|
gap: 2rem;
|
||||||
|
|
||||||
|
.portrait {
|
||||||
|
width: 300px;
|
||||||
|
height: 400px;
|
||||||
|
border: 2px solid var(--primary-color);
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: top;
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 1rem;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
.info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-size: 2rem;
|
||||||
|
font-weight: bold;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.technical {
|
||||||
|
font-size: 1rem;
|
||||||
|
color: #9d9d9d;
|
||||||
|
display: flex;
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.jobs {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
.job {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 0.5rem;
|
||||||
|
border: 2px solid var(--primary-color);
|
||||||
|
border-radius: 4px;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-weight: 600;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (max-width: 800px) {
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.portrait {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.description {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.info {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user