Compare commits

..

No commits in common. "main" and "release/v0.3.x" have entirely different histories.

39 changed files with 96 additions and 1223 deletions

View file

@ -14,8 +14,8 @@
"TraitBiases": {
"Outgoing": 0.9,
"Playful": 0.8,
"Active": 0.5,
"Nice": 0.7,
"Active": 0.7,
"Nice": 0.5,
"Neat": 0.3
}
},

View file

@ -1,12 +0,0 @@
<Router AppAssembly="@typeof(App).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
<NotFound>
<PageTitle>Not found</PageTitle>
<LayoutView Layout="@typeof(MainLayout)">
<p role="alert">Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>

View file

@ -1,16 +0,0 @@
@inherits LayoutComponentBase
<div class="page">
<div class="sidebar">
<NavMenu />
</div>
<main>
<div class="top-row px-4">
<a href="https://learn.microsoft.com/aspnet/core/" target="_blank">About</a>
</div>
<article class="content px-4">
@Body
</article>
</main>
</div>

View file

@ -1,77 +0,0 @@
.page {
position: relative;
display: flex;
flex-direction: column;
}
main {
flex: 1;
}
.sidebar {
background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
}
.top-row {
background-color: #f7f7f7;
border-bottom: 1px solid #d6d5d5;
justify-content: flex-end;
height: 3.5rem;
display: flex;
align-items: center;
}
.top-row ::deep a, .top-row ::deep .btn-link {
white-space: nowrap;
margin-left: 1.5rem;
text-decoration: none;
}
.top-row ::deep a:hover, .top-row ::deep .btn-link:hover {
text-decoration: underline;
}
.top-row ::deep a:first-child {
overflow: hidden;
text-overflow: ellipsis;
}
@media (max-width: 640.98px) {
.top-row {
justify-content: space-between;
}
.top-row ::deep a, .top-row ::deep .btn-link {
margin-left: 0;
}
}
@media (min-width: 641px) {
.page {
flex-direction: row;
}
.sidebar {
width: 250px;
height: 100vh;
position: sticky;
top: 0;
}
.top-row {
position: sticky;
top: 0;
z-index: 1;
}
.top-row.auth ::deep a:first-child {
flex: 1;
text-align: right;
width: 0;
}
.top-row, article {
padding-left: 2rem !important;
padding-right: 1.5rem !important;
}
}

View file

@ -1,39 +0,0 @@
<div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid">
<a class="navbar-brand" href="">PersonaForge.Blazor</a>
<button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</div>
<div class="@NavMenuCssClass nav-scrollable" @onclick="ToggleNavMenu">
<nav class="flex-column">
<div class="nav-item px-3">
<NavLink class="nav-link" href="" Match="NavLinkMatch.All">
<span class="bi bi-house-door-fill-nav-menu" aria-hidden="true"></span> Home
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="bi bi-plus-square-fill-nav-menu" aria-hidden="true"></span> Counter
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link" href="weather">
<span class="bi bi-list-nested-nav-menu" aria-hidden="true"></span> Weather
</NavLink>
</div>
</nav>
</div>
@code {
private bool collapseNavMenu = true;
private string? NavMenuCssClass => collapseNavMenu ? "collapse" : null;
private void ToggleNavMenu()
{
collapseNavMenu = !collapseNavMenu;
}
}

View file

