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

feat: add initial implementation for the initiative tracker #28

Merged
merged 2 commits into from
Apr 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1,545 changes: 697 additions & 848 deletions package-lock.json

Large diffs are not rendered by default.

37 changes: 19 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,16 @@
"type": "module",
"dependencies": {
"@ark-ui/react": "^2.2.3",
"@serwist/next": "9.0.0-preview.21",
"@serwist/precaching": "9.0.0-preview.21",
"@serwist/sw": "9.0.0-preview.21",
"@serwist/next": "9.0.1",
"@serwist/precaching": "9.0.1",
"@serwist/sw": "9.0.1",
"@vercel/analytics": "^1.2.2",
"@vercel/speed-insights": "^1.0.10",
"auto-text-size": "^0.2.3",
"immer": "^10.0.4",
"lucide-react": "^0.370.0",
"lucide-react": "^0.373.0",
"million": "^3.0.6",
"next": "14.2.1",
"next": "14.2.3",
"npm": "^10.5.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand All @@ -41,24 +41,24 @@
"@park-ui/panda-preset": "0.37.0",
"@release-it/bumper": "^6.0.1",
"@release-it/conventional-changelog": "^8.0.1",
"@storybook/addon-essentials": "^8.0.8",
"@storybook/addon-interactions": "^8.0.8",
"@storybook/addon-links": "^8.0.8",
"@storybook/addon-onboarding": "^8.0.8",
"@storybook/blocks": "^8.0.8",
"@storybook/nextjs": "^8.0.8",
"@storybook/react": "^8.0.8",
"@storybook/test": "^8.0.8",
"@storybook/addon-essentials": "^8.0.9",
"@storybook/addon-interactions": "^8.0.9",
"@storybook/addon-links": "^8.0.9",
"@storybook/addon-onboarding": "^8.0.9",
"@storybook/blocks": "^8.0.9",
"@storybook/nextjs": "^8.0.9",
"@storybook/react": "^8.0.9",
"@storybook/test": "^8.0.9",
"@types/glob": "^8.1.0",
"@types/lodash-es": "^4.17.12",
"@types/node": "^20.12.7",
"@types/react": "^18.2.79",
"@types/react-dom": "^18.2.25",
"@types/svg-sprite": "^0.0.39",
"@typescript-eslint/eslint-plugin": "7.7.0",
"@typescript-eslint/parser": "^7.7.0",
"@typescript-eslint/eslint-plugin": "7.7.1",
"@typescript-eslint/parser": "^7.7.1",
"eslint": "^8.57.0",
"eslint-config-next": "^14.2.1",
"eslint-config-next": "^14.2.3",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-deprecation": "^2.0.0",
"eslint-plugin-no-relative-import-paths": "^1.5.4",
Expand All @@ -71,12 +71,13 @@
"husky": "^9.0.11",
"prettier": "^3.2.5",
"release-it": "^17.2.0",
"storybook": "^8.0.8",
"serwist": "^9.0.2",
"storybook": "^8.0.9",
"svg-sprite": "^2.0.4",
"tsconfig-paths-webpack-plugin": "^4.1.0",
"tsx": "^4.7.2",
"typescript": "5.4.5",
"typescript-eslint": "^7.7.0"
"typescript-eslint": "^7.7.1"
},
"overrides": {
"svgo": "3.2.0"
Expand Down
23 changes: 23 additions & 0 deletions panda.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,42 @@ export default defineConfig({
// Useful for theme customization
theme: {
extend: {
keyframes: {
show: {
'100%': { opacity: 1 },
},
enemyCardPlayed: {
'100%': { opacity: 0.5, filter: 'grayscale(1)' },
},
},
tokens: {
fonts: {
philosopher: { value: 'var(--font-philosopher), sans-serif' },
pirataOne: { value: 'var(--font-pirata-one)' },
},
},
slotRecipes: {
pinInput: {
variants: {
size: {
xl: { input: { height: '12' } },
'2xl': { input: { height: '16' } },
},
},
},
},
recipes: {
heading: {
base: {
letterSpacing: '0 !important',
fontWeight: 'normal',
},
},
text: {
base: {
fontWeight: 'normal',
},
},
button: {
base: {
fontWeight: 'normal',
Expand Down
16 changes: 10 additions & 6 deletions src/app/scenarios/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { Box } from '@style/jsx';
import { SCENARIO_DEFINITIONS } from 'data/scenarios';
import { notFound } from 'next/navigation';

import { Main } from 'components/@navigation';
import { DeckList, Navbar } from 'components/@scenario';
import { UseWakeLock } from 'components/@utils';
import { DeckList, InitiativeList, Navbar } from 'components/@scenario';

const ScenarioPage = ({ params }: { params: { id: string } }) => {
const scenario = SCENARIO_DEFINITIONS.find(
Expand All @@ -15,10 +15,14 @@ const ScenarioPage = ({ params }: { params: { id: string } }) => {
return (
<>
<Navbar scenarioName={scenario.name} />
<Main justify="start">
<DeckList scenario={scenario} />
</Main>
<UseWakeLock />
<div>
<Main justify="start" flexDir="row">
<Box flexDir="column" flex={1}>
<DeckList scenario={scenario} />
</Box>
<InitiativeList />
</Main>
</div>
</>
);
};
Expand Down
8 changes: 4 additions & 4 deletions src/app/sw.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import type { SerwistGlobalConfig } from '@serwist/core';
import { defaultCache } from '@serwist/next/worker';
import type { PrecacheEntry } from '@serwist/precaching';
import { installSerwist } from '@serwist/sw';
import { type PrecacheEntry, Serwist, type SerwistGlobalConfig } from 'serwist';

declare global {
interface WorkerGlobalScope extends SerwistGlobalConfig {
Expand All @@ -14,11 +12,13 @@ declare global {

declare const self: ServiceWorkerGlobalScope;

installSerwist({
const serwist = new Serwist({
precacheEntries: self.__MM_MANIFEST,
skipWaiting: true,
clientsClaim: true,
navigationPreload: true,
runtimeCaching: defaultCache,
disableDevLogs: true,
});

serwist.addEventListeners();
43 changes: 43 additions & 0 deletions src/components/@common/Drawer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
'use client';

import { Dialog as ArkDrawer } from '@ark-ui/react/dialog';
import { ark } from '@ark-ui/react/factory';
import { styled } from '@style/jsx';
import { drawer } from '@style/recipes';
import { createStyleContext } from 'lib/create-style-context';
import type { ComponentProps } from 'react';

const { withProvider, withContext } = createStyleContext(drawer);

export const Root = withProvider(ArkDrawer.Root);
export const Backdrop = withContext(styled(ArkDrawer.Backdrop), 'backdrop');
export const Body = withContext(styled(ark.div), 'body');
export const CloseTrigger = withContext(
styled(ArkDrawer.CloseTrigger),
'closeTrigger',
);
export const Content = withContext(styled(ArkDrawer.Content), 'content');
export const Description = withContext(
styled(ArkDrawer.Description),
'description',
);
export const Footer = withContext(styled(ark.div), 'footer');
export const Header = withContext(styled(ark.div), 'header');
export const Positioner = withContext(
styled(ArkDrawer.Positioner),
'positioner',
);
export const Title = withContext(styled(ArkDrawer.Title), 'title');
export const Trigger = withContext(styled(ArkDrawer.Trigger), 'trigger');

export type RootProps = ComponentProps<typeof Root>;
export type BackdropProps = ComponentProps<typeof Backdrop>;
export type BodyProps = ComponentProps<typeof Body>;
export type CloseTriggerProps = ComponentProps<typeof CloseTrigger>;
export type ContentProps = ComponentProps<typeof Content>;
export type DescriptionProps = ComponentProps<typeof Description>;
export type FooterProps = ComponentProps<typeof Footer>;
export type HeaderProps = ComponentProps<typeof Header>;
export type PositionerProps = ComponentProps<typeof Positioner>;
export type TitleProps = ComponentProps<typeof Title>;
export type TriggerProps = ComponentProps<typeof Trigger>;
59 changes: 59 additions & 0 deletions src/components/@common/PinInput.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {
PinInput as ArkPinInput,
type PinInputRootProps,
} from '@ark-ui/react/pin-input';
import { css, cx } from '@style/css';
import { splitCssProps } from '@style/jsx';
import { pinInput, type PinInputVariantProps } from '@style/recipes';
import type { Assign, JsxStyleProps } from '@style/types';
import { forwardRef, type ReactNode } from 'react';

import { Input } from './Input';

export interface PinInputProps
extends Assign<JsxStyleProps, PinInputRootProps>,
PinInputVariantProps {
children?: ReactNode;
/**
* The number of inputs to render.
* @default 4
*/
length?: number;
}

export const PinInput = forwardRef<HTMLDivElement, PinInputProps>(
(props, ref) => {
const [variantProps, pinInputProps] = pinInput.splitVariantProps(props);
const [cssProps, localProps] = splitCssProps(pinInputProps);
const { children, className, length = 4, ...rootProps } = localProps;
const styles = pinInput(variantProps);

return (
<ArkPinInput.Root
className={cx(styles.root, css(cssProps), className)}
ref={ref}
{...rootProps}
>
{children && (
<ArkPinInput.Label className={styles.label}>
{children}
</ArkPinInput.Label>
)}
<ArkPinInput.Control className={styles.control}>
{Array.from({ length }, (_, index) => index).map((id, index) => (
<ArkPinInput.Input
className={styles.input}
key={id}
index={index}
asChild
>
<Input size={variantProps.size} />
</ArkPinInput.Input>
))}
</ArkPinInput.Control>
</ArkPinInput.Root>
);
},
);

PinInput.displayName = 'PinInput';
2 changes: 2 additions & 0 deletions src/components/@common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ export * from './Badge';
export * from './Button';
export * as Card from './Card';
export * as Dialog from './Dialog';
export * as Drawer from './Drawer';
export * from './Heading';
export * from './IconButton';
export * from './Input';
export * as Menu from './Menu';
export * from './PinInput';
export * as Popover from './Popover';
export * as RadioButtonGroup from './RadioButtonGroup';
export * as Select from './Select';
Expand Down
4 changes: 2 additions & 2 deletions src/components/@scenario/BossCardTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ const BossCardTitle = ({ deck }: Props) => {
style={{
gridTemplateColumns: `repeat(${Math.round(
immunities.length / 2,
)}, 1.25em)`,
)}, 1em)`,
}}
fontSize="1.4em"
fontSize="1.2em"
dangerouslySetInnerHTML={{ __html: immunityIcons }}
mr="8"
/>
Expand Down
1 change: 1 addition & 0 deletions src/components/@scenario/CardThumbnail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const CardThumbnail = ({ name, image }: Props) => {
justifyContent="center"
alignItems="center"
height="75px"
width="auto"
aspectRatio="128/147"
position="relative"
cursor="pointer"
Expand Down
31 changes: 8 additions & 23 deletions src/components/@scenario/ChangePartySize.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,28 @@
import { cva } from '@style/css';
import { Box, Stack } from '@style/jsx';
import { CHARACTERS } from 'data/characters';
import { Icon } from 'icons';
import Image from 'next/image';
import { useState } from 'react';
import useDeepCompareEffect from 'use-deep-compare-effect';

import { CharacterNames } from 'types/character.types';

import { Button, Dialog, IconButton } from 'components/@common';

import { characterInactive } from './styles';

interface Props {
open: boolean;
currentParty: CharacterNames[];
onSubmit: (party: CharacterNames[]) => void;
onClose: () => void;
}

const hoverIcon = cva({
base: { filter: 'none' },
variants: {
state: {
disabled: {
filter:
'brightness(0) invert(24%) sepia(2%) saturate(17%) hue-rotate(324deg) brightness(98%) contrast(82%)',
},
active: {
filter: 'none',
},
},
},
});

const ChangePartySize = ({ open, currentParty, onSubmit, onClose }: Props) => {
const [party, selectParty] = useState(currentParty);
const handleClose = (details: { open: boolean }) => {
if (!details.open) onClose();
};

useDeepCompareEffect(() => {
selectParty(currentParty);
}, [currentParty]);

const onChange = (character: CharacterNames) => {
selectParty((party) => {
if (party.includes(character)) {
Expand Down Expand Up @@ -80,13 +61,17 @@ const ChangePartySize = ({ open, currentParty, onSubmit, onClose }: Props) => {
{Object.values(CHARACTERS).map((item) => {
const isSelected = party.includes(item.name);
return (
<Box key={item.name} onClick={() => onChange(item.name)}>
<Box
key={item.name}
onClick={() => onChange(item.name)}
cursor="pointer"
>
<Image
src={`/images/characters/${item.icon}`}
width={42}
height={42}
alt={item.name}
className={hoverIcon({
className={characterInactive({
state: isSelected ? 'active' : 'disabled',
})}
/>
Expand Down
Loading