Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
c2de70d
Created rodux store and added flare actions and reducer
adam-drake1 Nov 29, 2022
65a4343
chore: update eslintrc
christopher-buss Dec 2, 2022
97145f4
Merge remote-tracking branch 'origin/main' into CU-3wekf8k_Flare
adam-drake1 Dec 2, 2022
cacc1fc
Moved package in studio to ReplicatedStorage so Roact components are …
adam-drake1 Dec 7, 2022
e0bda0c
Created a modal component which supports displaying in game and in Ho…
adam-drake1 Dec 7, 2022
09be31a
Merge remote-tracking branch 'origin/CU-384j922_Update-eslintrc' into…
adam-drake1 Dec 7, 2022
4adb55f
export StoreState and ClientStore type for use with rodux hooks
adam-drake1 Dec 7, 2022
70468b0
install roact-hooked and roact-rodux hooked
adam-drake1 Dec 7, 2022
ec10801
move rodux-utils to existing utilities folder
adam-drake1 Dec 7, 2022
ac4531a
move rodux-utils to existing utilities folder
adam-drake1 Dec 7, 2022
ad3013b
Moved functions relating to making Hoarcekat congruent with playing t…
adam-drake1 Dec 7, 2022
1fb6f17
Added message parameter to FireFlare action
adam-drake1 Dec 8, 2022
545225d
created common IFlare interface
adam-drake1 Dec 12, 2022
946fff3
created common padding element
adam-drake1 Dec 12, 2022
efff0a2
created ThemeContext for uniform text and frame styling
adam-drake1 Dec 12, 2022
dfad188
Fix jsxFragmentFactory setting
adam-drake1 Dec 12, 2022
fbdd178
Initial Flare and Console UI
adam-drake1 Dec 13, 2022
54ece0c
override no-unused-vars due to issue in .tsx files with Roact import
adam-drake1 Dec 15, 2022
bd2ab89
disable explicit-function-return-types for expressions
adam-drake1 Dec 15, 2022
b83b074
fix eslint warnings
adam-drake1 Dec 15, 2022
deb6902
Merge branch 'main' of https://github.com/AetherInteractiveLtd/Tina i…
RigidOfficial Feb 12, 2023
c222b60
merge
RigidOfficial Feb 14, 2023
fd3dc5f
console stuff
RigidOfficial Feb 15, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 15 additions & 5 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@
"ignoreVoid": true
}
],
"@typescript-eslint/no-explicit-any": "warn",
"@typescript-eslint/no-unused-vars": "warn",
"@typescript-eslint/explicit-function-return-type": "warn",
"@typescript-eslint/explicit-function-return-type": [
"warn", {
"allowExpressions": true
}
],
"@typescript-eslint/interface-name-prefix": "off",
"@typescript-eslint/no-empty-function": "off",
"@typescript-eslint/no-empty-interface": "off",
Expand Down Expand Up @@ -85,11 +88,18 @@
"allowEmptyCatch": true
}
],
"no-void": "off",
"no-extra-boolean-cast": "off",
"no-undef-init": "error",
"prefer-const": "off",
"simple-import-sort/exports": "warn",
"simple-import-sort/imports": "warn"
}
}
},
"overrides": [
{
"files": ["*.tsx"],
"rules": {
"@typescript-eslint/no-unused-vars": "off"
}
}
]
}
341 changes: 335 additions & 6 deletions package-lock.json

Large diffs are not rendered by default.

9 changes: 7 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "@rbxts/tina",
"name": "tina",
"version": "1.0.0",
"description": "",
"main": "out/init.lua",
Expand Down Expand Up @@ -45,7 +45,12 @@
},
"dependencies": {
"@eslint/github-action": "^0.1.0",
"@rbxts/roact": "^1.4.4-ts.0",
"@rbxts/roact-hooked": "^2.1.3",
"@rbxts/roact-rodux-hooked": "^1.1.3",
"@rbxts/rodux": "^3.0.0-ts.3",
"@rbxts/rowind-mini": "^1.0.0",
"@rbxts/services": "^1.5.1",
"roblox-ts": "^2.0.4"
}
}
}
21 changes: 16 additions & 5 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import Scheduler from "./lib/process/scheduler";
import { Users } from "./lib/user";
import { AbstractUser } from "./lib/user/default";
import { UserType } from "./lib/user/default/types";
/* User abstraction class */
import { ConsoleActionName } from "./lib/user-interface/console/console-actions";
import { ClientStore } from "./lib/user-interface/store";
import { formatFlareTraceback } from "./lib/utilities/string-utils";