@ -1,83 +0,0 @@
.navbar-toggler {
background-color: rgba(255, 255, 255, 0.1);
}
.top-row {
height: 3.5rem;
background-color: rgba(0,0,0,0.4);
}
.navbar-brand {
font-size: 1.1rem;
}
.bi {
display: inline-block;
position: relative;
width: 1.25rem;
height: 1.25rem;
margin-right: 0.75rem;
top: -1px;
background-size: cover;
}
.bi-house-door-fill-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-house-door-fill' viewBox='0 0 16 16'%3E%3Cpath d='M6.5 14.5v-3.505c0-.245.25-.495.5-.495h2c.25 0 .5.25.5.5v3.5a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5v-7a.5.5 0 0 0-.146-.354L13 5.793V2.5a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1.293L8.354 1.146a.5.5 0 0 0-.708 0l-6 6A.5.5 0 0 0 1.5 7.5v7a.5.5 0 0 0 .5.5h4a.5.5 0 0 0 .5-.5Z'/%3E%3C/svg%3E");
}
.bi-plus-square-fill-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-plus-square-fill' viewBox='0 0 16 16'%3E%3Cpath d='M2 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2H2zm6.5 4.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3a.5.5 0 0 1 1 0z'/%3E%3C/svg%3E");
}
.bi-list-nested-nav-menu {
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-list-nested' viewBox='0 0 16 16'%3E%3Cpath fill-rule='evenodd' d='M4.5 11.5A.5.5 0 0 1 5 11h10a.5.5 0 0 1 0 1H5a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 3 7h10a.5.5 0 0 1 0 1H3a.5.5 0 0 1-.5-.5zm-2-4A.5.5 0 0 1 1 3h10a.5.5 0 0 1 0 1H1a.5.5 0 0 1-.5-.5z'/%3E%3C/svg%3E");
}
.nav-item {
font-size: 0.9rem;
padding-bottom: 0.5rem;
}
.nav-item:first-of-type {
padding-top: 1rem;
}
.nav-item:last-of-type {
padding-bottom: 1rem;
}
.nav-item ::deep a {
color: #d7d7d7;
border-radius: 4px;
height: 3rem;
display: flex;
align-items: center;
line-height: 3rem;
}
.nav-item ::deep a.active {
background-color: rgba(255,255,255,0.37);
color: white;
}
.nav-item ::deep a:hover {
background-color: rgba(255,255,255,0.1);
color: white;
}
@media (min-width: 641px) {
.navbar-toggler {
display: none;
}
.collapse {
/* Never collapse the sidebar for wide screens */
display: block;
}
.nav-scrollable {
/* Allow sidebar to scroll for tall menus */
height: calc(100vh - 3.5rem);
overflow-y: auto;
}
}

View file

@ -1,18 +0,0 @@
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}

View file

@ -1,7 +0,0 @@
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.

View file

@ -1,57 +0,0 @@
@page "/craft"
@inject HttpClient Http
<PageTitle>Sims2Craft</PageTitle>
<h1>Craft</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/weather.json");
}
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}

View file

@ -1,57 +0,0 @@
@page "/weather"
@inject HttpClient Http
<PageTitle>Weather</PageTitle>
<h1>Weather</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("sample-data/weather.json");
}
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}

View file

@ -1,18 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="9.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="9.0.0" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PersonaForge\PersonaForge.csproj" />
</ItemGroup>
</Project>

View file

@ -1,11 +0,0 @@
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using PersonaForge.Blazor;
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");
builder.RootComponents.Add<HeadOutlet>("head::after");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
await builder.Build().RunAsync();

View file

@ -1,41 +0,0 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:55547",
"sslPort": 44325
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "http://localhost:5139",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"applicationUrl": "https://localhost:7023;http://localhost:5139",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

View file

@ -1,11 +0,0 @@
@using System.Net.Http
@using System.Net.Http.Json
@using Microsoft.AspNetCore.Components.Forms
@using Microsoft.AspNetCore.Components.Routing
@using Microsoft.AspNetCore.Components.Web
@using Microsoft.AspNetCore.Components.Web.Virtualization
@using Microsoft.AspNetCore.Components.WebAssembly.Http
@using Microsoft.JSInterop
@using PersonaForge.Blazor
@using PersonaForge.Blazor.Layout
@using PersonaForge

View file

