Working on layout, tilegrid

This commit is contained in:
Benjamin Sherriff
2023-10-31 08:48:21 -04:00
parent c5a6b762f0
commit 046bf51697
9 changed files with 155 additions and 76 deletions

View File

@@ -0,0 +1,5 @@
import React from 'react';
export default function Page() {
return <></>;
}

View File

@@ -0,0 +1,5 @@
import React from 'react';
export default function Page({ params }: { params: { id: string } }) {
return <>{params.id}</>;
}

View File

@@ -0,0 +1,5 @@
import React from 'react';
export default function Page() {
return <h1>Create new Character</h1>;
}

View File

@@ -0,0 +1,5 @@
import React from 'react';
export default function Page() {
return <></>;
}

View File

@@ -4,6 +4,16 @@ import React from 'react';
// Home page for siren
export default function Page() {
return (
// <div>
// <p>Siren is a Dungeon Master's best friend.</p>
// <h2>Features:</h2>
// <ul>
// <li>Manage your campaign and players</li>
// <li>Create battlemaps on the fly and track initiative</li>
// <li>Connect the Discord Bot to play online with friends</li>
// <li>Reference Races, Classes, Items, Spells, and more</li>
// </ul>
// </div>
<div style={{ overflow: 'hidden' }}>
<TileGrid />
</div>

View File

@@ -1,36 +1,49 @@
export interface HeaderItem {
name: string;
link: string;
role?: string;
label: string;
link?: string;
links?: HeaderItem[];
}
export const headerItems: HeaderItem[] = [
{
name: 'Races',
label: 'Campaigns',
link: '/campaigns'
},
{
label: 'Characters',
link: '/characters'
},
{
label: 'Resources',
links: [
{
label: 'Races',
link: '/races'
},
{
name: 'Classes',
label: 'Classes',
link: '/classes'
},
{
name: 'Feats',
label: 'Feats',
link: '/feats'
},
{
name: 'Options & Features',
label: 'Options & Features',
link: '/options'
},
{
name: 'Backgrounds',
label: 'Backgrounds',
link: '/backgrounds'
},
{
name: 'Items',
label: 'Items',
link: '/items'
},
{
name: 'Spells',
label: 'Spells',
link: '/spells'
}
]
}
];

View File

@@ -1,9 +1,9 @@
'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
import { usePathname, useRouter } from 'next/navigation';
import './header.css';
import { Avatar, Button, Card, FileButton, Grid, Group, Menu, Text, UnstyledButton } from '@mantine/core';
import { Avatar, Button, Card, Center, FileButton, Grid, Group, Menu, Text, UnstyledButton } from '@mantine/core';
import Cookies from 'js-cookie';
import { useEffect, useState } from 'react';
import { logout, refresh, refreshLoggedIn } from '@/api/auth';
@@ -13,14 +13,16 @@ import { HeaderItem, headerItems } from './headerItems';
import { userState } from '@/state/auth';
import { useRecoilState } from 'recoil';
import { getPicture, setPicture } from '@/api/users';
import { BsChevronDown } from 'react-icons/bs';
export default function Header() {
const pathName = usePathname();
const [modalType, toggle] = useToggle([undefined, 'login', 'register', 'reset']);
const [headers, setHeaders] = useState<HeaderItem[]>([]);
const [headers] = useState<HeaderItem[]>(headerItems);
const [user, setUser] = useRecoilState(userState);
const [refreshId, setRefreshId] = useState<NodeJS.Timeout | undefined>(undefined);
const [profilePicture, setProfilePicture] = useState<File | null>(null);
const router = useRouter();
useEffect(() => {
if (!user || !Cookies.get('logged_in')) {
@@ -40,16 +42,6 @@ export default function Header() {
}
}, [user]);
useEffect(() => {
const h: HeaderItem[] = [];
headerItems.forEach((item) => {
if (item.role == undefined || user?.role == item.role) {
h.push(item);
}
setHeaders(h);
});
}, [user]);
return (
<>
<nav className='navbar'>
@@ -58,11 +50,41 @@ export default function Header() {
Siren
</Link>
<div className='header-items'>
{headers.map((item) => (
<Link className={`header-item ${pathName == item.link && 'active'}`} href={item.link} key={item.name}>
{item.name}
{headers.map((item) => {
const menuItems = item.links?.map((subItem) => (
<Menu.Item
color={pathName == subItem.link ? 'blue' : undefined}
onClick={() => router.push(subItem.link ?? '#')}
key={subItem.label}
>
{subItem.label}
</Menu.Item>
));
if (menuItems) {
return (
<Menu trigger='hover' transitionProps={{ exitDuration: 0 }} withinPortal key={item.label}>
<Menu.Target>
<Link className={`header-item ${pathName == item.link && 'active'}`} href={item.link ?? '#'}>
<Center>
{item.label}
<BsChevronDown />
</Center>
</Link>
))}
</Menu.Target>
<Menu.Dropdown>{menuItems}</Menu.Dropdown>
</Menu>
);
}
return (
<Link
className={`header-item ${pathName == item.link && 'active'}`}
href={item.link ?? '#'}
key={item.label}
>
{item.label}
</Link>
);
})}
</div>
</div>
<div className='user-section'>

View File

@@ -1,10 +1,11 @@
'use client';
import { Graphics, Stage } from '@pixi/react';
import { Graphics, Stage, Text } from '@pixi/react';
import { Graphics as PixiGraphics } from '@pixi/graphics';
import { MouseEvent, WheelEvent, useCallback, useEffect, useState } from 'react';
import TileControls, { EditTool, Tool, defaultColors } from './TileControls';
import { Box } from '@mantine/core';
import { TextStyle } from 'pixi.js';
interface SquareEdit {
x: number;
@@ -31,21 +32,21 @@ export default function TileGrid() {
useEffect(() => {
if (window) {
window.addEventListener(
'wheel',
(event) => {
event.preventDefault();
},
{ passive: false }
);
// Disable right click context menu
window.addEventListener(
'contextmenu',
(event) => {
event.preventDefault();
},
{ passive: false }
);
// window.addEventListener(
// 'wheel',
// (event) => {
// event.preventDefault();
// },
// { passive: false }
// );
// // Disable right click context menu
// window.addEventListener(
// 'contextmenu',
// (event) => {
// event.preventDefault();
// },
// { passive: false }
// );
}
}, []);
@@ -73,20 +74,39 @@ export default function TileGrid() {
g.endFill();
});
},
[edits]
[edits, zoom]
);
function clickEvent(e: MouseEvent) {
setMouseDown(true);
setLastPosition({ x: e.clientX, y: e.clientY });
if (tool == Tool.ZOOM) {
handleZoom(e.button === 0 ? -100 : 100);
handleZoom(e.button === 0 ? -100 : 100, e.clientX, e.clientY);
} else if (tool == Tool.EDIT) {
if (editTool === EditTool.SQUARE) {
drawSquare(e.button, e.clientX, e.clientY);
} else if (editTool === EditTool.CIRCLE) {
// handle circle
}
}
}
function drawSquare(button: number, clientX: number, clientY: number) {
// Calculate tile coordinates
const x = Math.floor((clientX - position.x) / (32 * zoom));
const y = Math.floor((clientY - position.y) / (32 * zoom));
if (button === 1) {
// Add new edit if left mouse button is pressed
setEdits([...edits, { x, y, color: colors[selectedColor] }]);
} else if (button == 2) {
// Remove edit if right mouse button is pressed
setEdits(edits.filter((edit) => edit.x !== x || edit.y !== y));
}
}
function moveEvent(e: MouseEvent) {
if (mouseDown) {
if (tool == Tool.HAND) {
if (tool == Tool.HAND || e.buttons == 4) {
let dx = position.x + e.clientX - lastPosition.x;
let dy = position.y + e.clientY - lastPosition.y;
// Prevent coordinates from going out of bounds
@@ -98,18 +118,7 @@ export default function TileGrid() {
setLastPosition({ x: e.clientX, y: e.clientY });
} else if (tool === Tool.EDIT) {
if (editTool === EditTool.SQUARE) {
// Calculate tile coordinates
const x = Math.floor((e.clientX - position.x) / (32 * zoom));
const y = Math.floor((e.clientY - position.y - 64) / (32 * zoom));
// Check if tile is already edited, and remove it
const index = edits.findIndex((edit) => edit.x === x && edit.y === y);
if (index !== -1) {
setEdits([...edits.slice(0, index), ...edits.slice(index + 1)]);
}
// Add new edit if left mouse button is pressed
if (e.buttons === 1) {
setEdits([...edits, { x, y, color: colors[selectedColor] }]);
}
drawSquare(e.buttons, e.clientX, e.clientY);
} else if (editTool === EditTool.CIRCLE) {
// handle circle
}
@@ -120,10 +129,10 @@ export default function TileGrid() {
}
function zoomEvent(e: WheelEvent) {
handleZoom(e.deltaY);
handleZoom(e.deltaY, e.clientX, e.clientY);
}
function handleZoom(delta: number) {
function handleZoom(delta: number, clientX: number, clientY: number) {
let newZoom = zoom;
if (delta > 0) {
newZoom = zoom / 1.1;
@@ -132,7 +141,12 @@ export default function TileGrid() {
}
newZoom = Math.min(newZoom, 3);
newZoom = Math.max(newZoom, 0.6);
console.log(newZoom);
setZoom(newZoom);
// Adjust position to zoom in on mouse position
const dx = (position.x - clientX) * (newZoom / zoom) + clientX;
const dy = (position.y - clientY) * (newZoom / zoom) + clientY;
setPosition({ x: dx, y: dy });
}
return (