export enum Protocol {
/** Create/Load Online User Data */
Expand Down Expand Up @@ -48,8 +52,6 @@ namespace Tina {
Identifiers._init();
}

Logger.setName(name);

// TODO: Auto-Detect `manifest.tina.yml` and load it.
return new TinaGame();
}
Expand Down Expand Up @@ -81,8 +83,6 @@ namespace Tina {
*/
export function setUserClass(userClass: new (ref: Player | number) => UserType): void {
Users.changeUserClass(userClass); // Changes internally the way user is defined and constructed

Logger.warn("The User Class has been changed to:", userClass); // Not sure why this is being warned at all.
}

/**
Expand All @@ -106,7 +106,18 @@ namespace Tina {
return new Process(name, Scheduler);
}

export const Logger = new Scope("unnamed");
export function flare(eventName: string): void {
ClientStore.dispatch({ type: ConsoleActionName.AddFlare, eventName });
}

export function oops(eventName: string): void {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was sarcasm, please find a better name for firing flares 😅

const message = formatFlareTraceback(debug.traceback(undefined, 1));
ClientStore.dispatch({ type: ConsoleActionName.FireFlare, eventName, message });
}

export function getLogger(): void {
return;
}

/**
* Used to connect to Tina's internal events, such as when a user is registed, etc.
Expand Down
2 changes: 2 additions & 0 deletions src/lib/types/common.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export type IFlare = { eventName: string; amount: number; message?: string };
export type EnumOrName<T extends EnumItem> = T | T["Name"];
16 changes: 16 additions & 0 deletions src/lib/ui/console/console.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import Roact from "@rbxts/roact";
import { Div } from "@rbxts/rowind-mini";

export = function (parent: Instance) {
const UI = (
<Div className="bg-gray-800 w-100% h-100%">
<Div className="bg-gray-700 w-100% h-12% flex-left"></Div>
</Div>
);

const MountedUI = Roact.mount(UI, parent);

return function () {
Roact.unmount(MountedUI);
};
};
32 changes: 32 additions & 0 deletions src/lib/user-interface/common/padding.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Roact from "@rbxts/roact";

interface Props {
All?: number;
Horizontal?: number;
Vertical?: number;
Top?: number;
Bottom?: number;
Left?: number;
Right?: number;
}

const Padding: Roact.FunctionComponent<Props> = ({
All = 0,
Horizontal = 0,
Vertical = 0,
Top = 0,
Bottom = 0,
Right = 0,
Left = 0,
}: Props) => {
return (
<uipadding
PaddingBottom={new UDim(0, Bottom + Vertical + All)}
PaddingTop={new UDim(0, Top + Vertical + All)}
PaddingLeft={new UDim(0, Left + Horizontal + All)}
PaddingRight={new UDim(0, Right + Horizontal + All)}
/>
);
};

export default Padding;
15 changes: 15 additions & 0 deletions src/lib/user-interface/console/components/circle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Roact, { JsxInstanceProperties } from "@rbxts/roact";
import { withHooks } from "@rbxts/roact-hooked";

type CircleProps = JsxInstanceProperties<Frame>;

const Circle = withHooks((props: CircleProps) => {
return (
<frame {...props}>
<uicorner CornerRadius={new UDim(1, 0)} />
<uiaspectratioconstraint AspectRatio={1} />
</frame>
);
});

export default Circle;
14 changes: 14 additions & 0 deletions src/lib/user-interface/console/components/console.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Roact from "@rbxts/roact";
import { withHooks } from "@rbxts/roact-hooked";

import Header from "./header";

const Console = withHooks(() => {
return (
<frame Size={new UDim2(1, 0, 1, 0)} Transparency={1}>
<Header />
</frame>
);
});

export default Console;
47 changes: 47 additions & 0 deletions src/lib/user-interface/console/components/flare-bar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Roact, { JsxInstanceProperties } from "@rbxts/roact";
import { useCallback, useState, withHooks } from "@rbxts/roact-hooked";
import { useSelector } from "@rbxts/roact-rodux-hooked";

import { IFlare } from "../../../types/common";
import Padding from "../../common/padding";
import { StoreState } from "../../store";
import Flare from "./flare";

type FlareBarProps = Partial<Pick<JsxInstanceProperties<Frame>, "Position" | "AnchorPoint" | "Size">>;

export const FlareBar = withHooks((props: FlareBarProps) => {
const { Size = new UDim2(1, 0, 0, 36) } = props;
const flares = useSelector((state: StoreState) => state.flares);
const [selected, setSelected] = useState<IFlare | undefined>();

const handleClick = useCallback((flare: IFlare) => {
setSelected(selected => {
if (flare.amount === 0) return;
return flare === selected ? undefined : flare;
});
}, []);

return (
<scrollingframe
Size={Size}
Position={props.Position}
AnchorPoint={props.AnchorPoint}
BackgroundTransparency={1}
CanvasSize={new UDim2(1, 0, 0, 36)}
AutomaticCanvasSize={"X"}
ScrollingDirection={"X"}
ScrollBarThickness={0}
>
<uilistlayout
FillDirection={"Horizontal"}
HorizontalAlignment={"Left"}
VerticalAlignment={"Center"}
Padding={new UDim(0, 4)}
/>
<Padding Horizontal={3} />
{flares.map((flare, i) => (
<Flare Key={i} Info={flare} Selected={flare === selected} OnClick={handleClick} />
))}
</scrollingframe>
);
});
65 changes: 65 additions & 0 deletions src/lib/user-interface/console/components/flare.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import Roact, { Element } from "@rbxts/roact";
import { useRef, withHooksPure } from "@rbxts/roact-hooked";
import { TextService } from "@rbxts/services";

import { IFlare } from "../../../types/common";
import { getAbsolutePosition } from "../../../utilities/hoarcekat";
import Padding from "../../common/padding";
import { useTheme } from "../../theme/theme";
import Circle from "./circle";
import Tooltip from "./tooltip";

interface Props {
Info: IFlare;
Selected: boolean;
OnClick: (flare: IFlare) => void;
}

const Flare = withHooksPure(({ Info, Selected, OnClick }: Props) => {
const { eventName, amount, message } = Info;
const theme = useTheme();
const buttonRef = useRef<TextButton>();

const text = `${eventName} ${amount}x`;
const textSize = TextService.GetTextSize(text, theme.FontSize, theme.Font, new Vector2(math.huge, math.huge));
const circleColour = amount > 0 ? Color3.fromRGB(255, 18, 18) : Color3.fromRGB(18, 18, 255);

let tooltip: Element | undefined;
if (Selected) {
const button = buttonRef.getValue()!;
const { X: positionX, Y: positionY } = getAbsolutePosition(button);
const { Y: sizeY } = button.AbsoluteSize;
const tooltipPosition = UDim2.fromOffset(positionX - 3, positionY + sizeY + 8);
tooltip = <Tooltip Message={message} Position={tooltipPosition} />;
}

return (
<textbutton
Ref={buttonRef}
Size={UDim2.fromOffset(textSize.X, 30)}
AutomaticSize={"X"}
Text=""
BackgroundColor3={theme.SecondaryBackgroundColor3}
Event={{
Activated: () => OnClick(Info),
}}
>
<Padding Horizontal={7} />
<uicorner CornerRadius={new UDim(0.4, 0)} />
<uilistlayout FillDirection={"Horizontal"} VerticalAlignment={"Center"} Padding={new UDim(0, 4)} />
<Circle Size={UDim2.fromOffset(10, 10)} BackgroundColor3={circleColour} />
<textlabel
TextColor3={new Color3(0.9, 0.9, 0.9)}
Text={text}
Font={theme.Font}
TextSize={theme.FontSize}
Size={UDim2.fromOffset(textSize.X, 32)}
BackgroundTransparency={1}
/>
<uistroke Color={theme.PrimaryTextColor3} Thickness={Selected ? 1 : 0} ApplyStrokeMode={"Border"} />
{tooltip}
</textbutton>
);
});

export default Flare;
21 changes: 21 additions & 0 deletions src/lib/user-interface/console/components/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Roact from "@rbxts/roact";
import { withHooksPure } from "@rbxts/roact-hooked";

import { useTheme } from "../../theme/theme";
import { FlareBar } from "./flare-bar";

const Header = withHooksPure(() => {
const theme = useTheme();

return (
<frame
Size={new UDim2(1, 0, 0, 72)}
BackgroundColor3={theme.PrimaryBackgroundColor3}
BorderColor3={theme.SecondaryBackgroundColor3}
>
<FlareBar Position={UDim2.fromScale(0, 1)} AnchorPoint={new Vector2(0, 1)} />
</frame>
);
});

export default Header;
57 changes: 57 additions & 0 deletions src/lib/user-interface/console/components/modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/// <reference types="@rbxts/types/plugin" />

import Roact, { Children, Portal } from "@rbxts/roact";
import { withHooks } from "@rbxts/roact-hooked";
import { Players, RunService } from "@rbxts/services";

import { hoarcekatFrame } from "../../../utilities/hoarcekat";

const isGameRunning = RunService.IsRunning();

/**
* Modal which can be used with .story scripts. Generally a modal will be added directly to the PlayerGui, but
* since .story scripts are ran inside studio PlayerGui won't exists. Instead, we'll parent the modal directly
* to Hoarcekat's preview window, simulating a modal without running the game.
*
* This is not perfect as the AbsolutePosition of the preview window is about (154, 5) rather than (0, 0), so
* the position may be skewed when positioning components absolutely. But it's better than the component erroring.
*/
const HoarcekatModal = withHooks(props => {
const parent = hoarcekatFrame;
if (!parent) {
warn("Unable to find Hoarcekat preview window");
return <frame />;
}

const made = (
<Portal target={parent}>
<frame Size={UDim2.fromScale(1, 1)} Transparency={1} ZIndex={10000}>
{props[Children]}
</frame>
</Portal>
);

return made;
});

/**
* Modal which parents itself to the PlayerGui and renders children in a separate ScreenGui
*/
const GameRunningModal = withHooks(props => {
const playerGui = Players.LocalPlayer.FindFirstChildOfClass("PlayerGui")!;
return (
<Portal target={playerGui}>
<screengui DisplayOrder={10000}>{props[Children]}</screengui>
</Portal>
);
});

const Modal = withHooks(props => {
return isGameRunning ? (
<GameRunningModal>{props[Children]}</GameRunningModal>
) : (
<HoarcekatModal>{props[Children]}</HoarcekatModal>
);
});

export default Modal;
Loading