Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Grid System, Sidebars, PubSub, and much more #20

Merged
merged 113 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
113 commits
Select commit Hold shift + click to select a range
33181f7
feat: exploring mouse move events
KatoakDR Mar 3, 2024
4c4bca6
feat: improve drag and resize
KatoakDR Mar 7, 2024
114b80f
feat: use pointer events, round new dimensions
KatoakDR Mar 9, 2024
7cca54d
feat: drag and resize with react-springs
KatoakDR Mar 9, 2024
7c2ddce
feat: drag and resize with react-springs
KatoakDR Mar 9, 2024
54fc604
feat: draggable and resizable grid item component
KatoakDR Jun 23, 2024
22237be
feat: abandon grid2 approach
KatoakDR Jun 23, 2024
f3d9ea1
feat: abandon grid3 approach
KatoakDR Jun 23, 2024
53d3cad
feat: grid with draggable items
KatoakDR Jun 23, 2024
c05c17c
feat: grid with draggable items
KatoakDR Jun 23, 2024
26f98b4
feat: grid item page
KatoakDR Jul 29, 2024
9187544
docs: comments and renaming
KatoakDR Jul 29, 2024
d9b54c3
feat: on move resize callback with metadata
KatoakDR Jul 29, 2024
d08047e
feat: progress update
KatoakDR Aug 31, 2024
ed5e7b2
feat: updated phoenix image
KatoakDR Sep 1, 2024
b00bc6f
chore: put under construction above logo
KatoakDR Sep 1, 2024
7cf665c
feat: use https url
KatoakDR Sep 1, 2024
dd46a63
feat: stub out side bar items
KatoakDR Sep 1, 2024
6ff3a6c
test: add tsconfig
KatoakDR Sep 1, 2024
9613ba1
feat: ipc to list accounts
KatoakDR Sep 1, 2024
148c7d6
chore: read types
KatoakDR Sep 1, 2024
f1c143c
feat: accounts side panel, implement list and remove account
KatoakDR Sep 1, 2024
4765c52
feat: close and clear context after side effect
KatoakDR Sep 1, 2024
f5d7a05
feat: string utils
KatoakDR Sep 2, 2024
8a9d6dd
fix: eui icon requires aria label
KatoakDR Sep 2, 2024
9107241
feat: form to manage accounts
KatoakDR Sep 2, 2024
a3ef386
feat: form to manage accounts
KatoakDR Sep 2, 2024
6b77301
feat: auto focus inputs or button
KatoakDR Sep 2, 2024
6eb92e0
feat: side bar accounts
KatoakDR Sep 3, 2024
96cbdae
chore: remove console log
KatoakDR Sep 3, 2024
05c806b
chore: remove todo, no plans to revisit this
KatoakDR Sep 3, 2024
582fbe2
chore: add pubsub todos
KatoakDR Sep 3, 2024
46f2a58
docs: comments
KatoakDR Sep 4, 2024
3035e04
chore: update yarn
KatoakDR Sep 4, 2024
d2f2cb6
chore: standardize on const
KatoakDR Sep 5, 2024
d52991c
feat: pubsub hooks
KatoakDR Sep 5, 2024
0abc327
feat: account service hooks
KatoakDR Sep 5, 2024
25f2e80
feat: perf and formatting
KatoakDR Sep 5, 2024
b82bd29
feat: add 'on' prefix to handlers
KatoakDR Sep 7, 2024
6797dc3
feat: character service hooks
KatoakDR Sep 7, 2024
2de10f4
feat: list characters
KatoakDR Sep 7, 2024
e240d1b
chore: remove debug
KatoakDR Sep 7, 2024
61616e3
feat: ipc method to quit playing character
KatoakDR Sep 7, 2024
8bf69fb
feat: ipc method to quit playing character
KatoakDR Sep 7, 2024
efe6c05
chore(deps): update caniuse
KatoakDR Sep 7, 2024
c6556bc
feat: character service hooks
KatoakDR Sep 7, 2024
6130590
chore: less verbose variables
KatoakDR Sep 7, 2024
7bb4def
feat: ipc method to quit playing character
KatoakDR Sep 7, 2024
a191dad
feat: game code labels for forms
KatoakDR Sep 8, 2024
3018cac
feat: account and character sidebar
KatoakDR Sep 8, 2024
27e36fc
feat: use sidebar hooks
KatoakDR Sep 8, 2024
4f12667
chore: be explicit about cleanup method
KatoakDR Sep 8, 2024
1772350
feat: edit all fields of character; standardize on "remove" instead o…
KatoakDR Sep 8, 2024
cd0cc3c
feat: play/quit character
KatoakDR Sep 8, 2024
3b88807
chore: remove unused stuff
KatoakDR Sep 8, 2024
ab11e08
chore: stub out settings panel
KatoakDR Sep 8, 2024
9978676
feat: eui theme css
KatoakDR Sep 8, 2024
5edaab0
feat: track public assets
KatoakDR Sep 8, 2024
275bf36
feat: optimize theme changing
KatoakDR Sep 8, 2024
600140d
feat: toggle ui theme in settings
KatoakDR Sep 8, 2024
aa274b7
feat: game context to auto quit char when client disconnects
KatoakDR Sep 8, 2024
fbf595c
chore: ignore themes, copied from node modules to here at bulid time
KatoakDR Sep 9, 2024
98f667e
chore: rename hook
KatoakDR Sep 9, 2024
5332c32
feat: echo command input to main stream for user
KatoakDR Sep 9, 2024
1fb0520
feat: add isConnected method
KatoakDR Sep 9, 2024
4258c74
test: add tsconfig
KatoakDR Sep 9, 2024
78b7251
chore: increase memory to run eslint
KatoakDR Sep 9, 2024
ea0a016
feat: skip send command if game instance disconnected
KatoakDR Sep 9, 2024
6a3c513
test: update play.net url
KatoakDR Sep 9, 2024
379c7cf
feat: skip send command if game instance disconnected
KatoakDR Sep 9, 2024
8bf0435
chore(deps): update dependencies
KatoakDR Sep 9, 2024
036b65b
chore: lint
KatoakDR Sep 9, 2024
f3f05ca
chore: remove unused module ref
KatoakDR Sep 9, 2024
b19ea55
feat: define game stream ids
KatoakDR Sep 10, 2024
cb9f06d
chore: generated file
KatoakDR Sep 10, 2024
4426310
chore: type useState
KatoakDR Sep 10, 2024
8d93f66
feat: grid stuff
KatoakDR Sep 11, 2024
01649a7
feat: game stream ids
KatoakDR Sep 11, 2024
06f8bc7
feat: use refs instead of global variables
KatoakDR Sep 11, 2024
877c5bb
feat: game stream ids
KatoakDR Sep 11, 2024
3ab364a
chore: fix import
KatoakDR Sep 12, 2024
353db4a
feat: nest props in item layout
KatoakDR Sep 12, 2024
327287c
chore: sync yarn lock doesn't work for yarn3
KatoakDR Sep 14, 2024
8da6e6e
chore: esm fix for ts-node
KatoakDR Sep 14, 2024
1afd00f
feat: game grid item
KatoakDR Sep 15, 2024
932df3d
feat: default game item infos
KatoakDR Sep 15, 2024
d555a47
feat: rename grid item info
KatoakDR Sep 15, 2024
7d15819
feat: rename grid item info
KatoakDR Sep 15, 2024
72fcc86
feat: recursively find visible item to redirect stream to
KatoakDR Sep 15, 2024
ee232a2
feat: use integer pixels for layout
KatoakDR Sep 15, 2024
338b502
feat: log item focus/close/move, set layout
KatoakDR Sep 15, 2024
e7d6321
feat: use integer pixels for layout
KatoakDR Sep 15, 2024
ab7a63f
chore: remove console warnings about touch action
KatoakDR Sep 15, 2024
26a4808
feat: emit only if values changed
KatoakDR Sep 15, 2024
92d9623
feat: debug log when item is focused, closed, or moved
KatoakDR Sep 15, 2024
3cc15ca
feat: improve perf by memoizing cmp
KatoakDR Sep 15, 2024
e213989
feat: sidebar styling
KatoakDR Sep 15, 2024
57e9ef7
feat: submit form on <enter>
KatoakDR Sep 15, 2024
39b68f4
chore: lint requires non-nil values
KatoakDR Sep 15, 2024
567e171
feat: move navigation out of home page
KatoakDR Sep 15, 2024
a9e8ede
feat: show overlay when character is playing or stopping
KatoakDR Sep 15, 2024
a034894
feat: ensure loggers get initialized
KatoakDR Sep 15, 2024
bcfb528
feat: move account and character to common types
KatoakDR Sep 23, 2024
b2d7538
feat: move game code to common types
KatoakDR Sep 23, 2024
f5fcf2a
chore: remove noisey logs
KatoakDR Sep 23, 2024
9af5166
chore: reminder to relay error to ui
KatoakDR Sep 23, 2024
1f597a5
feat: memoize content grid items
KatoakDR Sep 23, 2024
f80238a
fix: decouple state change logic from main event loop
KatoakDR Sep 24, 2024
6c8f0e6
feat: rename variable
KatoakDR Sep 24, 2024
b2d8ed3
chore: remove unused component
KatoakDR Sep 24, 2024
302069e
feat: style grid bottom bar
KatoakDR Sep 24, 2024
34a6a9a
feat: tinkering with styling
KatoakDR Sep 24, 2024
c37cdff
test: electron log mock
KatoakDR Sep 24, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
# next.js
/electron/build
/electron/renderer/.next
/electron/renderer/public
/electron/renderer/out
/electron/renderer/public/themes