@ -1,103 +0,0 @@
html, body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
h1:focus {
outline: none;
}
a, .btn-link {
color: #0071c1;
}
.btn-primary {
color: #fff;
background-color: #1b6ec2;
border-color: #1861ac;
}
.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}
.content {
padding-top: 1.1rem;
}
.valid.modified:not([type=checkbox]) {
outline: 1px solid #26b050;
}
.invalid {
outline: 1px solid red;
}
.validation-message {
color: red;
}
#blazor-error-ui {
background: lightyellow;
bottom: 0;
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
display: none;
left: 0;
padding: 0.6rem 1.25rem 0.7rem 1.25rem;
position: fixed;
width: 100%;
z-index: 1000;
}
#blazor-error-ui .dismiss {
cursor: pointer;
position: absolute;
right: 0.75rem;
top: 0.5rem;
}
.blazor-error-boundary {
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
padding: 1rem 1rem 1rem 3.7rem;
color: white;
}
.blazor-error-boundary::after {
content: "An error has occurred."
}
.loading-progress {
position: relative;
display: block;
width: 8rem;
height: 8rem;
margin: 20vh auto 1rem auto;
}
.loading-progress circle {
fill: none;
stroke: #e0e0e0;
stroke-width: 0.6rem;
transform-origin: 50% 50%;
transform: rotate(-90deg);
}
.loading-progress circle:last-child {
stroke: #1b6ec2;
stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
transition: stroke-dasharray 0.05s ease-in-out;
}
.loading-progress-text {
position: absolute;
text-align: center;
font-weight: bold;
inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}
.loading-progress-text:after {
content: var(--blazor-load-percentage-text, "Loading");
}
code {
color: #c02d76;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,122 +0,0 @@
[
{
"Name": "Aries",
"TraitBiases": {
"Outgoing": 8.0,
"Playful": 3.0,
"Active": 7.0,
"Nice": 3.0,
"Neat": 4.0
}
},
{
"Name": "Taurus",
"TraitBiases": {
"Outgoing": 4.0,
"Playful": 4.0,
"Active": 4.0,
"Nice": 7.0,
"Neat": 6.0
}
},
{
"Name": "Gemini",
"TraitBiases": {
"Outgoing": 7.0,
"Playful": 7.0,
"Active": 4.0,
"Nice": 3.0,
"Neat": 4.0
}
},
{
"Name": "Cancer",
"TraitBiases": {
"Outgoing": 4.0,
"Playful": 3.0,
"Active": 4.0,
"Nice": 8.0,
"Neat": 6.0
}
},
{
"Name": "Leo",
"TraitBiases": {
"Outgoing": 8.0,
"Playful": 7.0,
"Active": 4.0,
"Nice": 2.0,
"Neat": 4.0
}
},
{
"Name": "Virgo",
"TraitBiases": {
"Outgoing": 2.0,
"Playful": 2.0,
"Active": 4.0,
"Nice": 8.0,
"Neat": 9.0
}
},
{
"Name": "Libra",
"TraitBiases": {
"Outgoing": 8.0,
"Playful": 6.0,
"Active": 4.0,
"Nice": 5.0,
"Neat": 2.0
}
},
{
"Name": "Scorpio",
"TraitBiases": {
"Outgoing": 5.0,
"Playful": 2.0,
"Active": 8.0,
"Nice": 4.0,
"Neat": 6.0
}
},
{
"Name": "Sagittarius",
"TraitBiases": {
"Outgoing": 7.0,
"Playful": 7.0,
"Active": 7.0,
"Nice": 2.0,
"Neat": 2.0
}
},
{
"Name": "Capricorn",
"TraitBiases": {
"Outgoing": 3.0,
"Playful": 2.0,
"Active": 6.0,
"Nice": 7.0,
"Neat": 7.0
}
},
{
"Name": "Aquarius",
"TraitBiases": {
"Outgoing": 6.0,
"Playful": 7.0,
"Active": 4.0,
"Nice": 5.0,
"Neat": 3.0
}
},
{
"Name": "Pisces",
"TraitBiases": {
"Outgoing": 4.0,
"Playful": 8.0,
"Active": 4.0,
"Nice": 5.0,
"Neat": 4.0
}
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -1,32 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>PersonaForge.Blazor</title>
<base href="/" />
<link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" />
<link rel="stylesheet" href="css/app.css" />
<link rel="icon" type="image/png" href="favicon.png" />
<link href="PersonaForge.Blazor.styles.css" rel="stylesheet" />
</head>
<body>
<div id="app">
<svg class="loading-progress">
<circle r="40%" cx="50%" cy="50%" />
<circle r="40%" cx="50%" cy="50%" />
</svg>
<div class="loading-progress-text"></div>
</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>

View file

@ -1,27 +0,0 @@
[
{
"date": "2022-01-06",
"temperatureC": 1,
"summary": "Freezing"
},
{
"date": "2022-01-07",
"temperatureC": 14,
"summary": "Bracing"
},
{
"date": "2022-01-08",
"temperatureC": -13,
"summary": "Freezing"
},
{
"date": "2022-01-09",
"temperatureC": -16,
"summary": "Balmy"
},
{
"date": "2022-01-10",
"temperatureC": -2,
"summary": "Chilly"
}
]

View file

@ -1,5 +0,0 @@
{
"version": 1,
"isRoot": true,
"tools": {}
}

View file

@ -1,24 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<Version>0.5.103</Version>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<PackAsTool>true</PackAsTool>
<ToolCommandName>personaforge</ToolCommandName>
<PackageId>PersonaForge</PackageId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.CommandLine" Version="2.0.0-beta4.22272.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\PersonaForge\PersonaForge.csproj" />
</ItemGroup>
</Project>

View file

@ -1,68 +0,0 @@
// .NET 8 C# - Random Sims 2 Personality Allocator
// Clear, minimal, portable, with basic validation.
using PersonaForge;
var rootCommand = new RootCommand("PersonaForge: Sims 2 Personality Generator");
var nameOption = new Option<string>(
name: "--name",
description: "Enter a name for the Sim"
);
var archetypeOption = new Option<string>(
name: "--archetype",
description: "The archetype template to base traits on",
getDefaultValue: () => "Random"
);
var zodiacOption = new Option<bool>(
name: "--zodiac",
description: "Use zodiac signs instead of archetypes"
)
{ IsRequired = false };
var exportOption = new Option<bool>(
name: "--export",
description: "Export the generated profile to a file"
)
{ IsRequired = false };
rootCommand.AddOption(nameOption);
rootCommand.AddOption(archetypeOption);
rootCommand.AddOption(exportOption);
rootCommand.SetHandler(async (
string name,
string archetype,
bool zodiac,
bool export
) =>
{
var archetypeDefs = Archetypes.LoadFromJson("archetypes.json");
var archetypeDict = new Dictionary<string, Dictionary<string, double>>();
if (zodiac)
archetypeDefs = Archetypes.LoadFromJson("zodiacs.json");
var traits = PersonalityGen.GenerateRandom(archetypeDict.GetValueOrDefault(archetype, new()));
var profile = new PersonaProfile
{
Name = name,
Qualities = traits,
Archetype = archetype
};
Console.WriteLine($"--- Generated Profile ---{Environment.NewLine}{PersonaProfile.ToJson(profile)}");
if (export)
{
var safeName = name.Replace(" ", "_").Replace("\"", "");
await File.WriteAllTextAsync($"{safeName}.json", PersonaProfile.ToJson(profile));
}
}, nameOption, archetypeOption, zodiacOption, exportOption);
return await rootCommand.InvokeAsync(args);

View file

@ -1,72 +0,0 @@
[
{
"Name": "Social Butterfly",
"TraitBiases": {
"Outgoing": 0.9,
"Playful": 0.8,
"Active": 0.6,
"Nice": 0.7,
"Neat": 0.5
}
},
{
"Name": "Party Animal",
"TraitBiases": {
"Outgoing": 0.9,
"Playful": 0.8,
"Active": 0.5,
"Nice": 0.7,
"Neat": 0.3
}
},
{
"Name": "Laidback",
"TraitBiases": {
"Outgoing": 0.4,
"Playful": 0.3,
"Active": 0.4,
"Nice": 0.8,
"Neat": 0.4
}
},
{
"Name": "Grumpy",
"TraitBiases": {
"Nice": 0.2,
"Playful": 0.4,
"Outgoing": 0.6,
"Neat": 0.7,
"Active": 0.5
}
},
{
"Name": "Artistic",
"TraitBiases": {
"Outgoing": 0.3,
"Playful": 0.7,
"Active": 0.5,
"Nice": 0.9,
"Neat": 0.6
}
},
{
"Name": "Ambitious",
"TraitBiases": {
"Outgoing": 0.6,
"Playful": 0.4,
"Active": 0.8,
"Nice": 0.5,
"Neat": 0.7
}
},
{
"Name": "Adventurous",
"TraitBiases": {
"Outgoing": 0.8,
"Playful": 0.8,
"Active": 0.9,
"Nice": 0.6,
"Neat": 0.4
}
}
]

View file

@ -1,11 +0,0 @@
{
"Name": "Max Casey",
"Archetype": "Party Animal",
"Qualities": {
"Outgoing": 7,
"Nice": 6,
"Playful": 6,
"Neat": 3,
"Active": 3
}
}

View file

@ -1,11 +0,0 @@
{
"Name": "Zack Casey",
"Archetype": "Laidback",
"Qualities": {
"Outgoing": 5,
"Nice": 8,
"Playful": 4,
"Neat": 4,
"Active": 4
}
}

View file

@ -1,122 +0,0 @@
[
{
"Name": "Aries",
"TraitBiases": {
"Outgoing": 8.0,
"Playful": 3.0,
"Active": 7.0,
"Nice": 3.0,
"Neat": 4.0
}
},
{
"Name": "Taurus",
"TraitBiases": {
"Outgoing": 4.0,
"Playful": 4.0,
"Active": 4.0,
"Nice": 7.0,
"Neat": 6.0
}
},
{
"Name": "Gemini",
"TraitBiases": {
"Outgoing": 7.0,
"Playful": 7.0,
"Active": 4.0,
"Nice": 3.0,
"Neat": 4.0
}
},
{
"Name": "Cancer",
"TraitBiases": {
"Outgoing": 4.0,
"Playful": 3.0,
"Active": 4.0,
"Nice": 8.0,
"Neat": 6.0
}
},
{
"Name": "Leo",
"TraitBiases": {
"Outgoing": 8.0,
"Playful": 7.0,
"Active": 4.0,
"Nice": 2.0,
"Neat": 4.0
}
},
{
"Name": "Virgo",
"TraitBiases": {
"Outgoing": 2.0,
"Playful": 2.0,
"Active": 4.0,
"Nice": 8.0,
"Neat": 9.0
}
},
{
"Name": "Libra",
"TraitBiases": {
"Outgoing": 8.0,
"Playful": 6.0,
"Active": 4.0,
"Nice": 5.0,
"Neat": 2.0
}
},
{
"Name": "Scorpio",
"TraitBiases": {
"Outgoing": 5.0,
"Playful": 2.0,
"Active": 8.0,
"Nice": 4.0,
"Neat": 6.0
}
},
{
"Name": "Sagittarius",
"TraitBiases": {
"Outgoing": 7.0,
"Playful": 7.0,
"Active": 7.0,
"Nice": 2.0,
"Neat": 2.0
}
},
{
"Name": "Capricorn",
"TraitBiases": {
"Outgoing": 3.0,
"Playful": 2.0,
"Active": 6.0,
"Nice": 7.0,
"Neat": 7.0
}
},
{
"Name": "Aquarius",
"TraitBiases": {
"Outgoing": 6.0,
"Playful": 7.0,
"Active": 4.0,
"Nice": 5.0,
"Neat": 3.0
}
},
{
"Name": "Pisces",
"TraitBiases": {
"Outgoing": 4.0,
"Playful": 8.0,
"Active": 4.0,
"Nice": 5.0,
"Neat": 4.0
}
}
]

View file

@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Version>0.5.103</Version>
<VersionSuffix>lts</VersionSuffix>
<OutputType>Exe</OutputType>
<Version>0.3.101</Version>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

View file

@ -1,34 +0,0 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PersonaForge.Console", "PersonaForge.Console\PersonaForge.Console.csproj", "{129AB949-1C7E-4E52-82E0-9339F43918AA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PersonaForge", "PersonaForge\PersonaForge.csproj", "{316741E2-8BE3-4FBF-A10D-F8FF2AD6979E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PersonaForge.Blazor", "PersonaForge.Blazor\PersonaForge.Blazor.csproj", "{381CCDD1-BB1A-45F0-8501-77769AB4578F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{129AB949-1C7E-4E52-82E0-9339F43918AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{129AB949-1C7E-4E52-82E0-9339F43918AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{129AB949-1C7E-4E52-82E0-9339F43918AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{129AB949-1C7E-4E52-82E0-9339F43918AA}.Release|Any CPU.Build.0 = Release|Any CPU
{316741E2-8BE3-4FBF-A10D-F8FF2AD6979E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{316741E2-8BE3-4FBF-A10D-F8FF2AD6979E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{316741E2-8BE3-4FBF-A10D-F8FF2AD6979E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{316741E2-8BE3-4FBF-A10D-F8FF2AD6979E}.Release|Any CPU.Build.0 = Release|Any CPU
{381CCDD1-BB1A-45F0-8501-77769AB4578F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{381CCDD1-BB1A-45F0-8501-77769AB4578F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{381CCDD1-BB1A-45F0-8501-77769AB4578F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{381CCDD1-BB1A-45F0-8501-77769AB4578F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View file

@ -1,91 +0,0 @@
namespace PersonaForge;
public class Archetypes
{
public string Name { get; set; }
public Dictionary<string, double> TraitBiases { get; set; } = new();
public static List<Archetypes> LoadFromJson(string json)
{
var opt = new JsonSerializerOptions()
{
PropertyNameCaseInsensitive = false
};
var definitions = JsonSerializer.Deserialize<List<Archetypes>>(json, opt);
if (definitions is null)
throw new InvalidOperationException("Failed to deserialize Archetype JSON.");
return definitions;
}
public static List<Archetypes> DefaultArchetypes() => new()
{
new Archetypes
{
Name = "Grumpy",
TraitBiases = new Dictionary<string, double>
{
{ "Nice", 0.2 },
{ "Playful", 0.4 },
{ "Outgoing", 0.6 },
{ "Neat", 0.7 },
{ "Active", 0.5 }
}
},
new Archetypes
{
Name = "Party Animal",
TraitBiases = new Dictionary<string, double>
{
{ "Outgoing", 0.9 },
{ "Playful", 0.8 },
{ "Active", 0.7 },
{ "Nice", 0.5 },
{ "Neat", 0.3 }
}
},
new Archetypes
{
Name = "Lazy",
TraitBiases = new Dictionary<string, double>
{
{ "Nice", 0.8 },
{ "Playful", 0.6 },
{ "Outgoing", 0.4 },
{ "Neat", 0.2 },
{ "Active", 0.1 }
}
},
new Archetypes
{
Name = "Shy",
TraitBiases = new Dictionary<string, double>
{
{ "Nice", 0.9 },
{ "Playful", 0.7 },
{ "Outgoing", 0.3 },
{ "Neat", 0.5 },
{ "Active", 0.2 }
}
},
new Archetypes
{
Name = "Energetic",
TraitBiases = new Dictionary<string, double>
{
{ "Nice", 0.7 },
{ "Playful", 0.6 },
{ "Outgoing", 0.5 },
{ "Neat", 0.4 },
{ "Active", 0.3 }
}
},
new Archetypes
{
Name = "Random",
TraitBiases = new()
}
};
}

36
PersonalityArchetype.cs Normal file
View file

@ -0,0 +1,36 @@
namespace PersonaForge;
public class PersonalityArchetype
{
public string Name { get; set; }
public Dictionary<string, double> TraitBiases { get; set; } = new();
// TODO: Load default archetypes from a file or database
public static List<PersonalityArchetype> DefaultArchetypes() => new()
{
new PersonalityArchetype
{
Name = "Grumpy",
TraitBiases = new Dictionary<string, double>
{
{ "Nice", 0.2 },
{ "Playful", 0.4 },
{ "Outgoing", 0.6 },
{ "Neat", 0.7 },
{ "Active", 0.5 }
}
},
new PersonalityArchetype
{
Name = "Party Animal",
TraitBiases = new Dictionary<string, double>
{
{ "Outgoing", 0.9 },
{ "Playful", 0.8 },
{ "Active", 0.7 },
{ "Nice", 0.5 },
{ "Neat", 0.3 }
}
}
};
}

View file

@ -6,24 +6,12 @@ public static class PersonalityGen
const int TotalBudget = 25;
static readonly Random rng = new();
public static PersonalityTraits GenerateRandom(Dictionary<string, double>? bias = null)
public static PersonalityTraits GenerateRandom()
{
var profile = PersonalityTraits.Create();
var traits = new List<string> { "Outgoing", "Nice", "Playful", "Neat", "Active" };
var remaining = TotalBudget;
if (bias != null)
{
foreach (var kvp in bias)
{
var trait = kvp.Key;
var points = Convert.ToInt32(kvp.Value);
var safePoints = Math.Min(points, MaxPoints);
SetTraitPoints(profile, trait, safePoints);
remaining -= points;
}
}
while (remaining > 0)
{
var trait = traits[rng.Next(traits.Count)];

View file

@ -2,11 +2,11 @@ namespace PersonaForge;
public class PersonalityTraits
{
public int Neat { get; set; }
public int Outgoing { get; set; }
public int Active { get; set; }
public int Playful { get; set; }
public int Nice { get; set; }
public int Playful { get; set; }
public int Neat { get; set; }
public int Active { get; set; }
public static PersonalityTraits Create() => new();

32
Program.cs Normal file
View file

@ -0,0 +1,32 @@
// .NET 8 C# - Random Sims 2 Personality Allocator
// Clear, minimal, portable, with basic validation.
using PersonaForge;
Console.WriteLine("=== Welcome to The Sims 2 Personality Generator ===");
Console.Write("Enter Sim's name: ");
string name = Console.ReadLine() ?? "Unndanmed Sim";
var qualities = PersonalityGen.GenerateRandom();
var profile = new PersonaProfile
{
Name = name,
Qualities = qualities,
Archetype = "Random"
};
Console.WriteLine($"{name}'s Profile{Environment.NewLine}{PersonaProfile.ToJson(profile)}");
Console.Write("Save profile? (y/n): ");
var saveInput = Console.ReadLine()?.Trim().ToLowerInvariant();
if (saveInput == "y")
{
var safeName = name.Replace(" ", "_").Replace("\"", "");
File.WriteAllText($"{safeName}.json", PersonaProfile.ToJson(profile));
Console.WriteLine($"Profile saved as {name}.json");
}
Console.WriteLine($"Done. Forge on! 🔥{Environment.NewLine}Press any key to exit...");
Console.ReadKey();

View file

@ -10,24 +10,18 @@ It helps if you want to:
## 💡 Why This Exists
Because The Sims 2 doesnt have traits in the same way later installments do, you had to figure out what kind of Sim you wanted based on personality stats with a strict 25 point budget. Even if you knew what you wanted, you didnt always know how to spend the rest. PersonaForge aimed to solve this problem.
With Sims 3 and later, creating personalities is as simple as selecting a trait. Sims 2 doesnt have traits in the same way later installments do. You had to figure out what kind of Sim you wanted based on certain qualities and points you had to spend. Even if you knew what you wanted, you didnt know how to spend the rest. This was created to solve that.
## 🛣️ Project Roadmap
| Phase | Goal | Status |
| -------- | ------------------------------------------- | ------ |
| v0.1 | Core random point generator | ✅ |
| ----- | ------------------------------------------- | ------ |
| v0.1 | Core random point generator (working) | ✅ |
| v0.2 | PersonalityProfile class | ✅ |
| v0.3 | Interactive JSON export | ✅ |
| v0.4 | Archetypes with weighted biases | ✅ |
| v0.5 LTS | Command line tool | ✅ |
| v0.4 | Archetypes with weighted biases | 🔜 |
| v0.5 | Profile import/load from JSON | 🔜 |
| v1.0 | Stable "Release" version with documentation | 🔜 |
| v1.x | Profile import/load from JSON | 🔜 |
## 📌 Stretch Goals
- [x] Import The Sims' Zodiac signs
- [x] Cross-platform dotnet tool. (e.g. `dotnet tool install`)
## 🧩 Tech Stack
@ -44,22 +38,17 @@ Because The Sims 2 doesnt have traits in the same way later installments do,
- Futureproof for new archetypes, quirks, or expansions
- Portable and clean
## 📦 Example
```shell
personaforge --name "Max Casey" --archetype "Party Animal" (--export)
```
## 📦 Example JSON Output
```json
{
"Name": "Max Casey",
"Archetype": "Party Animal",
"Qualities": {
"Outgoing": 7,
"Nice": 6,
"Outgoing": 6,
"Nice": 4,
"Playful": 6,
"Neat": 3,
"Active": 3
"Neat": 5,
"Active": 4
}
}
```
@ -67,8 +56,13 @@ personaforge --name "Max Casey" --archetype "Party Animal" (--export)
## 🚫 Not Planned
- No Sim 3-style traits.
- No UI. (Maybe a fork)
- No CAS-style tool.
## 📌 Stretch Goals
- Cross-platform dotnet tool. (e.g. `dotnet tool install`)
## 🗓️ Update Cycle
| Type | Frequency | Notes |