(
7 | ({ ...baseProps }, ref): JSX.Element => ,
8 | );
9 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/stack/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Stack' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiStack = {
8 | variants: [],
9 | };
10 | };
11 |
12 | export default injectTheme;
13 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20230919224026_pubsheet_cascade_delete/migration.sql:
--------------------------------------------------------------------------------
1 | -- DropForeignKey
2 | ALTER TABLE "PublishedSheet" DROP CONSTRAINT "PublishedSheet_rulesetId_fkey";
3 |
4 | -- AddForeignKey
5 | ALTER TABLE "PublishedSheet" ADD CONSTRAINT "PublishedSheet_rulesetId_fkey" FOREIGN KEY ("rulesetId") REFERENCES "PublishedRuleset"("id") ON DELETE CASCADE ON UPDATE CASCADE;
6 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/assets/discord-icon.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import DiscordImage from './discord-icon.png';
3 |
4 | interface DiscordIconProps {
5 | style?: React.CSSProperties;
6 | }
7 |
8 | export const DiscordIcon = ({ style }: DiscordIconProps) => {
9 | return
;
10 | };
11 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/composites/color-picker.css:
--------------------------------------------------------------------------------
1 | .color-picker-input {
2 | display: block;
3 | box-sizing: border-box;
4 | width: 90px;
5 | margin: 20px 55px 0;
6 | padding: 6px;
7 | border: 1px solid #ddd;
8 | border-radius: 4px;
9 | background: #eee;
10 | outline: none;
11 | font: inherit;
12 | text-transform: uppercase;
13 | text-align: center;
14 | }
15 |
--------------------------------------------------------------------------------
/client/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | verbose: true,
3 | setupFilesAfterEnv: ['./setupTests.ts'],
4 | projects: [
5 | {
6 | preset: 'ts-jest',
7 | testEnvironment: 'node',
8 | displayName: 'api',
9 | setupFilesAfterEnv: ['./packages/compass-api/setupTests.ts'],
10 | testMatch: ['/packages/compass-api/**/*.test.tsx'],
11 | },
12 | ],
13 | };
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/icon-button/index.tsx:
--------------------------------------------------------------------------------
1 | import MUIIconButton, { IconButtonProps as MUIIconButtonProps } from '@mui/material/IconButton';
2 |
3 | import type { JSX } from "react";
4 |
5 | export type IconButtonProps = MUIIconButtonProps;
6 |
7 | export const IconButton = ({ ...baseProps }: IconButtonProps): JSX.Element => (
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/v2/ui/skeleton.tsx:
--------------------------------------------------------------------------------
1 | import { cn } from '@/libs/compass-core-ui/utils';
2 |
3 | function Skeleton({ className, ...props }: React.ComponentProps<'div'>) {
4 | return (
5 |
10 | );
11 | }
12 |
13 | export { Skeleton };
14 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20231010183105_official_content_unique_entity_id/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - A unique constraint covering the columns `[entityId]` on the table `OfficialContent` will be added. If there are existing duplicate values, this will fail.
5 |
6 | */
7 | -- CreateIndex
8 | CREATE UNIQUE INDEX "OfficialContent_entityId_key" ON "OfficialContent"("entityId");
9 |
--------------------------------------------------------------------------------
/server/src/infrastructure/rest/services/email/email-templates.ts:
--------------------------------------------------------------------------------
1 | export const sharedRuleset = ({
2 | username,
3 | rulesetTitle,
4 | }: {
5 | username: string;
6 | rulesetTitle?: string;
7 | }) => `
8 | ${username} has shared ${rulesetTitle ?? 'a ruleset'} with you.
9 | Login to add the ruleset to your shelf.
10 | `;
11 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/assets/instagram-icon.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import InstagramImage from './instagram-icon.png';
3 |
4 | interface InstagramIconProps {
5 | style?: React.CSSProperties;
6 | }
7 |
8 | export const InstagramIcon = ({ style }: InstagramIconProps) => {
9 | return
;
10 | };
11 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/breadcrumbs/index.tsx:
--------------------------------------------------------------------------------
1 | import MUIBreadcrumbs, { BreadcrumbsProps as MUIBreadcrumbsProps } from '@mui/material/Breadcrumbs';
2 |
3 | import type { JSX } from "react";
4 |
5 | export type BreadcrumbsProps = MUIBreadcrumbsProps;
6 |
7 | export const Breadcrumbs = ({ ...baseProps }: BreadcrumbsProps): JSX.Element => (
8 |
9 | );
10 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/composites/loading.tsx:
--------------------------------------------------------------------------------
1 | import { AnimatedMonogram } from '../animations';
2 | import { Stack } from '../components';
3 |
4 | import type { JSX } from "react";
5 |
6 | export const Loading = (): JSX.Element => {
7 | return (
8 |
9 |
10 |
11 | );
12 | };
13 |
--------------------------------------------------------------------------------
/server/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:23.5.0
2 | WORKDIR server/build
3 | COPY package*.json ./
4 |
5 | RUN npm install
6 | COPY . .
7 | RUN npm run build:docker
8 | COPY . .
9 |
10 |
11 | RUN mkdir ./dist/storage
12 | RUN mkdir ./dist/storage/images
13 | RUN mkdir ./dist/storage/charts
14 | RUN mkdir ./dist/storage/documents
15 | RUN mkdir ./dist/storage/uploads
16 |
17 | EXPOSE 8000
18 | CMD ["npm", "run", "start:docker"]
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/tooltip/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Tooltip' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiTooltip = {
8 | variants: [],
9 | styleOverrides: {},
10 | };
11 | };
12 |
13 | export default injectTheme;
14 |
--------------------------------------------------------------------------------
/client/src/pages/ruleset/attributes/attribute-store/attribute-store.ts:
--------------------------------------------------------------------------------
1 | import { ContextualAttribute, ContextualItem } from '@/libs/compass-api';
2 | import { create } from 'zustand';
3 |
4 | type AttributeStore = {
5 | attributes: ContextualAttribute[];
6 | items: ContextualItem[];
7 | };
8 |
9 | export const useAttributeStore = create()((set) => ({
10 | attributes: [],
11 | items: [],
12 | }));
13 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/gql/mutations/index.ts:
--------------------------------------------------------------------------------
1 | export * from './archetypes';
2 | export * from './attributes';
3 | export * from './characters';
4 | export * from './charts';
5 | export * from './components';
6 | export * from './documents';
7 | export * from './items';
8 | export * from './pages';
9 | export * from './rulesets';
10 | export * from './sheets';
11 | export * from './storage';
12 | export * from './users';
13 |
--------------------------------------------------------------------------------
/client/src/types.ts:
--------------------------------------------------------------------------------
1 | import { TreeItem } from '@/libs/compass-core-composites';
2 |
3 | export type RulesetEntity =
4 | | 'sheet-templates'
5 | | 'page-templates'
6 | | 'charts'
7 | | 'attributes'
8 | | 'archetypes'
9 | | 'documents'
10 | | 'items';
11 |
12 | export type PageTreeItem = Omit & {
13 | parentId: string | null;
14 | sortIndex: number;
15 | children: PageTreeItem[];
16 | };
17 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20230919173309_remove_pubrs_user/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - You are about to drop the column `userId` on the `PublishedRuleset` table. All the data in the column will be lost.
5 |
6 | */
7 | -- DropForeignKey
8 | ALTER TABLE "PublishedRuleset" DROP CONSTRAINT "PublishedRuleset_userId_fkey";
9 |
10 | -- AlterTable
11 | ALTER TABLE "PublishedRuleset" DROP COLUMN "userId";
12 |
--------------------------------------------------------------------------------
/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Quest Bound
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/gql/queries/index.ts:
--------------------------------------------------------------------------------
1 | export * from './archetypes';
2 | export * from './attributes';
3 | export * from './characters';
4 | export * from './charts';
5 | export * from './components';
6 | export * from './documents';
7 | export * from './official-content';
8 | export * from './pages';
9 | export * from './rulesets';
10 | export * from './sheets';
11 | export * from './storage';
12 | export * from './users';
13 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/fab/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassDarkTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Fab' {}
5 |
6 | const injectTheme = (): void => {
7 | compassDarkTheme.components.MuiFab = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/composites/page.tsx:
--------------------------------------------------------------------------------
1 | import { CSSProperties, ReactNode } from 'react';
2 | import { Stack } from '../components';
3 |
4 | interface PageProps {
5 | children: ReactNode;
6 | style?: CSSProperties;
7 | }
8 |
9 | export const Page = ({ children, style }: PageProps) => {
10 | return (
11 |
12 | {children}
13 |
14 | );
15 | };
16 |
--------------------------------------------------------------------------------
/client/src/pages/navigation/components/client-side-link.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, LinkProps } from 'react-router-dom';
3 |
4 | /**
5 | * Pass to Button to render an as tag and use React Router.
6 | */
7 | export const ClientSideLink = React.forwardRef<
8 | HTMLAnchorElement,
9 | Omit & { href: LinkProps['to'] }
10 | >((props, ref) => );
11 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20231018161520_module_permissions/migration.sql:
--------------------------------------------------------------------------------
1 | -- AlterTable
2 | ALTER TABLE "PublishedRuleset" ADD COLUMN "modulePermissions" JSONB NOT NULL DEFAULT '{}',
3 | ADD COLUMN "rulesetPermissions" JSONB NOT NULL DEFAULT '{}';
4 |
5 | -- AlterTable
6 | ALTER TABLE "Ruleset" ADD COLUMN "modulePermissions" JSONB NOT NULL DEFAULT '{}',
7 | ADD COLUMN "rulesetPermissions" JSONB NOT NULL DEFAULT '{}';
8 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/providers/rulebook-provider.tsx:
--------------------------------------------------------------------------------
1 | import { Document, Page, pdfjs } from 'react-pdf';
2 | import 'react-pdf/dist/Page/AnnotationLayer.css';
3 | import 'react-pdf/dist/Page/TextLayer.css';
4 |
5 | pdfjs.GlobalWorkerOptions.workerSrc = new URL(
6 | 'pdfjs-dist/build/pdf.worker.min.js',
7 | import.meta.url,
8 | ).toString();
9 |
10 | export { Document as RulebookDocumentContext, Page as RulebookDocumentPage };
11 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/assets/logo-b.tsx:
--------------------------------------------------------------------------------
1 | import { CSSProperties } from 'react';
2 | import LogoBSvg from './qb-b.svg';
3 |
4 | interface LogoProps {
5 | style?: CSSProperties;
6 | }
7 |
8 | export const LogoB = ({ style }: LogoProps) => {
9 | return (
10 |
15 | );
16 | };
17 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/assets/logo-q.tsx:
--------------------------------------------------------------------------------
1 | import { CSSProperties } from 'react';
2 | import LogoQSvg from './qb-q.svg';
3 |
4 | interface LogoProps {
5 | style?: CSSProperties;
6 | }
7 |
8 | export const LogoQ = ({ style }: LogoProps) => {
9 | return (
10 |
15 | );
16 | };
17 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/chip/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Chip' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiChip = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/link/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Link' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiLink = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-composites/composites/client-side-link.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Link, LinkProps } from 'react-router-dom';
3 |
4 | /**
5 | * Pass to Button to render an as tag and use React Router.
6 | */
7 | export const ClientSideLink = React.forwardRef<
8 | HTMLAnchorElement,
9 | Omit & { href: LinkProps['to'] }
10 | >((props, ref) => );
11 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-composites/composites/index.ts:
--------------------------------------------------------------------------------
1 | export * from './client-side-link';
2 | export * from './editable-text';
3 | export * from './entity-card';
4 | export * from './file-upload';
5 | export * from './grid';
6 | export * from './icon-color-picker';
7 | export * from './image-gallery';
8 | export * from './notification';
9 | export * from './rulesets';
10 | export * from './sheets';
11 | export * from './sortable-tree';
12 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/assets/logo-dark.tsx:
--------------------------------------------------------------------------------
1 | import { CSSProperties } from 'react';
2 | import LogoDarkSvg from './logo-dark.svg';
3 |
4 | interface LogoProps {
5 | style?: CSSProperties;
6 | }
7 |
8 | export const LogoDark = ({ style }: LogoProps) => {
9 | return (
10 |
15 | );
16 | };
17 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/assets/logo-text.tsx:
--------------------------------------------------------------------------------
1 | import { CSSProperties } from 'react';
2 | import LogoTextSvg from './qb-text.svg';
3 |
4 | interface LogoProps {
5 | style?: CSSProperties;
6 | }
7 |
8 | export const LogoText = ({ style }: LogoProps) => {
9 | return (
10 |
15 | );
16 | };
17 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/paper/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Paper' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiPaper = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/slider/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassDarkTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Slider' {}
5 |
6 | const injectTheme = (): void => {
7 | compassDarkTheme.components.MuiSlider = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/drawer/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Drawer' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiDrawer = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/snackbar/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassDarkTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Snackbar' {}
5 |
6 | const injectTheme = (): void => {
7 | compassDarkTheme.components.MuiSnackbar = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/toolbar/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Toolbar' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiToolbar = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/backdrop/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Backdrop' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiBackdrop = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/skeleton/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Skeleton' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiSkeleton = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/limits.ts:
--------------------------------------------------------------------------------
1 | import { ResourceLimit } from '../types';
2 |
3 | export const freeLimits = new Map([
4 | [ResourceLimit.CHARACTER, 1],
5 | [ResourceLimit.PLAYER, 5],
6 | [ResourceLimit.RULESET, 1],
7 | [ResourceLimit.PUBLICATION, 0],
8 | ]);
9 |
10 | export const creatorLimits = new Map([
11 | [ResourceLimit.PLAYER, 15],
12 | [ResourceLimit.PUBLICATION, 1],
13 | ]);
14 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/speed-dial/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/SpeedDial' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiSpeedDial = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-planes/common/hooks/use-selections.ts:
--------------------------------------------------------------------------------
1 | import { SheetComponent } from '@/libs/compass-api';
2 | import { useNodes } from 'reactflow';
3 |
4 | export const useSelections = (components: SheetComponent[]) => {
5 | const nodes = useNodes();
6 | const selectedNodes = nodes.filter((node) => node.selected);
7 |
8 | return {
9 | selectedComponents: components.filter((c) => selectedNodes.some((n) => n.id === c.id)),
10 | };
11 | };
12 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/autocomplete/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Autocomplete' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiAutocomplete = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/breadcrumbs/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Breadcrumbs' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiBreadcrumbs = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/progress/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/LinearProgress' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiLinearProgress = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/v2/ui/spinner.tsx:
--------------------------------------------------------------------------------
1 | import { Loader2Icon } from 'lucide-react';
2 |
3 | import { cn } from '@/libs/compass-core-ui/utils';
4 |
5 | function Spinner({ className, ...props }: React.ComponentProps<'svg'>) {
6 | return (
7 |
13 | );
14 | }
15 |
16 | export { Spinner };
17 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20231005184900_official_content/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "OfficialContent" (
3 | "id" TEXT NOT NULL,
4 | "title" TEXT NOT NULL,
5 | "key" TEXT NOT NULL,
6 | "type" TEXT NOT NULL,
7 | "entityId" TEXT NOT NULL,
8 |
9 | CONSTRAINT "OfficialContent_pkey" PRIMARY KEY ("id")
10 | );
11 |
12 | -- CreateIndex
13 | CREATE UNIQUE INDEX "OfficialContent_key_key" ON "OfficialContent"("key");
14 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/index.ts:
--------------------------------------------------------------------------------
1 | export * from './test-connection';
2 | export * from './user';
3 | export * from './image';
4 | export * from './rulesets';
5 | export * from './archetype';
6 | export * from './attribute';
7 | export * from './character';
8 | export * from './chart';
9 | export * from './component';
10 | export * from './document';
11 | export * from './page';
12 | export * from './sheet';
13 | export * from './subscriptions';
14 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/loader/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/CircularProgress' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiCircularProgress = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {},
11 | },
12 | };
13 | };
14 |
15 | export default injectTheme;
16 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/user/index.ts:
--------------------------------------------------------------------------------
1 | import { currentUser } from './current-user';
2 | import { earlyAccessUser } from './early-access-user';
3 | import { searchUsers } from './search-users';
4 | import { updateCurrentUser } from './update-current-user';
5 |
6 | export const userResolvers = {
7 | Query: {
8 | currentUser,
9 | earlyAccessUser,
10 | searchUsers,
11 | },
12 | Mutation: {
13 | updateCurrentUser,
14 | },
15 | };
16 |
--------------------------------------------------------------------------------
/client/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:23.5.0
2 |
3 | # Set the working directory inside the container
4 | WORKDIR /build
5 |
6 | # Copy package.json and package-lock.json
7 | COPY package*.json ./
8 |
9 | # Install dependencies
10 | RUN npm install
11 |
12 | # Copy the rest of your application files
13 | COPY . .
14 |
15 | RUN npm run build
16 |
17 | # Expose the port your app runs on
18 | EXPOSE 5173
19 |
20 | # Define the command to run your app
21 | CMD ["npm", "run", "start"]
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/assets/logo-icon.tsx:
--------------------------------------------------------------------------------
1 | import { CSSProperties } from 'react';
2 | import LogoIconSvg from './qb-monogram.svg';
3 |
4 | interface LogoProps {
5 | style?: CSSProperties;
6 | }
7 |
8 | export const LogoIcon = ({ style }: LogoProps) => {
9 | return (
10 |
15 | );
16 | };
17 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/snackbar/index.tsx:
--------------------------------------------------------------------------------
1 | import MUISnackbar, { SnackbarProps as MUISnackbarProps } from '@mui/material/Snackbar';
2 | import { motion } from 'framer-motion';
3 | import { forwardRef } from 'react';
4 |
5 | export type SnackbarProps = MUISnackbarProps;
6 |
7 | const AnimatedSnackbar = forwardRef((props: SnackbarProps, ref) => (
8 |
9 | ));
10 |
11 | export const Snackbar = motion(AnimatedSnackbar);
12 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20251213160508_prisma_update/migration.sql:
--------------------------------------------------------------------------------
1 | -- AlterTable
2 | ALTER TABLE "_PublishedRulesetModules" ADD CONSTRAINT "_PublishedRulesetModules_AB_pkey" PRIMARY KEY ("A", "B");
3 |
4 | -- DropIndex
5 | DROP INDEX "_PublishedRulesetModules_AB_unique";
6 |
7 | -- AlterTable
8 | ALTER TABLE "_RulesetModules" ADD CONSTRAINT "_RulesetModules_AB_pkey" PRIMARY KEY ("A", "B");
9 |
10 | -- DropIndex
11 | DROP INDEX "_RulesetModules_AB_unique";
12 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/components/sign-up-form/form-validation.ts:
--------------------------------------------------------------------------------
1 | import * as yup from 'yup';
2 |
3 | export type FormValues = {
4 | email: string;
5 | password?: string;
6 | token: string;
7 | };
8 |
9 | export const initialValues: FormValues = {
10 | email: '',
11 | password: '',
12 | token: '',
13 | };
14 |
15 | export const signUpValidationSchema = yup.object({
16 | email: yup.string().email('Enter a valid email').required('Email is required'),
17 | });
18 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/chart/index.ts:
--------------------------------------------------------------------------------
1 | import { chart } from './chart';
2 | import { charts } from './charts';
3 | import { createChart } from './create-chart';
4 | import { deleteChart } from './delete-chart';
5 | import { updateChart } from './update-chart';
6 |
7 | export const chartResolvers = {
8 | Query: {
9 | charts,
10 | chart,
11 | },
12 | Mutation: {
13 | createChart,
14 | updateChart,
15 | deleteChart,
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/server/src/infrastructure/rest/services/metrics/index.ts:
--------------------------------------------------------------------------------
1 | import { Express } from 'express';
2 | import { buildRestfulRoutes } from '@helpers/build-restful-route';
3 | import { metricsProxy } from './proxy';
4 |
5 | export const initializeMetricsEndpoints = (app: Express) => {
6 | buildRestfulRoutes([
7 | {
8 | app,
9 | path: 'metrics',
10 | method: 'post',
11 | authRequired: false,
12 | handler: metricsProxy,
13 | },
14 | ]);
15 | };
16 |
--------------------------------------------------------------------------------
/server/src/infrastructure/rest/services/storage/bootstrap-storage.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import path from 'path';
3 |
4 | const storageDir = path.join(__dirname.split('server')[0], 'server', 'dist', 'storage');
5 |
6 | if (!fs.existsSync(storageDir)) {
7 | fs.mkdirSync(storageDir);
8 | fs.mkdirSync(`${storageDir}/uploads`);
9 | fs.mkdirSync(`${storageDir}/documents`);
10 | fs.mkdirSync(`${storageDir}/images`);
11 | fs.mkdirSync(`${storageDir}/charts`);
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/components/sign-up-form/social-links.tsx:
--------------------------------------------------------------------------------
1 | import { Stack } from '@/libs/compass-core-ui';
2 | import React from 'react';
3 | import { JoinDiscord } from './join-discord';
4 |
5 | interface SocialLinksProps {
6 | style?: React.CSSProperties;
7 | }
8 |
9 | export const SocialLinks = ({ style }: SocialLinksProps) => (
10 |
11 |
12 |
13 | );
14 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/text/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassDarkTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Typography' {}
5 |
6 | const injectTheme = (): void => {
7 | compassDarkTheme.components.MuiTypography = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {
11 | color: 'inherit',
12 | },
13 | },
14 | };
15 | };
16 |
17 | export default injectTheme;
18 |
--------------------------------------------------------------------------------
/client/src/libs/compass-planes/common/components/edit-bar/edit-actions/index.ts:
--------------------------------------------------------------------------------
1 | export * from './announcement-edit';
2 | export * from './archetype-edit';
3 | export * from './box-edit';
4 | export * from './chart-edit';
5 | export * from './checkbox-edit';
6 | export * from './css-edit';
7 | export * from './image-edit';
8 | export * from './input-edit';
9 | export * from './inventory-edit';
10 | export * from './layer-edit';
11 | export * from './pdf-edit';
12 | export * from './text-edit';
13 |
--------------------------------------------------------------------------------
/server/src/infrastructure/rest/services/email/types.ts:
--------------------------------------------------------------------------------
1 | export type EmailOctopusEmailResponse = {
2 | email_address: string;
3 | id: string;
4 | fields: {
5 | email_address: string;
6 | };
7 | tags: string[];
8 | };
9 |
10 | export type EmailOctopusResponse = {
11 | data: EmailOctopusEmailResponse[];
12 | };
13 |
14 | export type Subscriber = {
15 | memberId: string;
16 | email: string;
17 | free: boolean;
18 | creator: boolean;
19 | ignoreUpdates: boolean;
20 | };
21 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/image/index.ts:
--------------------------------------------------------------------------------
1 | import { createImage } from './create-image';
2 | import { deleteImage } from './delete-image';
3 | import { images } from './images';
4 | import { updateImage } from './update-image';
5 | import { updateImages } from './update-images';
6 |
7 | export const imageResolvers = {
8 | Query: {
9 | images,
10 | },
11 | Mutation: {
12 | createImage,
13 | updateImage,
14 | updateImages,
15 | deleteImage,
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/client/src/pages/ruleset/attributes/attribute-store/evaluation/evaluation-functions/index.ts:
--------------------------------------------------------------------------------
1 | export * from './action';
2 | export * from './boolean';
3 | export * from './chart';
4 | export * from './comparison';
5 | export * from './dice';
6 | export * from './get-item';
7 | export * from './if';
8 | export * from './inventory';
9 | export * from './math';
10 | export * from './not';
11 | export * from './return';
12 | export * from './set';
13 | export * from './utils';
14 | export * from './variable';
15 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/sheet/index.ts:
--------------------------------------------------------------------------------
1 | import { createSheet } from './create-sheet';
2 | import { deleteSheet } from './delete-sheet';
3 | import { sheet } from './sheet';
4 | import { sheetTemplates } from './sheet-templates';
5 | import { updateSheet } from './update-sheet';
6 |
7 | export const sheetResolvers = {
8 | Query: {
9 | sheet,
10 | sheetTemplates,
11 | },
12 | Mutation: {
13 | createSheet,
14 | updateSheet,
15 | deleteSheet,
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/server/src/infrastructure/rest/services/import-export/index.ts:
--------------------------------------------------------------------------------
1 | import { Express } from 'express';
2 | import { buildRestfulRoutes } from '@helpers/build-restful-route';
3 | import { importAttributes } from './import';
4 |
5 | export const initializeImportExportEndpoints = (app: Express) => {
6 | buildRestfulRoutes([
7 | {
8 | app,
9 | path: 'import/attributes',
10 | method: 'post',
11 | authRequired: true,
12 | handler: importAttributes,
13 | },
14 | ]);
15 | };
16 |
--------------------------------------------------------------------------------
/server/src/infrastructure/rest/services/signin/index.ts:
--------------------------------------------------------------------------------
1 | import { buildRestfulRoutes } from '@/infrastructure/server-helpers/build-restful-route';
2 | import { loginOrSignup } from './login-or-signup';
3 | import { Express } from 'express';
4 |
5 | export const initializeSigninEndpoints = (app: Express) => {
6 | buildRestfulRoutes([
7 | {
8 | app,
9 | path: 'signup',
10 | method: 'post',
11 | authRequired: false,
12 | handler: loginOrSignup,
13 | },
14 | ]);
15 | };
16 |
--------------------------------------------------------------------------------
/server/src/infrastructure/rest/services/storage/index.ts:
--------------------------------------------------------------------------------
1 | import { buildRestfulRoutes } from '@/infrastructure/server-helpers/build-restful-route';
2 | import { Express } from 'express';
3 | import { uploadFile } from './file-upload';
4 |
5 | export const initializeStorageEndpoints = (app: Express) => {
6 | buildRestfulRoutes([
7 | {
8 | app,
9 | path: 'storage/upload',
10 | method: 'upload',
11 | handler: uploadFile,
12 | authRequired: false,
13 | },
14 | ]);
15 | };
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/avatar/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassDarkTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Avatar' {}
5 |
6 | const injectTheme = (): void => {
7 | compassDarkTheme.components.MuiAvatar = {
8 | variants: [],
9 | defaultProps: {
10 | variant: 'rounded',
11 | },
12 | styleOverrides: {
13 | root: {},
14 | },
15 | };
16 | };
17 |
18 | export default injectTheme;
19 |
--------------------------------------------------------------------------------
/client/src/pages/ruleset/attributes/attribute-store/evaluation/evaluation-functions/return.ts:
--------------------------------------------------------------------------------
1 | import { Logic, Operation } from '@/libs/compass-planes';
2 | import { clampValueToAttributeMinMax, getValueOfInputIfShouldExecute } from './utils';
3 |
4 | export function evaluateReturnOperation(operation: Operation, logic: Logic) {
5 | const shouldInverse = operation.data?.inverse;
6 | const value = getValueOfInputIfShouldExecute(operation, logic, shouldInverse);
7 | return clampValueToAttributeMinMax(value, logic);
8 | }
9 |
--------------------------------------------------------------------------------
/client/buildspec.yml:
--------------------------------------------------------------------------------
1 | version: 0.2
2 |
3 | phases:
4 | install:
5 | runtime-versions:
6 | nodejs: 18
7 | commands:
8 | - npm i @nrwl/nx-linux-x64-gnu && npm install
9 | build:
10 | on-failure: ABORT
11 | commands:
12 | - npm run build
13 | post_build:
14 | commands:
15 | - aws cloudfront create-invalidation --distribution-id $CLOUDFRONT_DISTRIBUTION_ID --paths '/*'
16 | artifacts:
17 | enable-symlinks: yes
18 | base-directory: 'dist'
19 | files:
20 | - '**/*'
21 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export * from './archetypes';
2 | export * from './attributes';
3 | export * from './characters';
4 | export * from './charts';
5 | export * from './components';
6 | export * from './dddice';
7 | export * from './documents';
8 | export * from './email';
9 | export * from './metrics';
10 | export * from './official-content';
11 | export * from './pages';
12 | export * from './rulesets';
13 | export * from './sheets';
14 | export * from './storage';
15 | export * from './user';
16 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature Request
3 | about: Suggest a feature for this project
4 | title: ''
5 | labels: Feature Request
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem?**
11 | Use the Bug Report or Improvement template instead.
12 |
13 | **Describe the feature you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Additional context**
17 | Add any other context or screenshots about the feature request here.
18 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/gql/queries/documents.ts:
--------------------------------------------------------------------------------
1 | import { gql } from '@apollo/client/core/index.js';
2 |
3 | export const documents = gql`
4 | query Documents($rulesetId: String!) {
5 | documents(rulesetId: $rulesetId) {
6 | id
7 | rulesetId
8 | title
9 | }
10 | }
11 | `;
12 |
13 | export const document = gql`
14 | query Document($input: GetEntity!) {
15 | document(input: $input) {
16 | id
17 | rulesetId
18 | title
19 | fileKey
20 | }
21 | }
22 | `;
23 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/divider/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassDarkTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Divider' {}
5 |
6 | const injectTheme = (): void => {
7 | compassDarkTheme.components.MuiDivider = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {
11 | borderColor: compassDarkTheme.palette.primary.light,
12 | },
13 | },
14 | };
15 | };
16 |
17 | export default injectTheme;
18 |
--------------------------------------------------------------------------------
/server/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: '@typescript-eslint/parser',
4 | ignorePatterns: ['.eslintrc.js'],
5 | plugins: ['@typescript-eslint'],
6 | extends: ['plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
7 | rules: {
8 | 'no-console': ['error', { allow: ['warn', 'error', 'debug'] }],
9 | '@typescript-eslint/no-unused-vars': 'error',
10 | 'arrow-body-style': 'error',
11 | },
12 | parserOptions: {
13 | sourceType: 'module',
14 | },
15 | };
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/utils/base-props.ts:
--------------------------------------------------------------------------------
1 | import { SxProps } from '@mui/material';
2 | import { CSSProperties } from 'react';
3 |
4 | export interface BaseProps {
5 | id?: string;
6 |
7 | className?: string;
8 |
9 | style?: CSSProperties;
10 |
11 | 'data-testid'?: string;
12 |
13 | 'aria-label'?: string;
14 |
15 | 'aria-live'?: 'off' | 'assertive' | 'polite';
16 |
17 | 'aria-labelledby'?: string;
18 |
19 | 'aria-describedby'?: string;
20 |
21 | role?: string;
22 |
23 | sx?: SxProps;
24 | }
25 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/component/index.ts:
--------------------------------------------------------------------------------
1 | import { sheetComponents } from './components';
2 | import { createSheetComponents } from './create-components';
3 | import { deleteSheetComponents } from './delete-components';
4 | import { updateSheetComponents } from './update-components';
5 |
6 | export const componentResolvers = {
7 | Query: {
8 | sheetComponents,
9 | },
10 | Mutation: {
11 | createSheetComponents,
12 | updateSheetComponents,
13 | deleteSheetComponents,
14 | },
15 | };
16 |
--------------------------------------------------------------------------------
/client/src/components/log-panel/log-panel-button.tsx:
--------------------------------------------------------------------------------
1 | import { IconButton, Tooltip } from '@/libs/compass-core-ui';
2 | import { useEventLog } from '@/stores';
3 | import { ReceiptLong } from '@mui/icons-material';
4 |
5 | export const LogPanelButton = () => {
6 | const { setLogPanelOpen } = useEventLog();
7 |
8 | return (
9 |
10 | setLogPanelOpen(true)}>
11 |
12 |
13 |
14 | );
15 | };
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/tabs/index.tsx:
--------------------------------------------------------------------------------
1 | import MUITab, { TabProps as MUITabProps } from '@mui/material/Tab';
2 | import MUITabs, { TabsProps as MUITabsProps } from '@mui/material/Tabs';
3 |
4 | import type { JSX } from "react";
5 |
6 | export type TabsProps = MUITabsProps;
7 | export type TabProps = MUITabProps;
8 |
9 | export const Tabs = ({ ...baseProps }: TabsProps): JSX.Element => ;
10 |
11 | export const Tab = ({ ...baseProps }: TabProps): JSX.Element => ;
12 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20230920172108_/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - Added the required column `userId` to the `PublishedRuleset` table without a default value. This is not possible if the table is not empty.
5 | - Added the required column `username` to the `PublishedRuleset` table without a default value. This is not possible if the table is not empty.
6 |
7 | */
8 | -- AlterTable
9 | ALTER TABLE "PublishedRuleset" ADD COLUMN "userId" TEXT NOT NULL,
10 | ADD COLUMN "username" TEXT NOT NULL;
11 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/dialog/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassDarkTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Dialog' {}
5 |
6 | const injectTheme = (): void => {
7 | compassDarkTheme.components.MuiDialog = {
8 | variants: [],
9 | styleOverrides: {
10 | root: {
11 | '& .MuiPaper-root': {
12 | maxWidth: '100%',
13 | },
14 | },
15 | },
16 | };
17 | };
18 |
19 | export default injectTheme;
20 |
--------------------------------------------------------------------------------
/client/src/libs/compass-planes/common/hooks/use-node-size.ts:
--------------------------------------------------------------------------------
1 | import { useMemo } from 'react';
2 | import { useReactFlow } from 'reactflow';
3 |
4 | export const useNodeSize = (id?: string) => {
5 | const reactFlow = useReactFlow();
6 | const node = reactFlow.getNode(id ?? '');
7 |
8 | const height = useMemo(() => node?.height ?? 0, [node]);
9 | const width = useMemo(() => node?.width ?? 0, [node]);
10 |
11 | return {
12 | height: height ? `${height}px` : '',
13 | width: width ? `${width}px` : '',
14 | };
15 | };
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-planes/common/nodes/canvas-node/player-canvas-node.css:
--------------------------------------------------------------------------------
1 | .player-canvas-node .excalidraw.theme--dark {
2 | --theme-filter: none;
3 | }
4 |
5 | .player-canvas-node .excalidraw {
6 | border-radius: inherit;
7 | }
8 |
9 |
10 | .player-canvas-node .excalidraw .App-top-bar {
11 | display: none !important;
12 | }
13 |
14 | .player-canvas-node .excalidraw .App-toolbar-content {
15 | display: none !important;
16 | }
17 |
18 | .player-canvas-node .excalidraw .App-menu {
19 | display: none !important;
20 | }
21 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/types/apollo.ts:
--------------------------------------------------------------------------------
1 | import { MutationFetchPolicy } from '@apollo/client/core/watchQueryOptions';
2 | import { WatchQueryFetchPolicy } from '@apollo/client';
3 |
4 | export type QueryOptions = {
5 | fetchPolicy?: WatchQueryFetchPolicy;
6 | };
7 |
8 | export type MutationOptions = {
9 | fetchPolicy?: MutationFetchPolicy;
10 | };
11 |
12 | export type QueryFunction = (input: T, opts?: QueryOptions) => Promise;
13 |
14 | export type MutationFunction = (input: T, opts?: MutationOptions) => Promise;
15 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/types/planes/component-types.tsx:
--------------------------------------------------------------------------------
1 | import { baseComponentTypes, SheetComponentType } from './base-component-types';
2 | import { inventoryComponentTypes } from './inventory-component-types';
3 | import { logicComponentTypes } from './logic-component-types';
4 | import { manageComponentTypes } from './manage-component-types';
5 |
6 | export const componentTypes: SheetComponentType[] = [
7 | ...baseComponentTypes,
8 | ...logicComponentTypes,
9 | ...manageComponentTypes,
10 | ...inventoryComponentTypes,
11 | ];
12 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/app-bar/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassDarkTheme, compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/AppBar' {}
5 |
6 | const injectTheme = (): void => {
7 | [compassLightTheme, compassDarkTheme].forEach((theme) => {
8 | theme.components.MuiAppBar = {
9 | variants: [],
10 | styleOverrides: {
11 | root: {},
12 | },
13 | };
14 | });
15 | };
16 |
17 | export default injectTheme;
18 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/autocomplete/index.tsx:
--------------------------------------------------------------------------------
1 | import AutoComplete, {
2 | AutocompleteProps as MUIAutocompleteProps,
3 | } from '@mui/material/Autocomplete';
4 |
5 | export type AutoCompleteProps = MUIAutocompleteProps;
6 |
7 | export type AutoCompleteOption = {
8 | label: string;
9 | value: string;
10 | };
11 |
12 | export { AutoComplete };
13 |
14 | // export const AutoComplete = ({ ...baseProps }: AutoCompleteProps): JSX.Element => (
15 | //
16 | // );
17 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20240421162442_remove_item_model/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - You are about to drop the `Item` table. If the table is not empty, all the data it contains will be lost.
5 |
6 | */
7 | -- DropForeignKey
8 | ALTER TABLE "Item" DROP CONSTRAINT "Item_imageId_fkey";
9 |
10 | -- DropForeignKey
11 | ALTER TABLE "Item" DROP CONSTRAINT "Item_parentId_fkey";
12 |
13 | -- DropForeignKey
14 | ALTER TABLE "Item" DROP CONSTRAINT "Item_rulesetId_fkey";
15 |
16 | -- DropTable
17 | DROP TABLE "Item";
18 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/archetype/index.ts:
--------------------------------------------------------------------------------
1 | import { archetype } from './archetype';
2 | import { archetypes } from './archetypes';
3 | import { createArchetype } from './create-archetype';
4 | import { deleteArchetype } from './delete-archetype';
5 | import { updateArchetype } from './update-archetype';
6 |
7 | export const archetypeResolvers = {
8 | Query: {
9 | archetype,
10 | archetypes,
11 | },
12 | Mutation: {
13 | createArchetype,
14 | updateArchetype,
15 | deleteArchetype,
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/character/index.ts:
--------------------------------------------------------------------------------
1 | import { character } from './character';
2 | import { characters } from './characters';
3 | import { createCharacter } from './create-character';
4 | import { deleteCharacter } from './delete-character';
5 | import { updateCharacter } from './update-character';
6 |
7 | export const characterResolvers = {
8 | Query: {
9 | characters,
10 | character,
11 | },
12 | Mutation: {
13 | createCharacter,
14 | updateCharacter,
15 | deleteCharacter,
16 | },
17 | };
18 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/gql/queries/charts.ts:
--------------------------------------------------------------------------------
1 | import { gql } from '@apollo/client/core/index.js';
2 |
3 | export const charts = gql`
4 | query Charts($rulesetId: String!) {
5 | charts(rulesetId: $rulesetId) {
6 | id
7 | rulesetId
8 | title
9 | fileKey
10 | data
11 | }
12 | }
13 | `;
14 |
15 | export const chart = gql`
16 | query Chart($input: GetEntity!) {
17 | chart(input: $input) {
18 | id
19 | rulesetId
20 | title
21 | fileKey
22 | data
23 | }
24 | }
25 | `;
26 |
--------------------------------------------------------------------------------
/client/src/components/rulebook-loading.tsx:
--------------------------------------------------------------------------------
1 | import { Skeleton, Stack } from '@/libs/compass-core-ui';
2 |
3 | export const RulebookLoading = () => {
4 | return (
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/animations/animated-monogram.tsx:
--------------------------------------------------------------------------------
1 | import { useLottie } from 'lottie-react';
2 | import { useDeviceSize } from '../hooks';
3 | import LoadingAnimation from './loading.json';
4 |
5 | export const AnimatedMonogram = () => {
6 | const { mobile } = useDeviceSize();
7 | const style = { height: mobile ? 250 : 500, width: mobile ? 250 : 500 };
8 |
9 | const { View } = useLottie({
10 | animationData: LoadingAnimation,
11 | loop: true,
12 | autoPlay: true,
13 | style,
14 | });
15 |
16 | return View;
17 | };
18 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/tooltip/index.tsx:
--------------------------------------------------------------------------------
1 | import MUITooltip, { TooltipProps as MUITooltipProps } from '@mui/material/Tooltip';
2 | import { forwardRef, type JSX } from 'react';
3 |
4 | // export { Tooltip };
5 |
6 | export type TooltipProps = MUITooltipProps;
7 |
8 | export const Tooltip = forwardRef(
9 | ({ ...baseProps }: TooltipProps, ref): JSX.Element => (
10 |
11 | {baseProps.children}
12 |
13 | ),
14 | );
15 |
16 | Tooltip.displayName = 'Tooltip';
17 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-composites/composites/sortable-tree/types.ts:
--------------------------------------------------------------------------------
1 | import type { MutableRefObject } from 'react';
2 |
3 | export interface TreeItem {
4 | id: string;
5 | label: string;
6 | children: TreeItem[];
7 | collapsed?: boolean;
8 | hidden?: boolean;
9 | leaf?: boolean;
10 | }
11 |
12 | export interface FlattenedItem extends TreeItem {
13 | parentId: string | null;
14 | depth: number;
15 | index: number;
16 | }
17 |
18 | export type SensorContext = MutableRefObject<{
19 | items: FlattenedItem[];
20 | offset: number;
21 | }>;
22 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20230918220657_ruleset_images/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - You are about to drop the column `imageId` on the `PublishedRuleset` table. All the data in the column will be lost.
5 |
6 | */
7 | -- DropForeignKey
8 | ALTER TABLE "PublishedRuleset" DROP CONSTRAINT "PublishedRuleset_imageId_fkey";
9 |
10 | -- DropIndex
11 | DROP INDEX "PublishedRuleset_imageId_key";
12 |
13 | -- DropIndex
14 | DROP INDEX "PublishedSheet_imageId_key";
15 |
16 | -- AlterTable
17 | ALTER TABLE "PublishedRuleset" DROP COLUMN "imageId";
18 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/hooks/storage/images/use-get-images.ts:
--------------------------------------------------------------------------------
1 | import { images, ImagesQuery } from '../../../gql';
2 | import { useQuery } from '../../../utils';
3 | import { useError } from '../../metrics';
4 |
5 | export const useGetImages = () => {
6 | const { data, refetch, error, loading } = useQuery(images);
7 |
8 | useError({
9 | error,
10 | message: 'Failed to load images.',
11 | location: 'useGetImages',
12 | });
13 |
14 | return {
15 | images: data?.images ?? [],
16 | refetch,
17 | loading,
18 | };
19 | };
20 |
--------------------------------------------------------------------------------
/client/src/libs/compass-web-utils/hooks/use-keyboard-override.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react';
2 |
3 | export const useKeyboardOverride = (key: string, callback: () => void) => {
4 | useEffect(() => {
5 | const handleEnter = (e: KeyboardEvent) => {
6 | if (e.key === key) {
7 | e.preventDefault();
8 | e.stopImmediatePropagation();
9 | callback();
10 | }
11 | };
12 |
13 | document.addEventListener('keydown', handleEnter);
14 | return () => document.removeEventListener('keydown', handleEnter);
15 | }, []);
16 | };
17 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/animations/wrappers/fade-in.tsx:
--------------------------------------------------------------------------------
1 | import { motion } from 'framer-motion';
2 | import { ReactNode } from 'react';
3 |
4 | interface FadeInProps {
5 | children: ReactNode;
6 | delay?: number;
7 | duration?: number;
8 | }
9 |
10 | export const FadeIn = ({ children, delay = 0, duration = 0.5 }: FadeInProps) => {
11 | return (
12 |
16 | {children}
17 |
18 | );
19 | };
20 |
--------------------------------------------------------------------------------
/client/src/hooks/use-quick-create.ts:
--------------------------------------------------------------------------------
1 | import { useSearchParams } from 'react-router-dom';
2 |
3 | export const useQuickCreate = () => {
4 | const [searchParams, setSearchParams] = useSearchParams();
5 |
6 | const setQuickCreatePage = (page: string, others?: Record) => {
7 | searchParams.set('quick-create', page);
8 | if (others) {
9 | Object.entries(others).forEach(([key, value]) => {
10 | searchParams.set(key, value);
11 | });
12 | }
13 | setSearchParams(searchParams);
14 | };
15 |
16 | return { setQuickCreatePage };
17 | };
18 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/accordion/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassDarkTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Accordion' {}
5 |
6 | const injectTheme = (): void => {
7 | compassDarkTheme.components.MuiAccordion = {
8 | variants: [],
9 | };
10 |
11 | compassDarkTheme.components.MuiAccordionSummary = {
12 | variants: [],
13 | };
14 |
15 | compassDarkTheme.components.MuiAccordionDetails = {
16 | variants: [],
17 | };
18 | };
19 |
20 | export default injectTheme;
21 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/composites/index.ts:
--------------------------------------------------------------------------------
1 | export * from './card-view';
2 | export * from './color-picker';
3 | export * from './color-picker-popper';
4 | export * from './confirm';
5 | export * from './delete-button';
6 | export * from './error-page';
7 | export * from './font-select';
8 | export * from './font-size-select';
9 | export * from './form';
10 | export * from './loading';
11 | export * from './logo';
12 | export * from './min-max-slider';
13 | export * from './modal';
14 | export * from './page';
15 | export * from './panel';
16 | export * from './user-details';
17 |
--------------------------------------------------------------------------------
/client/src/libs/compass-web-journal/components/toolbar/style-map.ts:
--------------------------------------------------------------------------------
1 | import { FontFamilies } from '@/libs/compass-core-ui';
2 | import { CSSProperties } from 'react';
3 |
4 | export const styleMap: Record = {
5 | ALIGN_LEFT: {
6 | textAlign: 'left',
7 | },
8 | ALIGN_RIGHT: {
9 | textAlign: 'right',
10 | },
11 | };
12 |
13 | FontFamilies.forEach((family) => {
14 | styleMap[family] = {
15 | fontFamily: family,
16 | };
17 | });
18 |
19 | for (let i = 10; i <= 144; i++) {
20 | styleMap[`${i}px`] = {
21 | fontSize: `${i}px`,
22 | };
23 | }
24 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/.graphqlconfig.yml:
--------------------------------------------------------------------------------
1 | projects:
2 | Codegen Project:
3 | schemaPath: ./schema.graphql
4 | includes:
5 | - ./queries/*.ts
6 | excludes:
7 | - ./amplify/**
8 | extensions:
9 | amplify:
10 | codeGenTarget: typescript
11 | generatedFileName: ./generated-types.ts
12 | docsFilePath: ./queries
13 | region: us-east-1
14 | apiId: x5v5kc2ccvcarncsv2kr7aqqum
15 | frontend: javascript
16 | framework: none
17 | maxDepth: 6
18 | extensions:
19 | amplify:
20 | version: 3
21 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20231004182823_/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - You are about to drop the column `userId` on the `Sheet` table. All the data in the column will be lost.
5 |
6 | */
7 | -- DropForeignKey
8 | ALTER TABLE "Sheet" DROP CONSTRAINT "Sheet_userId_fkey";
9 |
10 | -- AlterTable
11 | ALTER TABLE "Character" ALTER COLUMN "attributeData" SET DEFAULT '[]';
12 |
13 | -- AlterTable
14 | ALTER TABLE "PublishedSheet" ADD COLUMN "createdBy" TEXT;
15 |
16 | -- AlterTable
17 | ALTER TABLE "Sheet" DROP COLUMN "userId",
18 | ADD COLUMN "createdBy" TEXT;
19 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/menu/index.tsx:
--------------------------------------------------------------------------------
1 | import MUIMenu, { MenuProps as MUIMenuProps } from '@mui/material/Menu';
2 | import MUIMenuItem, { MenuItemProps as MUIMenuItemProps } from '@mui/material/MenuItem';
3 |
4 | import type { JSX } from "react";
5 |
6 | export type MenuProps = MUIMenuProps;
7 |
8 | export const Menu = ({ ...baseProps }: MUIMenuProps): JSX.Element => ;
9 |
10 | export type MenuItemProps = MUIMenuItemProps;
11 |
12 | export const MenuItem = ({ ...baseProps }: MenuItemProps): JSX.Element => (
13 |
14 | );
15 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20240404123954_archetype_dimensions/migration.sql:
--------------------------------------------------------------------------------
1 | -- AlterTable
2 | ALTER TABLE "Archetype" ADD COLUMN "height" INTEGER NOT NULL DEFAULT 0,
3 | ADD COLUMN "width" INTEGER NOT NULL DEFAULT 0,
4 | ADD COLUMN "x" INTEGER NOT NULL DEFAULT 0,
5 | ADD COLUMN "y" INTEGER NOT NULL DEFAULT 0;
6 |
7 | -- AlterTable
8 | ALTER TABLE "PublishedArchetype" ADD COLUMN "height" INTEGER NOT NULL DEFAULT 0,
9 | ADD COLUMN "width" INTEGER NOT NULL DEFAULT 0,
10 | ADD COLUMN "x" INTEGER NOT NULL DEFAULT 0,
11 | ADD COLUMN "y" INTEGER NOT NULL DEFAULT 0;
12 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-composites/composites/grid/grid.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Roboto+Condensed');
2 | .ag-theme-quartz-dark {
3 | --ag-font-family: Roboto Condensed !important;
4 | --ag-foreground-color: #faf7f2 !important;
5 | --ag-background-color: #2a2a2a !important;
6 | --ag-header-foreground-color: #faf7f2 !important;
7 | --ag-header-background-color: #42403d !important;
8 | --ag-active-color: #417090 !important;
9 | --ag-checkbox-checked-background-color: #e66a3c !important;
10 | --ag-checkbox-checked-border-color: #e66a3c !important;
11 | }
12 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/select/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassDarkTheme, compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Select' {}
5 |
6 | const injectTheme = (): void => {
7 | compassLightTheme.components.MuiSelect = {
8 | variants: [],
9 | styleOverrides: {},
10 | };
11 |
12 | compassDarkTheme.components.MuiSelect = {
13 | variants: [],
14 | defaultProps: {
15 | size: 'small',
16 | },
17 | styleOverrides: {},
18 | };
19 | };
20 |
21 | export default injectTheme;
22 |
--------------------------------------------------------------------------------
/client/src/pages/settings/ruleset-settings/modules/create-module.tsx:
--------------------------------------------------------------------------------
1 | import { Button, Modal } from '@/libs/compass-core-ui';
2 | import { useState } from 'react';
3 |
4 | export const CreateModule = () => {
5 | const [modalOpen, setModalOpen] = useState(false);
6 |
7 | return (
8 | <>
9 |
12 | setModalOpen(false)}
15 | size='medium'
16 | title='Create Module'>
17 | >
18 | );
19 | };
20 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20230924012725_attribute_archetype_ids/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - The primary key for the `ArchetypeAttributes` table will be changed. If it partially fails, the table could be left without primary key constraint.
5 | - You are about to drop the column `id` on the `ArchetypeAttributes` table. All the data in the column will be lost.
6 |
7 | */
8 | -- AlterTable
9 | ALTER TABLE "ArchetypeAttributes" DROP CONSTRAINT "ArchetypeAttributes_pkey",
10 | DROP COLUMN "id",
11 | ADD CONSTRAINT "ArchetypeAttributes_pkey" PRIMARY KEY ("archetypeId", "attributeId");
12 |
--------------------------------------------------------------------------------
/client/src/libs/compass-planes/logic-editor/nodes/not-node.tsx:
--------------------------------------------------------------------------------
1 | import { Text } from '@chakra-ui/react';
2 | import { useContext } from 'react';
3 | import { useNodeId } from 'reactflow';
4 | import { NodeWrapper } from '../components';
5 | import { LogicContext } from '../provider';
6 |
7 | export const NotNode = () => {
8 | const { getOperation } = useContext(LogicContext);
9 | const operation = getOperation(useNodeId() ?? '');
10 |
11 | if (!operation) return null;
12 |
13 | return (
14 |
15 | NOT
16 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/client/src/libs/compass-planes/common/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export * from './use-component-click-actions';
2 | export * from './use-conditional-render';
3 | export * from './use-copy-paste';
4 | export * from './use-group-components';
5 | export * from './use-hydrate-editor-store';
6 | export * from './use-move-nodes';
7 | export * from './use-node-size';
8 | export * from './use-selections';
9 | export * from './use-sheet-colors';
10 | export * from './use-sheet-component-nodes';
11 | export * from './use-sheet-crud';
12 | export * from './use-subscribe-component-changes';
13 | export * from './use-sync-components-with-nodes';
14 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20240426133016_attribute_images/migration.sql:
--------------------------------------------------------------------------------
1 | -- AlterTable
2 | ALTER TABLE "Attribute" ADD COLUMN "imageId" TEXT;
3 |
4 | -- AlterTable
5 | ALTER TABLE "PublishedAttribute" ADD COLUMN "imageId" TEXT;
6 |
7 | -- AddForeignKey
8 | ALTER TABLE "Attribute" ADD CONSTRAINT "Attribute_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "Image"("id") ON DELETE SET NULL ON UPDATE CASCADE;
9 |
10 | -- AddForeignKey
11 | ALTER TABLE "PublishedAttribute" ADD CONSTRAINT "PublishedAttribute_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "Image"("id") ON DELETE SET NULL ON UPDATE CASCADE;
12 |
--------------------------------------------------------------------------------
/client/src/libs/compass-planes/common/hooks/use-subscribe-component-changes.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef, useState } from 'react';
2 | import { editorEmitter } from '../utils';
3 |
4 | export const useSubscribeComponentChanges = (id: string | null) => {
5 | const [key, setKey] = useState(0);
6 | const subscribed = useRef(false);
7 |
8 | useEffect(() => {
9 | if (subscribed.current || !id) return;
10 | editorEmitter.on(`component-${id}-update`, () => {
11 | setKey((prev) => prev + 1);
12 | });
13 | subscribed.current = true;
14 | }, [id]);
15 |
16 | return `component-${id}-key-${key}`;
17 | };
18 |
--------------------------------------------------------------------------------
/client/src/libs/compass-web-journal/components/loading-journal-page.tsx:
--------------------------------------------------------------------------------
1 | import { Skeleton, Stack } from '@/libs/compass-core-ui';
2 |
3 | import type { JSX } from "react";
4 |
5 | export const LoadingJournalPage = (): JSX.Element => {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | );
20 | };
21 |
--------------------------------------------------------------------------------
/client/src/pages/home/home-page.tsx:
--------------------------------------------------------------------------------
1 | import { useCurrentUser } from '@/libs/compass-api';
2 | import { useDeviceSize } from '@/libs/compass-core-ui';
3 | import { Navigate } from 'react-router-dom';
4 | import { SelectMenu } from './select-menu';
5 |
6 | export const HomePage = () => {
7 | const { isCreator } = useCurrentUser();
8 | const { mobile } = useDeviceSize();
9 | const lastRulesetId = localStorage.getItem('last-viewed-ruleset-id');
10 |
11 | if (lastRulesetId && !mobile && isCreator) {
12 | return ;
13 | }
14 |
15 | return ;
16 | };
17 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/page/index.ts:
--------------------------------------------------------------------------------
1 | import { createPage } from './create-page';
2 | import { createPageTemplate } from './create-page-template';
3 | import { deletePage } from './delete-page';
4 | import { page } from './page';
5 | import { pageTemplates } from './page-templates';
6 | import { pages } from './pages';
7 | import { updatePages } from './update-pages';
8 |
9 | export const pageResolvers = {
10 | Query: {
11 | page,
12 | pages,
13 | pageTemplates,
14 | },
15 | Mutation: {
16 | createPage,
17 | updatePages,
18 | deletePage,
19 | createPageTemplate,
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/client/src/libs/compass-planes/logic-editor/nodes/if-node.tsx:
--------------------------------------------------------------------------------
1 | import { Text } from '@chakra-ui/react';
2 | import { useContext } from 'react';
3 | import { useNodeId } from 'reactflow';
4 | import { NodeWrapper } from '../components';
5 | import { LogicContext } from '../provider';
6 |
7 | export const IfNode = () => {
8 | const { getOperation } = useContext(LogicContext);
9 | const operation = getOperation(useNodeId() ?? '');
10 | if (!operation) return null;
11 |
12 | return (
13 |
14 | IF
15 |
16 | );
17 | };
18 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/attribute/index.ts:
--------------------------------------------------------------------------------
1 | import { attribute } from './attribute';
2 | import { attributes } from './attributes';
3 | import { createAttribute } from './create-attribute';
4 | import { deleteAttribute } from './delete-attribute';
5 | import { updateAttribute } from './update-attribute';
6 | import { updateAttributeOrder } from './update-attribute-order';
7 |
8 | export const attributeResolvers = {
9 | Query: {
10 | attribute,
11 | attributes,
12 | },
13 | Mutation: {
14 | createAttribute,
15 | updateAttribute,
16 | deleteAttribute,
17 | updateAttributeOrder,
18 | },
19 | };
20 |
--------------------------------------------------------------------------------
/client/components.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://ui.shadcn.com/schema.json",
3 | "style": "new-york",
4 | "rsc": false,
5 | "tsx": true,
6 | "tailwind": {
7 | "config": "",
8 | "css": "src/index.css",
9 | "baseColor": "neutral",
10 | "cssVariables": true,
11 | "prefix": ""
12 | },
13 | "iconLibrary": "lucide",
14 | "aliases": {
15 | "components": "@/libs/compass-core-ui/v2/components",
16 | "utils": "@/libs/compass-core-ui/utils",
17 | "ui": "@/libs/compass-core-ui/v2/components/ui",
18 | "lib": "@/lib",
19 | "hooks": "@/libs/compass-core-ui/hooks"
20 | },
21 | "registries": {}
22 | }
23 |
--------------------------------------------------------------------------------
/server/.eslintignore:
--------------------------------------------------------------------------------
1 | ########################################################################
2 | # FOLDERS
3 | ########################################################################
4 |
5 | node_modules/
6 | bin
7 | build
8 | cdk.out
9 | .vscode
10 | .husky
11 | lib/infrastructure/prisma-layer
12 |
13 | ########################################################################
14 | # FILES
15 | ########################################################################
16 | *.env*
17 | *.ico
18 | *.jpg
19 | *.png
20 | *.rules
21 | *.svg
22 | *.txt
23 | .eslintignore
24 | .gitignore
25 | .gitkeep
26 | .nvmrc
27 | .npcrc
28 | .prettierignore
29 | .DS_Store
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/checkbox/index.tsx:
--------------------------------------------------------------------------------
1 | import { FormControlLabel } from '@mui/material';
2 | import MUICheckbox, { CheckboxProps as MUICheckboxProps } from '@mui/material/Checkbox';
3 |
4 | import type { JSX } from "react";
5 |
6 | export type CheckboxProps = MUICheckboxProps & {
7 | label?: string;
8 | labelPlacement?: 'bottom' | 'end' | 'start' | 'top';
9 | };
10 |
11 | export const Checkbox = ({ label, labelPlacement, ...baseProps }: CheckboxProps): JSX.Element => (
12 | }
16 | />
17 | );
18 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/radio/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassDarkTheme, compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Radio' {}
5 |
6 | const injectTheme = (): void => {
7 | [compassLightTheme, compassDarkTheme].forEach((theme) => {
8 | theme.components.MuiRadio = {
9 | variants: [],
10 | styleOverrides: {
11 | root: {
12 | '&.Mui-checked': {
13 | color: theme.palette.secondary.main,
14 | },
15 | },
16 | },
17 | };
18 | });
19 | };
20 |
21 | export default injectTheme;
22 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20240229200107_license_key/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "LicenseKey" (
3 | "key" TEXT NOT NULL,
4 | "email" TEXT NOT NULL,
5 | "userId" TEXT,
6 |
7 | CONSTRAINT "LicenseKey_pkey" PRIMARY KEY ("key")
8 | );
9 |
10 | -- CreateIndex
11 | CREATE UNIQUE INDEX "LicenseKey_email_key" ON "LicenseKey"("email");
12 |
13 | -- CreateIndex
14 | CREATE UNIQUE INDEX "LicenseKey_userId_key" ON "LicenseKey"("userId");
15 |
16 | -- AddForeignKey
17 | ALTER TABLE "LicenseKey" ADD CONSTRAINT "LicenseKey_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
18 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20240120194409_rs_playtesters/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "PlayTester" (
3 | "id" TEXT NOT NULL,
4 | "rulesetId" TEXT NOT NULL,
5 | "userId" TEXT NOT NULL,
6 |
7 | CONSTRAINT "PlayTester_pkey" PRIMARY KEY ("id")
8 | );
9 |
10 | -- AddForeignKey
11 | ALTER TABLE "PlayTester" ADD CONSTRAINT "PlayTester_rulesetId_fkey" FOREIGN KEY ("rulesetId") REFERENCES "Ruleset"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
12 |
13 | -- AddForeignKey
14 | ALTER TABLE "PlayTester" ADD CONSTRAINT "PlayTester_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
15 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/_shared/add-module-util.ts:
--------------------------------------------------------------------------------
1 | import { TPrismaClient } from '@/database';
2 | import { cloneUtil } from './clone-util';
3 |
4 | interface AddModule {
5 | db: TPrismaClient;
6 | moduleId: string;
7 | rulesetId: string;
8 | userId: string;
9 | }
10 |
11 | export async function addModule({ db, rulesetId, moduleId }: AddModule) {
12 | // Clone the modules entities into the ruleset
13 | const { cloneAllEntities } = await cloneUtil({
14 | db,
15 | rulesetId,
16 | originalRulesetId: moduleId,
17 | addingModule: true,
18 | });
19 |
20 | await cloneAllEntities();
21 |
22 | return 'success';
23 | }
24 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20240125232127_/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - The values [PLAYER,BUILDER] on the enum `Role` will be removed. If these variants are still used in the database, this will fail.
5 |
6 | */
7 | -- AlterEnum
8 | BEGIN;
9 | CREATE TYPE "Role_new" AS ENUM ('USER', 'CREATOR', 'EARLY_ACCESS');
10 | ALTER TABLE "User" ALTER COLUMN "role" DROP DEFAULT;
11 | ALTER TABLE "User" ALTER COLUMN "role" TYPE "Role_new" USING ("role"::text::"Role_new");
12 | ALTER TYPE "Role" RENAME TO "Role_old";
13 | ALTER TYPE "Role_new" RENAME TO "Role";
14 | DROP TYPE "Role_old";
15 | ALTER TABLE "User" ALTER COLUMN "role" SET DEFAULT 'USER';
16 | COMMIT;
17 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/hooks/rulesets/index.ts:
--------------------------------------------------------------------------------
1 | export * from './use-add-module';
2 | export * from './use-add-playtester';
3 | export * from './use-add-to-shelf';
4 | export * from './use-cancel-publish-ruleset';
5 | export * from './use-create-ruleset';
6 | export * from './use-delete-ruleset';
7 | export * from './use-permitted-rulesets';
8 | export * from './use-publish-ruleset';
9 | export * from './use-remove-module';
10 | export * from './use-remove-playtester';
11 | export * from './use-ruleset';
12 | export * from './use-ruleset-permitted-users';
13 | export * from './use-ruleset-sales-page';
14 | export * from './use-rulesets';
15 | export * from './use-update-ruleset';
16 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20231015223941_character_archetypes/migration.sql:
--------------------------------------------------------------------------------
1 | -- DropForeignKey
2 | ALTER TABLE "_CharacterArchetypes" DROP CONSTRAINT "_CharacterArchetypes_A_fkey";
3 |
4 | -- DropForeignKey
5 | ALTER TABLE "_CharacterArchetypes" DROP CONSTRAINT "_CharacterArchetypes_B_fkey";
6 |
7 | -- AddForeignKey
8 | ALTER TABLE "_CharacterArchetypes" ADD CONSTRAINT "_CharacterArchetypes_A_fkey" FOREIGN KEY ("A") REFERENCES "Archetype"("id") ON DELETE CASCADE ON UPDATE CASCADE;
9 |
10 | -- AddForeignKey
11 | ALTER TABLE "_CharacterArchetypes" ADD CONSTRAINT "_CharacterArchetypes_B_fkey" FOREIGN KEY ("B") REFERENCES "Character"("id") ON DELETE CASCADE ON UPDATE CASCADE;
12 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/hooks/use-mobile.ts:
--------------------------------------------------------------------------------
1 | import * as React from "react"
2 |
3 | const MOBILE_BREAKPOINT = 768
4 |
5 | export function useIsMobile() {
6 | const [isMobile, setIsMobile] = React.useState(undefined)
7 |
8 | React.useEffect(() => {
9 | const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
10 | const onChange = () => {
11 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
12 | }
13 | mql.addEventListener("change", onChange)
14 | setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
15 | return () => mql.removeEventListener("change", onChange)
16 | }, [])
17 |
18 | return !!isMobile
19 | }
20 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20240514212700_user_role_update/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - The values [EARLY_ACCESS] on the enum `Role` will be removed. If these variants are still used in the database, this will fail.
5 |
6 | */
7 | -- AlterEnum
8 | BEGIN;
9 | CREATE TYPE "Role_new" AS ENUM ('USER', 'CREATOR', 'PUBLISHER');
10 | ALTER TABLE "User" ALTER COLUMN "role" DROP DEFAULT;
11 | ALTER TABLE "User" ALTER COLUMN "role" TYPE "Role_new" USING ("role"::text::"Role_new");
12 | ALTER TYPE "Role" RENAME TO "Role_old";
13 | ALTER TYPE "Role_new" RENAME TO "Role";
14 | DROP TYPE "Role_old";
15 | ALTER TABLE "User" ALTER COLUMN "role" SET DEFAULT 'USER';
16 | COMMIT;
17 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/hooks/official-content/use-official-content.ts:
--------------------------------------------------------------------------------
1 | import { officialContent, OfficialContentQuery } from '../../gql';
2 | import { useQuery } from '../../utils';
3 | import { useError } from '../metrics';
4 |
5 | export const useOfficialContent = () => {
6 | const { data, loading, error } = useQuery(officialContent);
7 |
8 | useError({
9 | error,
10 | message: 'Failed to load Quest Bound content',
11 | location: 'useOfficialContent',
12 | });
13 |
14 | return {
15 | rulesets: data?.officialContent?.rulesets ?? [],
16 | modules: data?.officialContent?.modules ?? [],
17 | loading,
18 | error,
19 | };
20 | };
21 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/hooks/user/use-sign-out.ts:
--------------------------------------------------------------------------------
1 | import { EnvContext } from "@/libs/compass-web-utils";
2 | import { useCallback, useContext } from "react";
3 | import { useCurrentUser } from "./use-current-user";
4 |
5 | interface UseSignOut {
6 | signOut: () => void;
7 | }
8 |
9 | export const useSignOut = (): UseSignOut => {
10 | const { revokeCurrentUser } = useCurrentUser();
11 | const { domain } = useContext(EnvContext);
12 |
13 | const signOut = useCallback(async () => {
14 | localStorage.removeItem("last-viewed-ruleset-id");
15 | revokeCurrentUser();
16 | window.location.href = domain;
17 | }, []);
18 |
19 | return {
20 | signOut,
21 | };
22 | };
23 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/gql/mutations/characters.ts:
--------------------------------------------------------------------------------
1 | import { gql } from '@apollo/client/core/index.js';
2 |
3 | export const createCharacter = gql`
4 | mutation CreateCharacter($input: CreateCharacter!) {
5 | createCharacter(input: $input) {
6 | id
7 | name
8 | rulesetId
9 | }
10 | }
11 | `;
12 |
13 | export const deleteCharacter = gql`
14 | mutation DeleteCharacter($id: String!) {
15 | deleteCharacter(id: $id)
16 | }
17 | `;
18 |
19 | export const updateCharacter = gql`
20 | mutation UpdateCharacter($input: UpdateCharacter!) {
21 | updateCharacter(input: $input) {
22 | id
23 | name
24 | attributeData
25 | }
26 | }
27 | `;
28 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/gql/mutations/charts.ts:
--------------------------------------------------------------------------------
1 | import { gql } from '@apollo/client/core/index.js';
2 |
3 | export const createChart = gql`
4 | mutation CreateChart($input: CreateChart!) {
5 | createChart(input: $input) {
6 | id
7 | rulesetId
8 | title
9 | fileKey
10 | }
11 | }
12 | `;
13 |
14 | export const updateChart = gql`
15 | mutation UpdateChart($input: UpdateChart!) {
16 | updateChart(input: $input) {
17 | id
18 | rulesetId
19 | title
20 | fileKey
21 | }
22 | }
23 | `;
24 |
25 | export const deleteChart = gql`
26 | mutation DeleteChart($input: DeleteEntity!) {
27 | deleteChart(input: $input)
28 | }
29 | `;
30 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/character/delete-character.ts:
--------------------------------------------------------------------------------
1 | import { AuthorizationContext } from '@/infrastructure/types';
2 | import { DeleteCharacterMutationVariables } from '../../generated-types';
3 | import { dbClient } from '@/database';
4 |
5 | export const deleteCharacter = async (
6 | parent: any,
7 | args: DeleteCharacterMutationVariables,
8 | context: AuthorizationContext,
9 | ) => {
10 | const { userId } = context;
11 |
12 | const { id } = args;
13 |
14 | const db = dbClient();
15 |
16 | await db.character.delete({
17 | where: {
18 | id,
19 | userId,
20 | },
21 | });
22 |
23 | return `Successfully deleted character ${id}`;
24 | };
25 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/document/index.ts:
--------------------------------------------------------------------------------
1 | import { bootstrapRulebook } from './bootstrap-rulebook';
2 | import { createDocument } from './create-document';
3 | import { deleteBootstrap } from './delete-bootstrap';
4 | import { deleteDocument } from './delete-document';
5 | import { document } from './document';
6 | import { documents } from './documents';
7 | import { updateDocument } from './update-document';
8 |
9 | export const documentResolvers = {
10 | Query: {
11 | document,
12 | documents,
13 | },
14 | Mutation: {
15 | createDocument,
16 | updateDocument,
17 | deleteDocument,
18 | bootstrapRulebook,
19 | deleteBootstrap,
20 | },
21 | };
22 |
--------------------------------------------------------------------------------
/server/src/infrastructure/rest/endpoints.ts:
--------------------------------------------------------------------------------
1 | import { Express } from 'express';
2 | import { initializeEmailEndpoints } from './services/email';
3 | import { initializeMetricsEndpoints } from './services/metrics';
4 | import { initializeImportExportEndpoints } from './services/import-export';
5 | import { initializeSigninEndpoints } from './services/signin';
6 | import { initializeStorageEndpoints } from './services/storage';
7 |
8 | export const initializeRestfulEndpoints = (app: Express) => {
9 | initializeEmailEndpoints(app);
10 | initializeMetricsEndpoints(app);
11 | initializeImportExportEndpoints(app);
12 | initializeSigninEndpoints(app);
13 | initializeStorageEndpoints(app);
14 | };
15 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/image-list/index.tsx:
--------------------------------------------------------------------------------
1 | import MUIImageList, { ImageListProps as MUIImageListProps } from '@mui/material/ImageList';
2 | import MUIImageListItem, {
3 | ImageListItemProps as MUIImageListItemProps,
4 | } from '@mui/material/ImageListItem';
5 |
6 | import type { JSX } from "react";
7 |
8 | export type ImageListProps = MUIImageListProps;
9 | export type ImageListItemProps = MUIImageListItemProps;
10 |
11 | export const ImageList = ({ ...baseProps }: ImageListProps): JSX.Element => (
12 |
13 | );
14 | export const ImageListItem = ({ ...baseProps }: ImageListItemProps): JSX.Element => (
15 |
16 | );
17 |
--------------------------------------------------------------------------------
/client/src/pages/characters/character-journal.tsx:
--------------------------------------------------------------------------------
1 | import { Stack } from '@/libs/compass-core-ui';
2 | import { useLocation } from 'react-router-dom';
3 | import { RulebookPage } from '../ruleset/rulebook/components/rulebook-page';
4 |
5 | interface CharacterJournalProps {
6 | viewMode?: boolean;
7 | }
8 |
9 | export const CharacterJournal = ({ viewMode }: CharacterJournalProps) => {
10 | const { search } = useLocation();
11 | const queryParams = new URLSearchParams(search);
12 | const pageId = queryParams.get('page');
13 |
14 | return (
15 |
16 |
17 |
18 | );
19 | };
20 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20240218002305_character_items/migration.sql:
--------------------------------------------------------------------------------
1 | -- AlterTable
2 | ALTER TABLE "Character" ADD COLUMN "itemData" JSONB NOT NULL DEFAULT '[]';
3 |
4 | -- AlterTable
5 | ALTER TABLE "Item" ADD COLUMN "containerCapacity" INTEGER NOT NULL DEFAULT 100,
6 | ADD COLUMN "containerHeight" INTEGER NOT NULL DEFAULT 20,
7 | ADD COLUMN "containerWidth" INTEGER NOT NULL DEFAULT 20,
8 | ADD COLUMN "height" INTEGER NOT NULL DEFAULT 2,
9 | ADD COLUMN "isContainer" BOOLEAN NOT NULL DEFAULT false,
10 | ADD COLUMN "stackCapacity" INTEGER NOT NULL DEFAULT 1,
11 | ADD COLUMN "weight" INTEGER NOT NULL DEFAULT 0,
12 | ADD COLUMN "width" INTEGER NOT NULL DEFAULT 2;
13 |
--------------------------------------------------------------------------------
/client/src/libs/compass-planes/logic-editor/hooks/use-filter-changes.ts:
--------------------------------------------------------------------------------
1 | import { Operation, OperationType } from '../types';
2 |
3 | const operationsWhichShouldNotBeRemoved: OperationType[] = [];
4 |
5 | export const useFilterChanges = (getOperation: (id: string) => Operation | undefined) => {
6 | function filterChanges(changes: Array): any[] {
7 | return changes.filter((change) => {
8 | if (change.type === 'remove') {
9 | const operation = getOperation(change.id);
10 | if (operation && operationsWhichShouldNotBeRemoved.includes(operation?.type)) return false;
11 | }
12 |
13 | return true;
14 | });
15 | }
16 |
17 | return {
18 | filterChanges,
19 | };
20 | };
21 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/assets/qb-q.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/client/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | parser: "@typescript-eslint/parser",
4 | ignorePatterns: ['.eslintrc.js'],
5 | plugins: ["@typescript-eslint"],
6 | extends: [
7 | "plugin:@typescript-eslint/recommended",
8 | "plugin:prettier/recommended",
9 | "plugin:react/recommended"
10 | ],
11 | rules: {
12 | "no-console": ["error", { "allow": ["warn", "error", "debug"] }],
13 | "@typescript-eslint/no-unused-vars": "error",
14 | "arrow-body-style": "error",
15 | '@typescript-eslint/no-var-requires': 'warn',
16 | "react/no-unknown-property": [0],
17 | "react/prop-types": ["off"]
18 | },
19 | parserOptions: {
20 | sourceType: "module"
21 | }
22 | }
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/speed-dial/index.tsx:
--------------------------------------------------------------------------------
1 | import MUISpeedDial, { SpeedDialProps as MUISpeedDialProps } from '@mui/material/SpeedDial';
2 | import MUISpeedDialAction, {
3 | SpeedDialActionProps as MUISpeedDialActionProps,
4 | } from '@mui/material/SpeedDialAction';
5 |
6 | import type { JSX } from "react";
7 |
8 | export type SpeedDialProps = MUISpeedDialProps;
9 | export type SpeedDialActionProps = MUISpeedDialActionProps;
10 |
11 | export const SpeedDial = ({ ...baseProps }: SpeedDialProps): JSX.Element => (
12 |
13 | );
14 |
15 | export const SpeedDialAction = ({ ...baseProps }: SpeedDialActionProps): JSX.Element => (
16 |
17 | );
18 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/utils/utils.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Inserts the child ID in the sorted child ID array. If childIndex is -1, removes the child ID.
3 | * Pass Infinity for index to place new ID at the end.
4 | */
5 | export function insertPageAt(childIds: string[], newChildId: string, index: number) {
6 | const pageOrder = childIds.filter((id) => id !== newChildId);
7 |
8 | if (index >= 0) {
9 | pageOrder.splice(index, 0, newChildId);
10 | }
11 |
12 | return [...new Set(pageOrder)];
13 | }
14 |
15 | /**
16 | * Removes __typename from GraphQL response
17 | */
18 | export function convertRawResponse(raw: Record) {
19 | const copy = { ...raw };
20 | delete copy.__typename;
21 | return copy as T;
22 | }
23 |
--------------------------------------------------------------------------------
/client/src/libs/compass-planes/logic-editor/nodes/boolean-comparison-node.tsx:
--------------------------------------------------------------------------------
1 | import { Text } from '@chakra-ui/react';
2 | import { useContext } from 'react';
3 | import { useNodeId } from 'reactflow';
4 | import { NodeWrapper } from '../components';
5 | import { LogicContext } from '../provider';
6 | import { operationTypeToLabel } from '../types';
7 |
8 | export const BooleanComparisonNode = () => {
9 | const { getOperation } = useContext(LogicContext);
10 | const operation = getOperation(useNodeId() ?? '');
11 |
12 | if (!operation) return null;
13 |
14 | return (
15 |
16 | {operationTypeToLabel.get(operation.type)}
17 |
18 | );
19 | };
20 |
--------------------------------------------------------------------------------
/client/src/libs/compass-planes/logic-editor/nodes/set-node.tsx:
--------------------------------------------------------------------------------
1 | import { Stack, Text } from '@chakra-ui/react';
2 | import { useContext } from 'react';
3 | import { useNodeId } from 'reactflow';
4 | import { NodeWrapper } from '../components';
5 | import { LogicContext } from '../provider';
6 |
7 | export const SetNode = () => {
8 | const { getOperation } = useContext(LogicContext);
9 | const operation = getOperation(useNodeId() ?? '');
10 | if (!operation) return null;
11 |
12 | return (
13 |
14 |
15 | Set
16 |
17 |
18 | );
19 | };
20 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20240508135008_published_ruleset_properties/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - You are about to drop the column `approved` on the `PublishedRuleset` table. All the data in the column will be lost.
5 |
6 | */
7 | -- AlterTable
8 | ALTER TABLE "PublishedRuleset" DROP COLUMN "approved",
9 | ADD COLUMN "currentPrice" DOUBLE PRECISION NOT NULL DEFAULT 0,
10 | ADD COLUMN "live" BOOLEAN NOT NULL DEFAULT false;
11 |
12 | -- AlterTable
13 | ALTER TABLE "PublishedRulesetPermission" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
14 | ADD COLUMN "salePrice" DOUBLE PRECISION NOT NULL DEFAULT 0,
15 | ADD COLUMN "tipAmount" DOUBLE PRECISION NOT NULL DEFAULT 0;
16 |
--------------------------------------------------------------------------------
/client/src/libs/compass-planes/logic-editor/nodes/index.ts:
--------------------------------------------------------------------------------
1 | export * from './action-node';
2 | export * from './announce-node';
3 | export * from './attribute-node';
4 | export * from './boolean-comparison-node';
5 | export * from './chart-node';
6 | export * from './comment-node';
7 | export * from './comparison-node';
8 | export * from './default-value-node';
9 | export * from './dice-node';
10 | export * from './exponent-node';
11 | export * from './if-node';
12 | export * from './items';
13 | export * from './math-operation-node';
14 | export * from './not-node';
15 | export * from './primitive-node';
16 | export * from './return';
17 | export * from './set-node';
18 | export * from './side-effect-node';
19 | export * from './variable-node';
20 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/button/index.tsx:
--------------------------------------------------------------------------------
1 | import MUIButton, { ButtonProps as MUIButtonProps } from '@mui/material/Button';
2 | import { Loader } from '../loader';
3 |
4 | import type { JSX } from "react";
5 |
6 | export interface ButtonProps extends MUIButtonProps {
7 | loading?: boolean;
8 | target?: string;
9 | }
10 |
11 | export const Button = ({ loading, ...baseProps }: ButtonProps): JSX.Element => (
12 |
13 | {loading ? (
14 |
18 | ) : (
19 | baseProps.children
20 | )}
21 |
22 | );
23 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/theme/index.ts:
--------------------------------------------------------------------------------
1 | import { Components, createTheme, responsiveFontSizes, Theme } from '@mui/material/styles';
2 | import { components } from './components';
3 | import { darkPalette, lightPalette } from './palette';
4 | import { typography } from './typography';
5 |
6 | interface CompassTheme extends Theme {
7 | components: Components;
8 | }
9 |
10 | export const compassLightTheme = responsiveFontSizes(
11 | createTheme({
12 | palette: lightPalette,
13 | typography,
14 | components,
15 | }),
16 | ) as CompassTheme;
17 |
18 | export const compassDarkTheme = responsiveFontSizes(
19 | createTheme({
20 | palette: darkPalette,
21 | typography,
22 | components,
23 | }),
24 | ) as CompassTheme;
25 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/component/delete-components.ts:
--------------------------------------------------------------------------------
1 | import { AuthorizationContext } from '@/infrastructure/types';
2 | import { DeleteSheetComponentsMutationVariables } from '../../generated-types';
3 | import { dbClient } from '@/database';
4 |
5 | export const deleteSheetComponents = async (
6 | parent: any,
7 | args: DeleteSheetComponentsMutationVariables,
8 | context: AuthorizationContext,
9 | ) => {
10 | const { input } = args;
11 |
12 | const db = dbClient();
13 |
14 | await db.sheetComponent.deleteMany({
15 | where: {
16 | id: { in: input.map((input) => `${input.id}-${input.sheetId}-${input.rulesetId}`) },
17 | },
18 | });
19 |
20 | return `Sheet components deleted successfully.`;
21 | };
22 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/hooks/pages/use-pages.ts:
--------------------------------------------------------------------------------
1 | import { useParams } from 'react-router-dom';
2 | import { Page, pages, PagesQuery, PagesQueryVariables } from '../../gql';
3 | import { useQuery } from '../../utils';
4 | import { useError } from '../metrics';
5 |
6 | export const usePages = () => {
7 | const { rulesetId } = useParams();
8 |
9 | const { data, loading, error } = useQuery(pages, {
10 | variables: {
11 | rulesetId: rulesetId ?? '',
12 | },
13 | skip: !rulesetId,
14 | });
15 |
16 | useError({
17 | error,
18 | message: 'Failed to load pages',
19 | });
20 |
21 | return {
22 | pages: (data?.pages ?? []) as Page[],
23 | loading,
24 | error,
25 | };
26 | };
27 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/gql/mutations/users.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 |
3 | /* eslint-disable */
4 | // this is an auto generated file. This will be overwritten
5 | import { gql } from '@apollo/client/core/index.js';
6 |
7 | export const updateCurrentUser = gql`
8 | mutation UpdateCurrentUser($input: CurrentUserUpdateInput!) {
9 | updateCurrentUser(input: $input) {
10 | id
11 | username
12 | onboarded
13 | avatarSrc
14 | preferences {
15 | emailShares
16 | emailUpdates
17 | emailUnsubscribe
18 | }
19 | companion {
20 | id
21 | name
22 | description
23 | animal
24 | color
25 | src
26 | model
27 | }
28 | }
29 | }
30 | `;
31 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/types/planes/inventory-component-types.tsx:
--------------------------------------------------------------------------------
1 | import { ComponentTypes, SheetComponentType } from './base-component-types';
2 | import { DEFAULT_GRID_SIZE, MAX_SIZE } from './defaults';
3 |
4 | export const inventoryComponentTypes: SheetComponentType[] = [
5 | {
6 | label: 'Item',
7 | description: 'Item',
8 | type: ComponentTypes.ITEM,
9 | minWidth: DEFAULT_GRID_SIZE,
10 | minHeight: DEFAULT_GRID_SIZE,
11 | defaultWidth: 10 * DEFAULT_GRID_SIZE,
12 | defaultHeight: 10 * DEFAULT_GRID_SIZE,
13 | maxHeight: MAX_SIZE * DEFAULT_GRID_SIZE,
14 | maxWidth: MAX_SIZE * DEFAULT_GRID_SIZE,
15 | defaultRotation: 0,
16 | defaultLayer: 2,
17 | transparent: true,
18 | scalable: true,
19 | },
20 | ];
21 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/v2/ui/label.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import * as LabelPrimitive from '@radix-ui/react-label';
4 | import * as React from 'react';
5 |
6 | import { cn } from '@/libs/compass-core-ui/utils';
7 |
8 | function Label({ className, ...props }: React.ComponentProps) {
9 | return (
10 |
18 | );
19 | }
20 |
21 | export { Label };
22 |
--------------------------------------------------------------------------------
/client/src/pages/ruleset/attributes/attribute-store/evaluation/evaluation-functions/inventory.ts:
--------------------------------------------------------------------------------
1 | import { ContextualItem } from '@/libs/compass-api';
2 | import { LogicalValue, Operation } from '@/libs/compass-planes';
3 |
4 | export const getInventory = (
5 | operation: Operation,
6 | items: ContextualItem[],
7 | useTestValue: boolean,
8 | ): LogicalValue => {
9 | const weight = items
10 | .map((item) => {
11 | const itemQty = (item.properties.find((property) => property.id === 'quantity')?.value ??
12 | 0) as number;
13 | return itemQty * item.data.weight;
14 | })
15 | .reduce((acc, curr) => acc + curr, 0);
16 |
17 | if (useTestValue) return operation.data?.testValue ?? weight ?? '';
18 |
19 | return weight;
20 | };
21 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/attribute/utils.ts:
--------------------------------------------------------------------------------
1 | import { Attribute } from '../../generated-types';
2 |
3 | /**
4 | * Injects the default value into the defaultValue operation
5 | * Filters out any corrupted operations
6 | */
7 | export function syncAttributeLogic(attribute: any): Attribute {
8 | const injectedAttribute = {
9 | ...attribute,
10 | logic: JSON.stringify(
11 | JSON.parse(attribute.logic)
12 | .filter((op: any) => !!op.id)
13 | .map((op: any) => {
14 | if (op.type !== 'default-value') return op;
15 | return {
16 | ...op,
17 | value: attribute.defaultValue,
18 | };
19 | }),
20 | ),
21 | };
22 |
23 | return injectedAttribute;
24 | }
25 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/toggle-button/index.tsx:
--------------------------------------------------------------------------------
1 | import MUIToggleButton, {
2 | ToggleButtonProps as MUIToggleButtonProps,
3 | } from '@mui/material/ToggleButton';
4 | import MUIToggleButtonGroup, {
5 | ToggleButtonGroupProps as MUIGroupProps,
6 | } from '@mui/material/ToggleButtonGroup';
7 |
8 | import type { JSX } from "react";
9 |
10 | export type ToggleButtonProps = MUIToggleButtonProps;
11 | export type ToggleButtonGroupProps = MUIGroupProps;
12 |
13 | export const ToggleButton = ({ ...baseProps }: ToggleButtonProps): JSX.Element => (
14 |
15 | );
16 |
17 | export const ToggleButtonGroup = ({ ...baseProps }: ToggleButtonGroupProps): JSX.Element => (
18 |
19 | );
20 |
--------------------------------------------------------------------------------
/server/.prettierignore:
--------------------------------------------------------------------------------
1 | ########################################################################
2 | # FOLDERS
3 | ########################################################################
4 |
5 |
6 | .github/
7 | .husky/
8 | .next/
9 | .vscode/
10 | node_modules
11 | build
12 | cdk.out
13 | bin
14 | lib/infrastructure/prisma-layer/dist
15 | lib/infrastructure/prisma-layer/prisma
16 | lib/infrastructure/prisma-layer/node_modules
17 |
18 | ########################################################################
19 | # FILES
20 | ########################################################################
21 | *.env*
22 | *.ico
23 | *.jpg
24 | *.png
25 | *.rules
26 | *.svg
27 | *.txt
28 | .eslintignore
29 | .gitignore
30 | .gitkeep
31 | .nvmrc
32 | .npmrc
33 | .prettierignore
34 | .DS_Store
35 |
--------------------------------------------------------------------------------
/client/src/libs/compass-planes/logic-editor/nodes/dice-node.tsx:
--------------------------------------------------------------------------------
1 | import { Stack, Text } from '@chakra-ui/react';
2 | import { Casino } from '@mui/icons-material';
3 | import { useContext } from 'react';
4 | import { useNodeId } from 'reactflow';
5 | import { NodeWrapper } from '../components';
6 | import { LogicContext } from '../provider';
7 |
8 | export const DiceNode = () => {
9 | const { getOperation } = useContext(LogicContext);
10 | const operation = getOperation(useNodeId() ?? '');
11 |
12 | if (!operation) return null;
13 |
14 | return (
15 |
16 |
17 |
18 | {operation.value}
19 |
20 |
21 | );
22 | };
23 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-composites/composites/sheets/sheet-attribute-control/animated-update-msg.tsx:
--------------------------------------------------------------------------------
1 | import { motion } from 'framer-motion';
2 | import React from 'react';
3 |
4 | export function AnimatedUpdateMsg({
5 | value,
6 | isDerivedAttribute,
7 | children,
8 | }: {
9 | value: number | string | null;
10 | isDerivedAttribute: boolean;
11 | children: React.ReactNode;
12 | }) {
13 | if (!isDerivedAttribute) {
14 | return <>{children}>;
15 | }
16 |
17 | return (
18 |
24 | {children}
25 |
26 | );
27 | }
28 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/gql/queries/archetypes.ts:
--------------------------------------------------------------------------------
1 | import { gql } from '@apollo/client/core/index.js';
2 |
3 | export const archetypes = gql`
4 | query Archetypes($rulesetId: String!) {
5 | archetypes(rulesetId: $rulesetId) {
6 | id
7 | rulesetId
8 | moduleId
9 | category
10 | moduleTitle
11 | title
12 | description
13 | image {
14 | id
15 | src
16 | }
17 | }
18 | }
19 | `;
20 |
21 | export const archetype = gql`
22 | query Archetype($input: GetEntity!) {
23 | archetype(input: $input) {
24 | id
25 | rulesetId
26 | moduleId
27 | category
28 | moduleTitle
29 | title
30 | description
31 | image {
32 | id
33 | src
34 | }
35 | }
36 | }
37 | `;
38 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/hooks/documents/use-documents.ts:
--------------------------------------------------------------------------------
1 | import { useParams } from 'react-router-dom';
2 | import { Document, documents, DocumentsQuery, DocumentsQueryVariables } from '../../gql';
3 | import { useQuery } from '../../utils';
4 | import { useError } from '../metrics';
5 |
6 | export const useDocuments = () => {
7 | const { rulesetId } = useParams();
8 | const { data, loading, error } = useQuery(documents, {
9 | variables: {
10 | rulesetId: rulesetId ?? '',
11 | },
12 | skip: !rulesetId,
13 | });
14 |
15 | useError({
16 | error,
17 | message: 'Failed to load documents',
18 | });
19 |
20 | return {
21 | documents: (data?.documents ?? []) as Document[],
22 | loading,
23 | error,
24 | };
25 | };
26 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/hooks/rulesets/use-rulesets.ts:
--------------------------------------------------------------------------------
1 | import { Ruleset, rulesets, RulesetsQuery } from '../../gql';
2 | import { useQuery } from '../../utils';
3 | import { useError } from '../metrics';
4 |
5 | export const useRulesets = (pollInterval = 0) => {
6 | const { data, loading, error } = useQuery(rulesets, {
7 | pollInterval,
8 | });
9 |
10 | useError({
11 | error,
12 | message: 'Failed to load rulesets',
13 | });
14 |
15 | const userContent = (data?.rulesets ?? []) as Ruleset[];
16 | const modules = userContent.filter((ruleset) => ruleset.isModule);
17 | const userRulesets = userContent.filter((ruleset) => !ruleset.isModule);
18 |
19 | return {
20 | rulesets: userRulesets,
21 | modules,
22 | loading,
23 | error,
24 | };
25 | };
26 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/toggle-button/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassDarkTheme, compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/ToggleButton' {}
5 |
6 | const injectTheme = (): void => {
7 | [compassLightTheme, compassDarkTheme].forEach((theme) => {
8 | theme.components.MuiToggleButton = {
9 | variants: [],
10 | styleOverrides: {
11 | root: {
12 | textTransform: 'none',
13 | '&:focus-visible': {
14 | outline: '1px solid',
15 | outlineColor: compassDarkTheme.palette.info.main,
16 | outlineOffset: '2px',
17 | },
18 | },
19 | },
20 | };
21 | });
22 | };
23 |
24 | export default injectTheme;
25 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/image/images.ts:
--------------------------------------------------------------------------------
1 | import { dbClient } from '@/database';
2 | import { Image } from '@/infrastructure/graphql';
3 | import { AuthorizationContext, ResolverInput } from '@/infrastructure/types';
4 |
5 | export const images = async (
6 | parent: any,
7 | args: ResolverInput,
8 | context: AuthorizationContext,
9 | ) => {
10 | const { userId } = context;
11 | const db = dbClient();
12 |
13 | const images = await db.user
14 | .findUnique({
15 | where: {
16 | id: userId,
17 | },
18 | })
19 | .images();
20 |
21 | return (images ?? [])
22 | .filter((img: any) => !img.hidden)
23 | .map((image: any) => ({
24 | ...image,
25 | details: image.details ? JSON.stringify(image.details) : undefined,
26 | }));
27 | };
28 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/stepper/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Stepper' {}
5 | declare module '@mui/material/Step' {}
6 | declare module '@mui/material/StepLabel' {}
7 |
8 | const injectTheme = (): void => {
9 | compassLightTheme.components.MuiStepper = {
10 | variants: [],
11 | styleOverrides: {
12 | root: {},
13 | },
14 | };
15 | compassLightTheme.components.MuiStep = {
16 | variants: [],
17 | styleOverrides: {
18 | root: {},
19 | },
20 | };
21 | compassLightTheme.components.MuiStepLabel = {
22 | variants: [],
23 | styleOverrides: {
24 | root: {},
25 | },
26 | };
27 | };
28 |
29 | export default injectTheme;
30 |
--------------------------------------------------------------------------------
/client/src/components/share/publish/not-published.tsx:
--------------------------------------------------------------------------------
1 | import { Button, Stack, Text } from '@chakra-ui/react';
2 | import { Newspaper } from '@mui/icons-material';
3 |
4 | export const NotPublished = ({
5 | onPublish,
6 | loading,
7 | }: {
8 | onPublish: () => void;
9 | loading?: boolean;
10 | }) => {
11 | return (
12 |
13 |
14 | Publish your content
15 |
16 | Published content may be added to other users' shelves. You may unpublish at any time, but
17 | content on shelves will not be removed.
18 |
19 |
22 |
23 | );
24 | };
25 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/switch/index.tsx:
--------------------------------------------------------------------------------
1 | import { FormControl, FormControlLabel } from '@mui/material';
2 | import MUISwitch, { SwitchProps as MUISwitchProps } from '@mui/material/Switch';
3 |
4 | import type { JSX } from "react";
5 |
6 | export type SwitchProps = MUISwitchProps & {
7 | label?: string;
8 | labelPlacement?: 'top' | 'bottom' | 'start' | 'end';
9 | fullWidth?: boolean;
10 | };
11 |
12 | export const Switch = ({
13 | label,
14 | labelPlacement,
15 | fullWidth = false,
16 | ...baseProps
17 | }: SwitchProps): JSX.Element => (
18 |
19 | }
24 | />
25 |
26 | );
27 |
--------------------------------------------------------------------------------
/client/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "useDefineForClassFields": true,
5 | "lib": ["DOM", "DOM.Iterable", "ESNext"],
6 | "allowJs": false,
7 | "skipLibCheck": true,
8 | "esModuleInterop": false,
9 | "allowSyntheticDefaultImports": true,
10 | "strict": true,
11 | "forceConsistentCasingInFileNames": true,
12 | "module": "esnext",
13 | "moduleResolution": "Node",
14 | "resolveJsonModule": true,
15 | "isolatedModules": true,
16 | "noEmit": true,
17 | "jsx": "react-jsx",
18 | "baseUrl": "./",
19 | "paths": {
20 | "@/*": ["src/*"],
21 | },
22 | "maxNodeModuleJsDepth": 0
23 | },
24 | "include": ["src", "./custom.d.ts"],
25 | "exclude": ["node_modules"],
26 | "references": [{ "path": "./tsconfig.node.json" }]
27 | }
28 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20240506160659_character_created_from_pub/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - You are about to drop the `_CharacterArchetypes` table. If the table is not empty, all the data it contains will be lost.
5 |
6 | */
7 | -- DropForeignKey
8 | ALTER TABLE "Character" DROP CONSTRAINT "Character_rulesetId_fkey";
9 |
10 | -- DropForeignKey
11 | ALTER TABLE "_CharacterArchetypes" DROP CONSTRAINT "_CharacterArchetypes_A_fkey";
12 |
13 | -- DropForeignKey
14 | ALTER TABLE "_CharacterArchetypes" DROP CONSTRAINT "_CharacterArchetypes_B_fkey";
15 |
16 | -- AlterTable
17 | ALTER TABLE "Character" ADD COLUMN "archetypeIds" JSONB NOT NULL DEFAULT '[]',
18 | ADD COLUMN "createdFromPublishedRuleset" BOOLEAN NOT NULL DEFAULT false;
19 |
20 | -- DropTable
21 | DROP TABLE "_CharacterArchetypes";
22 |
--------------------------------------------------------------------------------
/client/src/libs/compass-web-journal/components/editor.css:
--------------------------------------------------------------------------------
1 | .DraftEditor-root {
2 | height: 100% !important;
3 | width: 100%;
4 | }
5 |
6 | .DraftEditor-root figure {
7 | margin: 0;
8 | }
9 |
10 | .text-align-left > .public-DraftStyleDefault-block {
11 | text-align: left;
12 | }
13 |
14 | .text-align-center > .public-DraftStyleDefault-block {
15 | text-align: center;
16 | }
17 |
18 | .text-align-right > .public-DraftStyleDefault-block {
19 | text-align: right;
20 | }
21 |
22 | .blockquote > .public-DraftStyleDefault-block {
23 | padding: 0.5rem 0.75rem;
24 | border-left: 4px solid rgba(125, 125, 125, 0.5);
25 | }
26 |
27 |
28 | .DraftEditor-editorContainer .journal-link {
29 | text-decoration: underline;
30 | color: inherit;
31 | }
32 |
33 | .DraftEditor-editorContainer .journal-link:hover {
34 | cursor: pointer
35 | }
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/page/create-page.ts:
--------------------------------------------------------------------------------
1 | import { AuthorizationContext } from '@/infrastructure/types';
2 | import { CreatePageMutationVariables } from '../../generated-types';
3 | import { convertEntityId, createPageUtil } from '../_shared';
4 | import { dbClient } from '@/database';
5 |
6 | export const createPage = async (
7 | parent: any,
8 | args: CreatePageMutationVariables,
9 | context: AuthorizationContext,
10 | ) => {
11 | const { input } = args;
12 | const { toEntity } = convertEntityId(input.rulesetId);
13 |
14 | const db = dbClient();
15 |
16 | const { page, sheet } = await createPageUtil({ db, input });
17 |
18 | return {
19 | ...page,
20 | id: page.entityId,
21 | parentId: page.parentId ? toEntity(page.parentId) : undefined,
22 | sheetId: sheet.entityId,
23 | };
24 | };
25 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-composites/composites/sheets/sheet-attribute-control/text-attribute-node.tsx:
--------------------------------------------------------------------------------
1 | import { Stack, Tooltip } from '@chakra-ui/react';
2 |
3 | interface Props {
4 | renderedAttributeValue: string | number | null;
5 | alwaysShowSign?: boolean;
6 | attributeDescription?: string;
7 | }
8 |
9 | export const TextAttributeNode = ({
10 | alwaysShowSign,
11 | renderedAttributeValue,
12 | attributeDescription,
13 | }: Props) => {
14 | const numberIsPositive = parseFloat(`${renderedAttributeValue}`) >= 0;
15 |
16 | return (
17 |
18 |
19 | {alwaysShowSign && numberIsPositive && +}
20 | {renderedAttributeValue}
21 |
22 |
23 | );
24 | };
25 |
--------------------------------------------------------------------------------
/client/src/pages/settings/settings-button.tsx:
--------------------------------------------------------------------------------
1 | import { IconButton, Tooltip } from '@/libs/compass-core-ui';
2 | import { SettingsContext } from '@/libs/compass-web-utils';
3 | import { Settings } from '@mui/icons-material';
4 | import { useContext } from 'react';
5 |
6 | interface Props {
7 | defaultPage?: string;
8 | }
9 |
10 | export const SettingsButton = ({ defaultPage }: Props) => {
11 | const { openSettingsModal, setSettingsPage } = useContext(SettingsContext);
12 |
13 | const handleOpen = () => {
14 | if (defaultPage) {
15 | setSettingsPage(defaultPage);
16 | }
17 |
18 | openSettingsModal(true);
19 | };
20 |
21 | return (
22 |
23 |
24 |
25 |
26 |
27 | );
28 | };
29 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug, enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Additional context**
32 | Add any other context about the problem here.
33 |
--------------------------------------------------------------------------------
/client/src/components/error-boundary.tsx:
--------------------------------------------------------------------------------
1 | import { ErrorPage } from '@/libs/compass-core-ui';
2 | import { ReactNode } from 'react';
3 | import { ErrorBoundary as ReactErrorBoundary } from 'react-error-boundary';
4 |
5 | interface ErrorBoundaryProps {
6 | children: ReactNode;
7 | }
8 |
9 | export const ErrorBoundary = ({ children }: ErrorBoundaryProps) => {
10 | const Fallback = (
11 |
22 |
23 |
24 | );
25 |
26 | return {children};
27 | };
28 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/checkbox/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassDarkTheme, compassLightTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Checkbox' {}
5 |
6 | const injectTheme = (): void => {
7 | [compassLightTheme, compassDarkTheme].forEach((theme) => {
8 | theme.components.MuiCheckbox = {
9 | variants: [],
10 | styleOverrides: {
11 | root: {
12 | '&.Mui-checked': {
13 | color: theme.palette.secondary.main,
14 | },
15 | '&.Mui-focusVisible': {
16 | outline: '1px solid',
17 | outlineColor: compassDarkTheme.palette.info.main,
18 | outlineOffset: '2px',
19 | },
20 | },
21 | },
22 | };
23 | });
24 | };
25 |
26 | export default injectTheme;
27 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/composites/form/radio.tsx:
--------------------------------------------------------------------------------
1 | import { FormControlLabel, Radio, RadioProps } from '@mui/material';
2 | import { useContext } from 'react';
3 | import { FormContext } from './form';
4 |
5 | interface FormRadioProps extends Partial {
6 | /**
7 | * Used to match input to formik values.
8 | */
9 | id?: string;
10 |
11 | /**
12 | * Optionally renders a label
13 | */
14 | label: string;
15 | }
16 |
17 | export const FormRadio = ({ label, id, ...others }: FormRadioProps) => {
18 | const { formDisabled } = useContext(FormContext);
19 | const genId = id ?? label.toLowerCase().replace(' ', '-');
20 |
21 | return (
22 | }
26 | />
27 | );
28 | };
29 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/pubsub.ts:
--------------------------------------------------------------------------------
1 | import { RedisPubSub } from 'graphql-redis-subscriptions';
2 | import { Redis, RedisOptions } from 'ioredis';
3 |
4 | const REDIS_URL = process.env.REDIS_URL || 'localhost';
5 | const REDIS_PORT = process.env.REDIS_PORT || '6379';
6 | const REDIS_USER = process.env.REDIS_USER || 'default';
7 | const REDIS_PASSWORD = process.env.REDIS_PASSWORD;
8 |
9 | const options: RedisOptions = {
10 | host: REDIS_URL,
11 | port: parseInt(REDIS_PORT),
12 | username: REDIS_USER,
13 | password: REDIS_PASSWORD,
14 | retryStrategy: (times) => {
15 | // reconnect after
16 | return Math.min(times * 50, 2000);
17 | },
18 | };
19 |
20 | const sub = new Redis(options);
21 | const pub = new Redis(options);
22 |
23 | export const pubsub = new RedisPubSub({
24 | publisher: pub,
25 | subscriber: sub,
26 | });
27 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/stepper/index.tsx:
--------------------------------------------------------------------------------
1 | import MUIStep, { StepProps as MUIStepProps } from '@mui/material/Step';
2 | import MUIStepLabel, { StepLabelProps as MUIStepLabelProps } from '@mui/material/StepLabel';
3 | import MUIStepper, { StepperProps as MUIStepperProps } from '@mui/material/Stepper';
4 |
5 | import type { JSX } from "react";
6 |
7 | export type StepperProps = MUIStepperProps;
8 | export type StepProps = MUIStepProps;
9 | export type StepLabelProps = MUIStepLabelProps;
10 |
11 | export const Stepper = ({ ...baseProps }: StepperProps): JSX.Element => (
12 |
13 | );
14 |
15 | export const Step = ({ ...baseProps }: StepProps): JSX.Element => ;
16 |
17 | export const StepLabel = ({ ...baseProps }: StepLabelProps): JSX.Element => (
18 |
19 | );
20 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/v2/ui/progress.tsx:
--------------------------------------------------------------------------------
1 | import * as ProgressPrimitive from '@radix-ui/react-progress';
2 | import * as React from 'react';
3 |
4 | import { cn } from '@/libs/compass-core-ui/utils';
5 |
6 | function Progress({
7 | className,
8 | value,
9 | ...props
10 | }: React.ComponentProps) {
11 | return (
12 |
16 |
21 |
22 | );
23 | }
24 |
25 | export { Progress };
26 |
--------------------------------------------------------------------------------
/client/src/pages/ruleset/charts/utils.ts:
--------------------------------------------------------------------------------
1 | import { GridColumn } from '@/libs/compass-core-composites';
2 | import { generateId } from '@/libs/compass-web-utils';
3 |
4 | interface IGenericGridRow {}
5 |
6 | export const getHeaderRow = (rows: string[], editable = true): GridColumn[] => {
7 | return rows.map((row) => ({
8 | field: row,
9 | headerName: row,
10 | width: 150,
11 | editable,
12 | filter: true,
13 | }));
14 | };
15 |
16 | export const buildRows = (rows: string[][], headerRow: string[]) => {
17 | return !rows.length
18 | ? []
19 | : rows.slice(1).map((valueArray) => {
20 | const row: any = {};
21 |
22 | valueArray.forEach((value, index) => {
23 | row[headerRow[index]] = value;
24 | });
25 |
26 | row._id = generateId();
27 |
28 | return row;
29 | });
30 | };
31 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20240214155718_items/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "Item" (
3 | "id" TEXT NOT NULL,
4 | "entityId" TEXT NOT NULL,
5 | "rulesetId" TEXT NOT NULL,
6 | "moduleId" TEXT,
7 | "moduleTitle" TEXT,
8 | "title" TEXT NOT NULL,
9 | "description" TEXT,
10 | "imageId" TEXT,
11 | "logic" JSONB NOT NULL DEFAULT '[]',
12 | "category" TEXT,
13 | "details" JSONB NOT NULL DEFAULT '{}',
14 |
15 | CONSTRAINT "Item_pkey" PRIMARY KEY ("id")
16 | );
17 |
18 | -- AddForeignKey
19 | ALTER TABLE "Item" ADD CONSTRAINT "Item_rulesetId_fkey" FOREIGN KEY ("rulesetId") REFERENCES "Ruleset"("id") ON DELETE CASCADE ON UPDATE CASCADE;
20 |
21 | -- AddForeignKey
22 | ALTER TABLE "Item" ADD CONSTRAINT "Item_imageId_fkey" FOREIGN KEY ("imageId") REFERENCES "Image"("id") ON DELETE SET NULL ON UPDATE CASCADE;
23 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/v2/ui/separator.tsx:
--------------------------------------------------------------------------------
1 | 'use client';
2 |
3 | import * as SeparatorPrimitive from '@radix-ui/react-separator';
4 | import * as React from 'react';
5 |
6 | import { cn } from '@/libs/compass-core-ui/utils';
7 |
8 | function Separator({
9 | className,
10 | orientation = 'horizontal',
11 | decorative = true,
12 | ...props
13 | }: React.ComponentProps) {
14 | return (
15 |
25 | );
26 | }
27 |
28 | export { Separator };
29 |
--------------------------------------------------------------------------------
/server/.env:
--------------------------------------------------------------------------------
1 | # .env and ./server/.env should be identical
2 |
3 | # Optionally change these to use whatever DB name and password you'd like
4 | DATABASE_NAME=qbdb
5 | DATABASE_PASSWORD=password
6 | ###############################################
7 |
8 | # These should not be changed
9 | MODE=local
10 | PORT=8000
11 | DATABASE_PORT=5432
12 | DATABASE_HOST=localhost
13 | REDIS_URL=localhost
14 | ###############################################
15 |
16 | # If you changed the DATABASE_NAME or DATABASE_PASSWORD, you must update these
17 | # The DATABASE_NAME should match the string following :5432/ in DATABASE_URL and :6543/ in DIRECT_URL
18 | # The DATABASE_PASSWORD should follow 'postgres:'
19 | DATABASE_URL="postgres://postgres:password@localhost:5432/qbdb?pgbouncer=true"
20 | DIRECT_URL="postgres://postgres:password@localhost:5432/qbdb"
21 | ###############################################
22 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/v2/ui/textarea.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 |
3 | import { cn } from '@/libs/compass-core-ui/utils';
4 |
5 | function Textarea({ className, ...props }: React.ComponentProps<'textarea'>) {
6 | return (
7 |
15 | );
16 | }
17 |
18 | export { Textarea };
19 |
--------------------------------------------------------------------------------
/server/src/infrastructure/graphql/services/image/create-image.ts:
--------------------------------------------------------------------------------
1 | import { dbClient } from '@/database';
2 | import { CreateImage } from '@/infrastructure/graphql';
3 | import { AuthorizationContext, ResolverInput } from '@/infrastructure/types';
4 |
5 | export const createImage = async (
6 | parent: any,
7 | args: ResolverInput,
8 | context: AuthorizationContext,
9 | ) => {
10 | const { userId } = context;
11 | const { input } = args;
12 |
13 | const db = dbClient();
14 |
15 | const image = await db.image.create({
16 | data: {
17 | ...input,
18 | userId,
19 | src: input.src ?? undefined,
20 | sortIndex: input.sortIndex ?? undefined,
21 | details: input.details ?? undefined,
22 | },
23 | });
24 |
25 | return {
26 | ...image,
27 | details: image.details ? JSON.stringify(image.details) : undefined,
28 | };
29 | };
30 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20231011163901_public_dependencies/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - You are about to drop the `_ModuleDependencies` table. If the table is not empty, all the data it contains will be lost.
5 |
6 | */
7 | -- DropForeignKey
8 | ALTER TABLE "_ModuleDependencies" DROP CONSTRAINT "_ModuleDependencies_A_fkey";
9 |
10 | -- DropForeignKey
11 | ALTER TABLE "_ModuleDependencies" DROP CONSTRAINT "_ModuleDependencies_B_fkey";
12 |
13 | -- AlterTable
14 | ALTER TABLE "PublishedRuleset" ADD COLUMN "dependenciesArePublic" BOOLEAN NOT NULL DEFAULT false,
15 | ADD COLUMN "isPublic" BOOLEAN NOT NULL DEFAULT false;
16 |
17 | -- AlterTable
18 | ALTER TABLE "Ruleset" ADD COLUMN "dependenciesArePublic" BOOLEAN NOT NULL DEFAULT false,
19 | ADD COLUMN "isPublic" BOOLEAN NOT NULL DEFAULT false;
20 |
21 | -- DropTable
22 | DROP TABLE "_ModuleDependencies";
23 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | # .env and ./server/.env should be identical
2 |
3 | # Optionally change these to use whatever DB name and password you'd like
4 | DATABASE_NAME=qbdb
5 | DATABASE_PASSWORD=password
6 | ###############################################
7 |
8 | # These should not be changed
9 | MODE=local
10 | PORT=8000
11 | DATABASE_PORT=5432
12 | DATABASE_HOST=quest-bound-db
13 | REDIS_URL=quest-bound-redis
14 | ###############################################
15 |
16 | # If you changed the DATABASE_NAME or DATABASE_PASSWORD, you must update these
17 | # The DATABASE_NAME should match the string following :5432/ in DATABASE_URL and :6543/ in DIRECT_URL
18 | # The DATABASE_PASSWORD should follow 'postgres:'
19 | DATABASE_URL="postgres://postgres:password@quest-bound-db:6543/qbdb?pgbouncer=true"
20 | DIRECT_URL="postgres://postgres:password@quest-bound-db:5432/qbdb"
21 | ###############################################
22 |
--------------------------------------------------------------------------------
/client/src/libs/compass-api/hooks/pages/use-page-templates.ts:
--------------------------------------------------------------------------------
1 | import { useParams } from 'react-router-dom';
2 | import { pageTemplates, PageTemplatesQuery, PageTemplatesQueryVariables, Sheet } from '../../gql';
3 | import { useQuery } from '../../utils';
4 | import { useError } from '../metrics';
5 |
6 | export const usePageTemplates = () => {
7 | const { rulesetId } = useParams();
8 |
9 | const { data, loading, error } = useQuery(
10 | pageTemplates,
11 | {
12 | variables: {
13 | rulesetId: rulesetId ?? '',
14 | },
15 | skip: !rulesetId,
16 | },
17 | );
18 |
19 | useError({
20 | error,
21 | message: 'Failed to load pages',
22 | });
23 |
24 | const templates: Sheet[] = data?.pageTemplates ?? [];
25 |
26 | return {
27 | pages: templates,
28 | loading,
29 | error,
30 | };
31 | };
32 |
--------------------------------------------------------------------------------
/client/src/libs/compass-planes/common/hooks/use-navigate-tabs.ts:
--------------------------------------------------------------------------------
1 | import { SheetTab } from '@/libs/compass-api';
2 | import { useSearchParams } from 'react-router-dom';
3 |
4 | export const useNavigateTabs = (tabs: SheetTab[]) => {
5 | const [searchParams, setSearchParams] = useSearchParams();
6 |
7 | const directTabId = searchParams.get('tab');
8 |
9 | const sortedTabs = [...tabs].sort((a, b) => a.position - b.position);
10 |
11 | const directTabFound = tabs.find((t) => t.tabId === directTabId);
12 |
13 | const defaultTabId =
14 | directTabId && directTabFound ? directTabId : sortedTabs.length > 0 ? sortedTabs[0].tabId : '';
15 |
16 | const activeTab = defaultTabId;
17 |
18 | const setActiveTab = (id: string) => {
19 | searchParams.set('tab', id);
20 | setSearchParams(searchParams);
21 | };
22 |
23 | return {
24 | activeTab,
25 | setActiveTab,
26 | };
27 | };
28 |
--------------------------------------------------------------------------------
/client/src/components/description-modal.tsx:
--------------------------------------------------------------------------------
1 | import { Modal, Stack, Text } from '@/libs/compass-core-ui';
2 | import { useState } from 'react';
3 | import { Description } from './description';
4 |
5 | interface Props {
6 | value: string;
7 | title: string;
8 | }
9 |
10 | export const DescriptionModal = ({ value, title }: Props) => {
11 | const [modalOpen, setModalOpen] = useState(false);
12 |
13 | return (
14 | <>
15 | setModalOpen(true)}>
20 | Description
21 |
22 | setModalOpen(false)}>
23 |
24 |
25 |
26 |
27 | >
28 | );
29 | };
30 |
--------------------------------------------------------------------------------
/client/src/libs/compass-core-ui/components/switch/theme.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable @typescript-eslint/no-empty-interface */
2 | import { compassDarkTheme } from '../../theme';
3 |
4 | declare module '@mui/material/Switch' {}
5 |
6 | const injectTheme = (): void => {
7 | compassDarkTheme.components.MuiSwitch = {
8 | variants: [],
9 | defaultProps: {
10 | size: 'small',
11 | },
12 | styleOverrides: {
13 | root: {
14 | '& .MuiSwitch-switchBase.Mui-checked': {
15 | color: compassDarkTheme.palette.secondary.main,
16 | },
17 |
18 | '& .MuiSwitch-switchBase': {
19 | '&.Mui-focusVisible': {
20 | outline: '1px solid',
21 | outlineColor: compassDarkTheme.palette.info.main,
22 | outlineOffset: '2px',
23 | },
24 | },
25 | },
26 | },
27 | };
28 | };
29 |
30 | export default injectTheme;
31 |
--------------------------------------------------------------------------------
/server/src/database/prisma/migrations/20231017152235_pub_rs_created_by/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - You are about to drop the column `listed` on the `PublishedRuleset` table. All the data in the column will be lost.
5 | - You are about to drop the column `price` on the `PublishedRuleset` table. All the data in the column will be lost.
6 | - You are about to drop the column `username` on the `PublishedRuleset` table. All the data in the column will be lost.
7 | - Added the required column `createdBy` to the `PublishedRuleset` table without a default value. This is not possible if the table is not empty.
8 |
9 | */
10 | -- AlterTable
11 | ALTER TABLE "PublishedRuleset" DROP COLUMN "listed",
12 | DROP COLUMN "price",
13 | DROP COLUMN "username",
14 | ADD COLUMN "createdBy" TEXT NOT NULL;
15 |
16 | -- AlterTable
17 | ALTER TABLE "Ruleset" ADD COLUMN "version" INTEGER NOT NULL DEFAULT 1;
18 |
--------------------------------------------------------------------------------