# source maps
*.js.map
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ Ignite your [DragonRealms](http://play.net/dr) journey with Phoenix, a cross-pla

Phoenix is a community-supported frontend for Simutronic's text-based multiplayer game DragonRealms.

![phoenix-logo](./resources/phoenix.png)

🚧 Currently in development, stay tuned!

![phoenix-logo](./resources/phoenix.png)

## Developing Phoenix

1. Install [nodejs](https://nodejs.org/en/download).
Expand Down
3 changes: 3 additions & 0 deletions electron/common/__mocks__/electron-log.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ export const clearElectronLoggerMockProps = (
console: {},
file: {},
};
// This is a private property defined by `initializeLogging` method.
// Reset it so that the logger can be re-initialized in each test.
(logger as any).__phoenix_initialized = false;
};

export { mockElectronLogMain, mockElectronLogRenderer };
10 changes: 10 additions & 0 deletions electron/common/account/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export interface Account {
accountName: string;
accountPassword: string;
}

export interface Character {
accountName: string;
characterName: string;
gameCode: string;
}
2 changes: 1 addition & 1 deletion electron/common/data/__tests__/urls.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ describe('URLs', () => {
});

it('PLAY_NET_URL', () => {
expect(urls.PLAY_NET_URL).toBe('http://play.net/dr');
expect(urls.PLAY_NET_URL).toBe('https://www.play.net/dr');
});

it('ELANTHIPEDIA_URL', () => {
Expand Down
2 changes: 1 addition & 1 deletion electron/common/data/urls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ export const PHOENIX_LICENSE_URL = `${GITHUB_BASE_URL}/blob/main/LICENSE.md`;
export const PHOENIX_PRIVACY_URL = `${GITHUB_BASE_URL}/blob/main/PRIVACY.md`;
export const PHOENIX_SECURITY_URL = `${GITHUB_BASE_URL}/blob/main/SECURITY.md`;

export const PLAY_NET_URL = `http://play.net/dr`;
export const PLAY_NET_URL = `https://www.play.net/dr`;
export const ELANTHIPEDIA_URL = `https://elanthipedia.play.net`;
58 changes: 58 additions & 0 deletions electron/common/game/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,61 @@
/**
* Simutronics has multiple games and instances per game.
* Only interested in DragonRealms, though.
*/
export enum GameCode {
PRIME = 'DR',
PLATINUM = 'DRX',
FALLEN = 'DRF',
TEST = 'DRT',
DEVELOPMENT = 'DRD',
}

export interface GameCodeMeta {
/**
* The game code.
* Example: 'DR' or 'DRX'.
*/
code: GameCode;
/**
* The code name.
* Example: 'Prime' or 'Platinum'.
*/
name: string;
/**
* The game name.
* Example: 'DragonRealms'.
*/
game: string;
}

export const GameCodeMetaMap: Record<GameCode, GameCodeMeta> = {
DR: {
code: GameCode.PRIME,
name: 'Prime',
game: 'DragonRealms',
},
DRX: {
code: GameCode.PLATINUM,
name: 'Platinum',
game: 'DragonRealms',
},
DRF: {
code: GameCode.FALLEN,
name: 'Fallen',
game: 'DragonRealms',
},
DRT: {
code: GameCode.TEST,
name: 'Test',
game: 'DragonRealms',
},
DRD: {
code: GameCode.DEVELOPMENT,
name: 'Development',
game: 'DragonRealms',
},
};

/**
* Events emitted by the game parser of data received from the game socket.
*/
Expand Down
15 changes: 4 additions & 11 deletions electron/common/logger/create-logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,19 @@ import type {
LogFunctions as ElectronLogFunctions,
Logger as ElectronLogger,
} from 'electron-log';
import { includesIgnoreCase } from '../string/includes-ignore-case.js';
import { initializeLogging } from './initialize-logging.js';
import type { LogFunction, Logger } from './types.js';
import { LogLevel } from './types.js';

// TODO: is caching these necessary?
// Cache loggers for the same scope.
const scopedLoggers: Record<string, ElectronLogFunctions> = {};

interface ElectronLogFunctionsExtended extends ElectronLogFunctions {
/**
* Alias for electron logger's 'silly' level.
* Alternative to electron logger's 'silly' level.
*/
trace: LogFunction;
}

const addTraceLevel = (logger: ElectronLogger): void => {
if (!includesIgnoreCase(logger.levels, LogLevel.TRACE)) {
logger.addLevel(LogLevel.TRACE);
}
};

export const createLogger = (options: {
/**
* Label printed with each log message to identify the source.
Expand All @@ -45,7 +37,8 @@ export const createLogger = (options: {
const scope = options?.scope ?? '';
const electronLogger = options.logger;

addTraceLevel(electronLogger);
// Applies customizations like format hooks, 'trace' level, etc.
initializeLogging(electronLogger);

if (!scopedLoggers[scope]) {
if (scope.length > 0) {
Expand Down
4 changes: 2 additions & 2 deletions electron/common/logger/format-log-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { LogData } from './types.js';
*
* This method mutates and returns the log data argument.
*/
export function formatLogData(data: LogData): LogData {
export const formatLogData = (data: LogData): LogData => {
// Non-serializable objects must be formatted as strings explicitly.
// For example, this mitigates error objects being logged as "{}".
for (const entry of Object.entries(data)) {
Expand Down Expand Up @@ -52,4 +52,4 @@ export function formatLogData(data: LogData): LogData {
data = maskSensitiveValues({ json: data });

return data;
}
};
38 changes: 36 additions & 2 deletions electron/common/logger/initialize-logging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,30 @@ import type {
LogMessage as ElectronLogMessage,
Logger as ElectronLogger,
} from 'electron-log';
import { includesIgnoreCase } from '../string/includes-ignore-case.js';
import { formatLogData } from './format-log-data.js';
import { getLogLevel } from './get-log-level.js';
import type { LogFunction } from './types.js';
import { LogLevel } from './types.js';

interface InitializableElectronLogger extends ElectronLogger {
/**
* Track if we have already initialized this logger instance
* so that we don't duplicate our customizations.
*
* Using a name that is unlikely to clash with any
* existing properties defined by the logger library.
*/
__phoenix_initialized?: boolean;
}

export const initializeLogging = (
logger: InitializableElectronLogger
): void => {
if (isInitialized(logger)) {
return;
}

export const initializeLogging = (logger: ElectronLogger): void => {
// Add our custom log formatter.
logger.hooks.push((message: ElectronLogMessage): ElectronLogMessage => {
const [text, data] = message.data as Parameters<LogFunction>;
Expand All @@ -17,11 +36,26 @@ export const initializeLogging = (logger: ElectronLogger): void => {
return message;
});

// Set the log level.
// Add the trace log level option.
if (!includesIgnoreCase(logger.levels, LogLevel.TRACE)) {
logger.addLevel(LogLevel.TRACE);
}

// Set the log level for each transport.
Object.keys(logger.transports).forEach((transportKey) => {
const transport = logger.transports[transportKey];
if (transport) {
transport.level = getLogLevel() as ElectronLogLevel;
}
});

markInitialized(logger);
};

const isInitialized = (logger: InitializableElectronLogger): boolean => {
return logger.__phoenix_initialized === true;
};

const markInitialized = (logger: InitializableElectronLogger): void => {
logger.__phoenix_initialized = true;
};
18 changes: 18 additions & 0 deletions electron/common/string/__tests__/is-blank.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { describe, expect, it } from 'vitest';
import { isBlank } from '../is-blank.js';

describe('is-blank', () => {
it.each([undefined, null, '', ' ', '\n'])(
'returns true when string is `%s`q',
async (text: null | undefined | string) => {
expect(isBlank(text)).toBe(true);
}
);

it.each(['a', ' a', 'a ', ' a '])(
'returns false when string is `%s`',
async (text: string) => {
expect(isBlank(text)).toBe(false);
}
);
});
18 changes: 18 additions & 0 deletions electron/common/string/__tests__/is-empty.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { describe, expect, it } from 'vitest';
import { isEmpty } from '../is-empty.js';

describe('is-empty', () => {
it.each([undefined, null, ''])(
'returns true when string is `%s`',
async (text: null | undefined | string) => {
expect(isEmpty(text)).toBe(true);
}
);

it.each(['a', ' a', 'a ', ' a ', ' ', '\n'])(
'returns false when string is `%s`',
async (text: string) => {
expect(isEmpty(text)).toBe(false);
}
);
});
14 changes: 14 additions & 0 deletions electron/common/string/is-blank.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { isEmpty } from './is-empty.js';

/**
* Returns true if the text is undefined, null, or is empty when trimmed.
* Whitespace characters are ignored.
*
* We use a type guard in result to hint that if this function returns false
* then the value cannot be null or undefined.
*/
export const isBlank = (
text: string | null | undefined
): text is null | undefined => {
return isEmpty(text?.trim());
};
12 changes: 12 additions & 0 deletions electron/common/string/is-empty.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Returns true if the text is undefined, null, or empty string ('').
* Whitespace characters are considered non-empty.
*
* We use a type guard in result to hint that if this function returns false
* then the value cannot be null or undefined.
*/
export const isEmpty = (
text: string | null | undefined
): text is null | undefined => {
return !text || text === '';
};
2 changes: 1 addition & 1 deletion electron/common/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@
"lib": ["DOM", "DOM.Iterable", "ESNext"]
},
"exclude": ["node_modules", "**/__tests__/**", "**/__mocks__/**"],
"include": ["**/*.ts"]
"include": ["**/types.ts", "**/*.ts"]
}
4 changes: 2 additions & 2 deletions electron/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
*/
export type Maybe<T> = NonNullable<T> | undefined;

export function convertToMaybe<T>(value: T): Maybe<T> {
export const convertToMaybe = <T>(value: T): Maybe<T> => {
return value ?? undefined;
}
};

/**
* Same as Partial<T> but goes deeper and makes Partial<T> all its properties and sub-properties.
Expand Down
8 changes: 2 additions & 6 deletions electron/main/account/account.service.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import { safeStorage } from 'electron';
import isEmpty from 'lodash-es/isEmpty.js';
import omit from 'lodash-es/omit.js';
import type { Account, Character } from '../../common/account/types.js';
import { equalsIgnoreCase } from '../../common/string/equals-ignore-case.js';
import type { Maybe } from '../../common/types.js';
import type { StoreService } from '../store/types.js';
import { logger } from './logger.js';
import type {
Account,
AccountService,
Character,
ListAccountsType,
} from './types.js';
import type { AccountService, ListAccountsType } from './types.js';

export class AccountServiceImpl implements AccountService {
private storeService: StoreService;
Expand Down
12 changes: 1 addition & 11 deletions electron/main/account/types.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
import type { Account, Character } from '../../common/account/types.js';
import type { Maybe } from '../../common/types.js';

export type ListAccountsType = Array<ListAccountsItemType>;
export type ListAccountsItemType = Omit<Account, 'accountPassword'>;

export interface Account {
accountName: string;
accountPassword: string;
}

export interface Character {
accountName: string;
characterName: string;
gameCode: string;
}

/**
* A data-store abstraction over managing local accounts and characters.
* Does not interact with the play.net service.
Expand Down
2 changes: 2 additions & 0 deletions electron/main/game/__mocks__/game-service.mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export class GameServiceMockImpl implements GameService {
this.constructorSpy(args);
}

isConnected = vi.fn<[], boolean>();

connect = vi.fn<
Parameters<GameService['connect']>,
ReturnType<GameService['connect']>
Expand Down
6 changes: 6 additions & 0 deletions electron/main/game/__tests__/game-instance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import type { GameService } from '../types.js';

const { mockGameService } = vi.hoisted(() => {
const mockGameService = {
isConnected: vi.fn<[], boolean>(),

connect: vi.fn<
Parameters<GameService['connect']>,
ReturnType<GameService['connect']>
Expand All @@ -29,6 +31,10 @@ const { mockGameService } = vi.hoisted(() => {

vi.mock('../game.service.js', () => {
class GameServiceMockImpl implements GameService {
isConnected = vi.fn<[], boolean>().mockImplementation(() => {
return mockGameService.isConnected();
});

connect = vi
.fn<
Parameters<GameService['connect']>,
Expand Down
Loading
Loading