Skip to content

Commit

Permalink
feat: new battle history list
Browse files Browse the repository at this point in the history
  • Loading branch information
dsrkafuu committed Mar 18, 2022
1 parent fde0cab commit 28d709e
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 83 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
[![](https://img.shields.io/github/license/dsrkafuu/skyline-overlay)](https://github.com/dsrkafuu/skyline-overlay/blob/main/LICENSE)
[![](https://img.shields.io/lgtm/grade/javascript/github/dsrkafuu/skyline-overlay)](https://lgtm.com/projects/g/dsrkafuu/skyline-overlay/context:javascript)

An extended horizon overlay like [horizoverlay](https://github.com/bsides/horizoverlay/) with some of [ikegami](https://github.com/hibiyasleep/ikegami)'s features. The project is based on React with MobX & Vite, and the dedicated [ffxiv-overlay-api](https://github.com/dsrkafuu/ffxiv-overlay-api).
Features: Basic overlay, extended details, customizable display/data settings, battle history, and more. The project is based on React with MobX & Vite, and the dedicated [ffxiv-overlay-api](https://github.com/dsrkafuu/ffxiv-overlay-api).

<img align="center" src="https://raw.githubusercontent.com/dsrkafuu/skyline-overlay/main/assets/preview-en-v3.jpg" alt="Skyline Preview" />

Expand All @@ -27,6 +27,8 @@ Check [ngld/OverlayPlugin](https://github.com/ngld/OverlayPlugin). For WebSocket

2K+ (WQHD+) screen with 1.1x scale is recommended for better experience in FFXIV.

Click the encounter can ends current battle and start a new one; zone name will be fully displayed when hover; click the DPS meter on encounter bar can switch to show HPS.

By default the overlay follows the pet-merging policy set in the FFXIV ACT Plugin. When playing on global servers with a custom language patch which causes the plugin's pet-merging not working, you can set your ID in an overlay config to manually merge your pets' data.

Local server:
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"private": true,
"type": "module",
"name": "skyline-overlay",
"version": "3.3.2",
"version": "3.4.0",
"description": "A modern customizable horizon FFXIV miniparse overlay.",
"license": "Apache-2.0",
"author": "DSRKafuU <dsrkafuu@outlook.com> (https://dsrkafuu.net)",
Expand All @@ -25,7 +25,7 @@
"@sentry/tracing": "~6.18.2",
"clsx": "~1.1.1",
"ffxiv-overlay-api": "~4.2.0",
"mobx": "~6.4.2",
"mobx": "~6.5.0",
"mobx-react-lite": "~3.3.0",
"normalize.css": "~8.0.1",
"react": "~17.0.2",
Expand All @@ -47,7 +47,7 @@
"eslint-plugin-react-hooks": "~4.3.0",
"glob": "~7.2.0",
"npm-run-all": "~4.1.5",
"prettier": "~2.5.1",
"prettier": "~2.6.0",
"rollup-plugin-visualizer": "~5.6.0",
"sass": "~1.49.9",
"serve": "~13.0.2",
Expand Down
22 changes: 11 additions & 11 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 20 additions & 22 deletions src/store/modules/API.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import OverlayAPI, { ExtendData } from 'ffxiv-overlay-api';
import { makeAutoObservable } from 'mobx';
import { Store } from '..';
import { cloneDeep } from '../../utils/lodash';
import { getLS, setLS } from '../../utils/storage';

const cleanData: ExtendData = {
isActive: false,
Expand All @@ -25,21 +24,24 @@ class API {
overlay = new OverlayAPI();
data: ExtendData = cleanData;
historys: HistoryData[] = [];
history: HistoryData | null = null;
history = {
idx: -1, // mark current history index for active comparsion
data: null as HistoryData | null,
};

/** @mobx computed */

get active() {
return (this.history || this.data).isActive;
return (this.history.data || this.data).isActive;
}
get encounter() {
return (this.history || this.data).encounter;
return (this.history.data || this.data).encounter;
}
get lb() {
return (this.history || this.data).limitBreak;
return (this.history.data || this.data).limitBreak;
}
get combatant() {
return (this.history || this.data).combatant;
return (this.history.data || this.data).combatant;
}

/**
Expand All @@ -48,12 +50,6 @@ class API {
constructor(rootStore: Store) {
this.rootStore = rootStore;

// load historys from storage
const historys = getLS('historys');
if (historys && Array.isArray(historys) && historys.length <= 5) {
this.historys = historys;
}

// add overlay callback
this.overlay.addListener('CombatData', (rawData) => {
const data = rawData.extendData;
Expand All @@ -74,34 +70,36 @@ class API {
/**
* show a history data (-1 to disable)
*/
showHistory(index: number) {
if (index < 0 || index >= 5 || !this.historys[index]) {
this.history = null;
showHistory(idx: number) {
if (idx < 0 || idx >= 5 || !this.historys[idx]) {
this.history.idx = -1;
this.history.data = null;
return;
}
// direct set reference instead of deep clone,
// for Object.is() comparsion
this.history = this.historys[index];
this.history.idx = idx;
this.history.data = this.historys[idx];
}
/**
* update new combat data
*/
updateCombat(payload: ExtendData) {
this.data = payload;
this.history && (this.history = null);
// clear current history display if new data appears
if (this.history.data) {
this.history.idx = -1;
this.history.data = null;
}
this.rootStore.settings.toggleShowCombatants(true);
}
/**
* push a history (active must be false) (5 max)
*/
tryPushHistory(payload: ExtendData) {
// if last data (false) this data (true) which indicates a new encounter
// if last data (false) this data (true) which indicates a new battle,
// push last data (false) into a new history
if (lastData && !lastData.isActive && payload.isActive) {
this.historys.length >= 5 && this.historys.pop();
this.historys.unshift({ time: Date.now(), ...lastData });
// save to storage
setLS('historys', this.historys);
}
// record data for future use
lastData = cloneDeep(payload);
Expand Down
41 changes: 23 additions & 18 deletions src/views/Settings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -175,30 +175,35 @@
white-space: nowrap;
overflow: hidden;
flex: 0 0 auto;
margin-left: $padding-md;

margin-left: $padding-md;
&:last-child {
margin-right: $padding-md;
}
}

&:first-child,
&:nth-child(3) {
flex: 0 0 auto;
width: 0.4rem;
text-align: center;
}
&-duration {
flex: 0 0 auto;
width: 0.38rem;
text-align: center;
}

&:nth-child(2) {
flex: 0 0 auto;
width: 0.6rem;
text-align: center;
}
&-time {
flex: 0 0 auto;
width: 0.58rem;
text-align: center;
}

&:last-child {
flex: 1 1 auto;
min-width: 0;
text-overflow: ellipsis;
padding: 0 $padding-sm;
}
&-zone {
flex: 1 1 auto;
text-overflow: ellipsis;
min-width: 0;
padding: 0 $padding-sm;
}

&-dps {
display: flex;
justify-content: flex-end;
padding-right: $padding-lg;
}
}
65 changes: 37 additions & 28 deletions src/views/SettingsHistory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,9 @@ import { observer } from 'mobx-react-lite';
import { useStore } from '../hooks';
import clsx from 'clsx';
import { fmtDuration, fmtZoneName } from '../utils/formatters';
import { useEffect, useState } from 'react';

function parseDate(time?: number) {
if (!time) {
return '';
}
const d = new Date(time);
const mon = d.getMonth() + 1;
const day = d.getDate();
const MM = mon < 10 ? `0${mon}` : mon;
const DD = day < 10 ? `0${day}` : day;
return `${MM}-${DD}`;
}

function parseTime(time?: number) {
if (!time) {
return '';
}
function parseTime(time: number) {
const d = new Date(time);
const hour = d.getHours();
const min = d.getMinutes();
Expand All @@ -32,53 +18,76 @@ function parseTime(time?: number) {
interface SettingsHistoryRowProps {
current: boolean;
duration: string;
zone: string;
dps: number;
zoneName: string;
time?: number;
onClick?: () => void;
}

function SettingsHistoryRow({
current,
duration,
zone,
dps,
zoneName,
time,
onClick,
}: SettingsHistoryRowProps) {
const [now, setNow] = useState(Date.now());
useEffect(() => {
const timer = setInterval(() => setNow(Date.now()), 1000);
return () => clearInterval(timer);
}, []);

return (
<div
className={clsx('settings-history-row', {
'settings-history-row--active': current,
})}
onClick={onClick}
>
<span className='settings-history-item'>{parseDate(time)}</span>
<span className='settings-history-item'>{parseTime(time)}</span>
<span className='settings-history-item'>{fmtDuration(duration)}</span>
<span className='settings-history-item'>{fmtZoneName(zone)}</span>
<div className='settings-history-item settings-history-time'>
{parseTime(time || now)}
</div>
<div className='settings-history-item settings-history-duration'>
{fmtDuration(duration)}
</div>
<div className='settings-history-item settings-history-zone'>
{fmtZoneName(zoneName)}
</div>
<div className='settings-history-item settings-history-dps'>
<span className='g-number'>{dps}</span>
<span className='g-counter'>DPS</span>
</div>
</div>
);
}

function SettingsHistory() {
const { api } = useStore();
// do not use getters here,
// since getter may returns history data when selected
const { duration, dps, zoneName } = api.data.encounter;

return (
<div className='settings-history'>
<div className='settings-history-space'></div>
<SettingsHistoryRow
current={!api.history}
duration={api.data.encounter.duration}
zone={api.data.encounter.zoneName}
current={api.history.idx === -1}
duration={duration}
dps={dps}
zoneName={zoneName}
onClick={() => api.showHistory(-1)}
/>
{api.historys.map((item, idx) => {
const { duration, dps, zoneName } = item.encounter;
return (
<SettingsHistoryRow
key={idx}
current={Object.is(api.history, item)}
current={api.history.idx === idx}
time={item.time}
duration={item.encounter.duration}
zone={item.encounter.zoneName}
duration={duration}
dps={dps}
zoneName={zoneName}
onClick={() => api.showHistory(idx)}
/>
);
Expand Down

0 comments on commit 28d709e

Please sign in to comment.