💻 React !
This commit is contained in:
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -6,7 +6,7 @@
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"[typescriptreact]": {
|
||||
"editor.defaultFormatter": "dbaeumer.vscode-eslint",
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"editor.formatOnSave": true
|
||||
},
|
||||
"eslint.run": "onType",
|
||||
|
||||
@@ -39,7 +39,9 @@
|
||||
"@flamework/components": "^1.3.2",
|
||||
"@flamework/core": "^1.3.2",
|
||||
"@flamework/networking": "^1.3.2",
|
||||
"@rbxts/fusion-0.3-temp": "^0.7.2",
|
||||
"@rbxts/object-utils": "^1.0.4"
|
||||
"@rbxts/object-utils": "^1.0.4",
|
||||
"@rbxts/pretty-react-hooks": "^0.6.4",
|
||||
"@rbxts/react": "^17.2.3",
|
||||
"@rbxts/react-roblox": "^17.2.3"
|
||||
}
|
||||
}
|
||||
70
pnpm-lock.yaml
generated
70
pnpm-lock.yaml
generated
@@ -17,12 +17,18 @@ importers:
|
||||
'@flamework/networking':
|
||||
specifier: ^1.3.2
|
||||
version: 1.3.2(@flamework/core@1.3.2)
|
||||
'@rbxts/fusion-0.3-temp':
|
||||
specifier: ^0.7.2
|
||||
version: 0.7.2
|
||||
'@rbxts/object-utils':
|
||||
specifier: ^1.0.4
|
||||
version: 1.0.4
|
||||
'@rbxts/pretty-react-hooks':
|
||||
specifier: ^0.6.4
|
||||
version: 0.6.4(@rbxts/react-roblox@17.2.3)(@rbxts/react@17.2.3)
|
||||
'@rbxts/react':
|
||||
specifier: ^17.2.3
|
||||
version: 17.2.3
|
||||
'@rbxts/react-roblox':
|
||||
specifier: ^17.2.3
|
||||
version: 17.2.3
|
||||
devDependencies:
|
||||
'@eslint/eslintrc':
|
||||
specifier: ^3.3.1
|
||||
@@ -173,18 +179,36 @@ packages:
|
||||
'@rbxts/compiler-types@3.0.0-types.0':
|
||||
resolution: {integrity: sha512-VGOHJPoL7+56NTatMGqQj3K7xWuzEV+aP4QD5vZiHu+bcff3kiTmtoadaF6NkJrmwfFAvbsd4Dg764ZjWNceag==}
|
||||
|
||||
'@rbxts/fusion-0.3-temp@0.7.2':
|
||||
resolution: {integrity: sha512-204MueZ6/3sps9bf4H+usqAL3VO+M5cmHwQnRci0LEF/Q4yV1re/ID96BTYTaWlohI0Vn+yKE45iFYNoclhk5Q==}
|
||||
|
||||
'@rbxts/maid@1.1.0':
|
||||
resolution: {integrity: sha512-bVWXZ0p2M3OJzPzvN5fY0T4s37ezUMY7EX31Xspp7Ds4C/K9yE4MHMRXjtlNvsYVPmoc5tdhAbpZY02Veix5lg==}
|
||||
|
||||
'@rbxts/object-utils@1.0.4':
|
||||
resolution: {integrity: sha512-dLLhf022ipV+9i910sOE7kl9losKHoon0WgeerHqVMQA5EYsLUsVT2AxhJuhk8MiDn5oJ2GiFofE/LadY9TpJQ==}
|
||||
|
||||
'@rbxts/pretty-react-hooks@0.6.4':
|
||||
resolution: {integrity: sha512-yiuM3kOD0s2x0GFCUVfFdeSDJRX2ZycS88WOvqydaYwPIZ5rYDjzHjOzRgSpAzGcTVOFXsO64QOtD6svAdadzg==}
|
||||
peerDependencies:
|
||||
'@rbxts/react': '*'
|
||||
'@rbxts/react-roblox': '*'
|
||||
|
||||
'@rbxts/react-roblox@17.2.3':
|
||||
resolution: {integrity: sha512-YgS+C3tf92iM1NTK1f6R2O2G8+nbcKFnblA0mTs2Nt878OsWLgxhnhkCBZ6wYv+yeDGD9/sssKHZ6s2LzUWTrQ==}
|
||||
|
||||
'@rbxts/react-vendor@17.2.3':
|
||||
resolution: {integrity: sha512-dWCiVelvTK6h920geaFH/OQ5zoWHyhyqyfH51hKx2/iVZ6OiiyNVJ5UqEIkJMG4HsJ8JnkTORizV3+MtQ41BtA==}
|
||||
|
||||
'@rbxts/react@17.2.3':
|
||||
resolution: {integrity: sha512-IoOB8e2W8MxT0MKWFf0Ls0vT61ImYL6ctHQgz5+oazma6z8bqFtJjgPxOuy6jmMSuyfBe7rYp/muou0kIjZT+Q==}
|
||||
|
||||
'@rbxts/ripple@0.9.3':
|
||||
resolution: {integrity: sha512-GmwjQl7a8pvGPGQYLmaAcf2RBPpneOL5P1+U8CzTHt9tBhCdk0TEJ/MQoTv9JnHD62RMBE1jogQBvuGgl9VXAg==}
|
||||
|
||||
'@rbxts/services@1.6.0':
|
||||
resolution: {integrity: sha512-YH02E1/tGHeMXB0Mam8qPdAZa2fjQWdylEscSL4Zn0RIaQeByYImA2qUsXM3nBdhcyKHDwltzSznDKyCGfFEWA==}
|
||||
|
||||
'@rbxts/set-timeout@1.1.2':
|
||||
resolution: {integrity: sha512-P/A0IiH9wuZdSJYr4Us0MDFm61nvIFR0acfKFHLkcOsgvIgELC90Up9ugiSsaMEHRIcIcO5UjE39LuS3xTzQHw==}
|
||||
|
||||
'@rbxts/signal@1.1.1':
|
||||
resolution: {integrity: sha512-WX+ONE+ld4pG9PvRkR8OgDld9NpaV1RfXyUIw+Q2oXP/5rehkYzvt20NWtrLAP3NhMc5inYInLd+hnufey6nFw==}
|
||||
|
||||
@@ -197,9 +221,6 @@ packages:
|
||||
'@rbxts/types@1.0.887':
|
||||
resolution: {integrity: sha512-vhp4vIKEfl1TaBcKxBxU5dTFsVNqLkvefoF9pw/Epb+Jk9T+0g4SFQQtBdCu3UdZcBGK/PWk/IJeEyoRNDMkSw==}
|
||||
|
||||
'@rbxts/ui-labs@2.4.2':
|
||||
resolution: {integrity: sha512-9cyzDYN4mM7KSupZpbHRCUWCfSHzy8LCqa9Czys2jaKYUCn8oV4j5AE+5jTrHD/8RcltP5EvCSFIFwB0N/NfxA==}
|
||||
|
||||
'@roblox-ts/luau-ast@2.0.0':
|
||||
resolution: {integrity: sha512-cmMi093IdwBOLVxwuordhM8AmtbyTIyRpsTbB0D/JauidW4SXsQRQowSwWjHo4QP0DRJBXvOIlxtqEQi50uNzQ==}
|
||||
|
||||
@@ -1078,16 +1099,37 @@ snapshots:
|
||||
|
||||
'@rbxts/compiler-types@3.0.0-types.0': {}
|
||||
|
||||
'@rbxts/fusion-0.3-temp@0.7.2':
|
||||
dependencies:
|
||||
'@rbxts/ui-labs': 2.4.2
|
||||
|
||||
'@rbxts/maid@1.1.0': {}
|
||||
|
||||
'@rbxts/object-utils@1.0.4': {}
|
||||
|
||||
'@rbxts/pretty-react-hooks@0.6.4(@rbxts/react-roblox@17.2.3)(@rbxts/react@17.2.3)':
|
||||
dependencies:
|
||||
'@rbxts/react': 17.2.3
|
||||
'@rbxts/react-roblox': 17.2.3
|
||||
'@rbxts/ripple': 0.9.3
|
||||
'@rbxts/services': 1.6.0
|
||||
'@rbxts/set-timeout': 1.1.2
|
||||
|
||||
'@rbxts/react-roblox@17.2.3':
|
||||
dependencies:
|
||||
'@rbxts/react': 17.2.3
|
||||
'@rbxts/react-vendor': 17.2.3
|
||||
|
||||
'@rbxts/react-vendor@17.2.3': {}
|
||||
|
||||
'@rbxts/react@17.2.3':
|
||||
dependencies:
|
||||
'@rbxts/react-vendor': 17.2.3
|
||||
|
||||
'@rbxts/ripple@0.9.3': {}
|
||||
|
||||
'@rbxts/services@1.6.0': {}
|
||||
|
||||
'@rbxts/set-timeout@1.1.2':
|
||||
dependencies:
|
||||
'@rbxts/services': 1.6.0
|
||||
|
||||
'@rbxts/signal@1.1.1': {}
|
||||
|
||||
'@rbxts/t@2.2.1': {}
|
||||
@@ -1096,8 +1138,6 @@ snapshots:
|
||||
|
||||
'@rbxts/types@1.0.887': {}
|
||||
|
||||
'@rbxts/ui-labs@2.4.2': {}
|
||||
|
||||
'@roblox-ts/luau-ast@2.0.0': {}
|
||||
|
||||
'@roblox-ts/path-translator@1.1.0':
|
||||
|
||||
30
src/client/controllers/gui.tsx
Normal file
30
src/client/controllers/gui.tsx
Normal file
@@ -0,0 +1,30 @@
|
||||
import { Controller, OnStart } from "@flamework/core";
|
||||
import React from "@rbxts/react";
|
||||
import { StrictMode } from "@rbxts/react";
|
||||
import { createPortal, createRoot } from "@rbxts/react-roblox";
|
||||
import { Players, StarterGui } from "@rbxts/services";
|
||||
import PlayersBoard from "shared/gui/players_board";
|
||||
|
||||
@Controller()
|
||||
class GuiController implements OnStart {
|
||||
onStart(): void {
|
||||
StarterGui.SetCoreGuiEnabled(Enum.CoreGuiType.All, false);
|
||||
StarterGui.SetCoreGuiEnabled(Enum.CoreGuiType.Chat, true);
|
||||
try {
|
||||
StarterGui.SetCore("ResetButtonCallback", true);
|
||||
} catch (error) {}
|
||||
|
||||
const root = createRoot(new Instance("Folder"));
|
||||
|
||||
root.render(
|
||||
<StrictMode>
|
||||
{createPortal(
|
||||
<screengui>
|
||||
<PlayersBoard />
|
||||
</screengui>,
|
||||
(Players.LocalPlayer as unknown as { PlayerGui: PlayerGui }).PlayerGui,
|
||||
)}
|
||||
</StrictMode>,
|
||||
);
|
||||
}
|
||||
}
|
||||
4
src/shared/gui/players_board/index.story.ts
Normal file
4
src/shared/gui/players_board/index.story.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { hoarcekat } from "@rbxts/pretty-react-hooks";
|
||||
import PlayersBoard from ".";
|
||||
|
||||
export = hoarcekat(PlayersBoard);
|
||||
108
src/shared/gui/players_board/index.tsx
Normal file
108
src/shared/gui/players_board/index.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
import { lerp, useMotion } from "@rbxts/pretty-react-hooks";
|
||||
import React, { Component, ReactNode, StrictMode, useEffect, useState } from "@rbxts/react";
|
||||
import { Players } from "@rbxts/services";
|
||||
import Profile from "./profile";
|
||||
|
||||
function PlayerEntry({
|
||||
player,
|
||||
selectedPlayer,
|
||||
setSelectedPlayer,
|
||||
}: {
|
||||
player: Player;
|
||||
setSelectedPlayer: React.Dispatch<React.SetStateAction<Player | undefined>>;
|
||||
selectedPlayer: Player | undefined;
|
||||
}) {
|
||||
const [enable, enableMotor] = useMotion(0);
|
||||
useEffect(() => {
|
||||
if (player === selectedPlayer) {
|
||||
enableMotor.spring(90);
|
||||
} else {
|
||||
enableMotor.spring(0);
|
||||
}
|
||||
}, [selectedPlayer]);
|
||||
return (
|
||||
<frame BackgroundTransparency={1}>
|
||||
<uistroke Color={new Color3(1, 1, 1)} Thickness={3} Transparency={0.2} />
|
||||
<textbutton
|
||||
Text={player.DisplayName}
|
||||
TextScaled={true}
|
||||
BackgroundTransparency={0.8}
|
||||
BackgroundColor3={new Color3(0.26, 0.65, 0.91)}
|
||||
TextColor3={new Color3(1, 1, 1)}
|
||||
TextTransparency={0.2}
|
||||
BorderColor3={new Color3(1, 1, 1)}
|
||||
Size={UDim2.fromScale(1, 1)}
|
||||
Event={{
|
||||
Activated: () => {
|
||||
setSelectedPlayer(player === selectedPlayer ? undefined : player);
|
||||
},
|
||||
}}
|
||||
></textbutton>
|
||||
<textlabel
|
||||
Text={">"}
|
||||
TextColor3={new Color3(1, 1, 1)}
|
||||
TextScaled={true}
|
||||
BackgroundTransparency={1}
|
||||
Size={new UDim2(0.5, 0, 0.5, 0)}
|
||||
Position={UDim2.fromScale(0, 0.25)}
|
||||
SizeConstraint={Enum.SizeConstraint.RelativeYY}
|
||||
Rotation={enable.map((t) => t)}
|
||||
></textlabel>
|
||||
</frame>
|
||||
);
|
||||
}
|
||||
|
||||
export default function PlayersBoard() {
|
||||
const [players, setPlayers] = useState<Player[]>(Players.GetPlayers());
|
||||
const [selectedPlayer, setSelectedPlayer] = useState<Player>();
|
||||
useEffect(() => {
|
||||
const playerAdded = Players.PlayerAdded.Connect(() => {
|
||||
setPlayers(Players.GetPlayers());
|
||||
});
|
||||
const playerRemoving = Players.PlayerRemoving.Connect(() => {
|
||||
setPlayers(Players.GetPlayers());
|
||||
});
|
||||
return () => {
|
||||
playerAdded.Disconnect();
|
||||
playerRemoving.Disconnect();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<frame
|
||||
Size={UDim2.fromScale(0.2, 0.6)}
|
||||
Position={UDim2.fromScale(0.8, 0.1)}
|
||||
BackgroundColor3={new Color3(0, 0.72, 1)}
|
||||
BackgroundTransparency={0.7}
|
||||
>
|
||||
<frame
|
||||
BorderColor3={new Color3(1, 1, 1)}
|
||||
BorderSizePixel={5}
|
||||
BackgroundTransparency={1}
|
||||
Position={new UDim2(0, 10, 0, 10)}
|
||||
Size={new UDim2(1, -20, 1, -20)}
|
||||
>
|
||||
<scrollingframe
|
||||
CanvasSize={UDim2.fromScale(1, 0)}
|
||||
Size={new UDim2(1, 0, 1, 0)}
|
||||
AutomaticCanvasSize={Enum.AutomaticSize.Y}
|
||||
BackgroundTransparency={1}
|
||||
ScrollingDirection={Enum.ScrollingDirection.Y}
|
||||
>
|
||||
<uigridlayout CellSize={new UDim2(1, 0, 0, 50)} CellPadding={new UDim2()} />
|
||||
{players.map((p) => (
|
||||
<PlayerEntry
|
||||
player={p}
|
||||
selectedPlayer={selectedPlayer}
|
||||
setSelectedPlayer={setSelectedPlayer}
|
||||
/>
|
||||
))}
|
||||
</scrollingframe>
|
||||
<uistroke Color={new Color3(1, 1, 1)} Thickness={5} Transparency={0.2} />
|
||||
</frame>
|
||||
</frame>
|
||||
{selectedPlayer ? <Profile player={selectedPlayer} /> : undefined}
|
||||
</>
|
||||
);
|
||||
}
|
||||
17
src/shared/gui/players_board/profile/index.story.tsx
Normal file
17
src/shared/gui/players_board/profile/index.story.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import { StrictMode } from "@rbxts/react";
|
||||
import Profile from ".";
|
||||
import React from "@rbxts/react";
|
||||
import { createRoot } from "@rbxts/react-roblox";
|
||||
import { Players } from "@rbxts/services";
|
||||
|
||||
export = function (target: Instance) {
|
||||
const root = createRoot(target);
|
||||
root.render(
|
||||
<StrictMode>
|
||||
<Profile player={Players.GetPlayers()[0]} />
|
||||
</StrictMode>,
|
||||
);
|
||||
return function () {
|
||||
root.unmount();
|
||||
};
|
||||
};
|
||||
97
src/shared/gui/players_board/profile/index.tsx
Normal file
97
src/shared/gui/players_board/profile/index.tsx
Normal file
@@ -0,0 +1,97 @@
|
||||
import React, { useEffect, useRef, useState } from "@rbxts/react";
|
||||
import { LocalizationService, Players } from "@rbxts/services";
|
||||
|
||||
function TimePlayed({ targetTime }: { targetTime: number }) {
|
||||
const [time, setTime] = useState();
|
||||
const [id, setId] = useState<DateTime>();
|
||||
useEffect(() => {
|
||||
let killed = false;
|
||||
setId(DateTime.fromUnixTimestamp(targetTime));
|
||||
task.spawn(() => {
|
||||
while (true) {
|
||||
if (killed) return;
|
||||
}
|
||||
});
|
||||
return () => {
|
||||
killed = true;
|
||||
};
|
||||
}, [targetTime]);
|
||||
}
|
||||
|
||||
export default function Profile({ player }: { player: Player }) {
|
||||
const [userIcon, setUserIcon] = useState<string>();
|
||||
const ref = useRef<ImageLabel>();
|
||||
useEffect(() => {
|
||||
const [image] = Players.GetUserThumbnailAsync(
|
||||
player.UserId,
|
||||
Enum.ThumbnailType.HeadShot,
|
||||
Enum.ThumbnailSize.Size180x180,
|
||||
);
|
||||
setUserIcon(image);
|
||||
}, [player]);
|
||||
const reeloffset = ref.current?.AbsoluteSize.X ?? 0;
|
||||
return (
|
||||
<frame
|
||||
Size={new UDim2(0.5, 0, 0.5, 0)}
|
||||
Position={new UDim2(0.3, -10, 0.1, 0)}
|
||||
BackgroundColor3={new Color3(0, 0.72, 1)}
|
||||
BackgroundTransparency={0.7}
|
||||
>
|
||||
<frame
|
||||
BorderColor3={new Color3(1, 1, 1)}
|
||||
BorderSizePixel={5}
|
||||
BackgroundTransparency={1}
|
||||
Position={new UDim2(0, 10, 0, 10)}
|
||||
Size={new UDim2(1, -20, 1, -20)}
|
||||
>
|
||||
<frame Size={new UDim2(1, 0, 0.4, 0)} BackgroundTransparency={1}>
|
||||
<imagelabel
|
||||
Image={userIcon}
|
||||
Size={new UDim2(1, -20, 1, -20)}
|
||||
Position={UDim2.fromOffset(10, 10)}
|
||||
SizeConstraint={Enum.SizeConstraint.RelativeYY}
|
||||
BackgroundTransparency={1}
|
||||
ref={ref}
|
||||
>
|
||||
<uicorner CornerRadius={new UDim(1, 1)} />
|
||||
<uistroke Thickness={5} />
|
||||
</imagelabel>
|
||||
<textlabel
|
||||
Text={player.DisplayName}
|
||||
Size={new UDim2(1, -reeloffset, 0.3, 0)}
|
||||
BackgroundTransparency={1}
|
||||
TextScaled={true}
|
||||
Position={new UDim2(0, reeloffset, 0, 0)}
|
||||
TextColor3={new Color3(0, 0, 0)}
|
||||
/>
|
||||
<textlabel
|
||||
Text={"@" + player.Name}
|
||||
Size={new UDim2(1, -reeloffset, 0.2, 0)}
|
||||
BackgroundTransparency={1}
|
||||
TextScaled={true}
|
||||
Position={new UDim2(0, reeloffset, 0.25, 0)}
|
||||
TextColor3={new Color3(0.13, 0.13, 0.13)}
|
||||
/>
|
||||
<textlabel
|
||||
Text={DateTime.fromUnixTimestamp().FormatLocalTime("LTS", LocalizationService.RobloxLocaleId)}
|
||||
Size={new UDim2(1, -reeloffset, 0.3, 0)}
|
||||
BackgroundTransparency={1}
|
||||
TextScaled={true}
|
||||
Position={new UDim2(0, reeloffset, 0.45, 0)}
|
||||
TextColor3={new Color3(0, 0, 0)}
|
||||
/>
|
||||
<textlabel
|
||||
Text={`Lev : ${0}`}
|
||||
Size={new UDim2(1, -reeloffset, 0.3, 0)}
|
||||
BackgroundTransparency={1}
|
||||
TextScaled={true}
|
||||
Position={new UDim2(0, reeloffset, 0.7, 0)}
|
||||
TextColor3={new Color3(0, 0, 0)}
|
||||
/>
|
||||
<uistroke Color={new Color3(1, 1, 1)} Thickness={5} Transparency={0.2} />
|
||||
</frame>
|
||||
<uistroke Color={new Color3(1, 1, 1)} Thickness={5} Transparency={0.2} />
|
||||
</frame>
|
||||
</frame>
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"downlevelIteration": true,
|
||||
"jsx": "react",
|
||||
"jsxFactory": "Fusion.jsx",
|
||||
"jsxFactory": "React.createElement",
|
||||
"jsxFragmentFactory": "React.Fragment",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "Node",
|
||||
|
||||
Reference in New Issue
Block a user