fix(setup): improve layout centering and add terminal-style complete page

- Fix CheckingPage centering by using justify-start with pt-[30%] padding
- Replace h-full with flex-1 for proper flex container sizing
- Redesign CompletePage with compact terminal-style command display
- Add framework logos (JavaScript, TypeScript, React, Vue, Svelte, etc.)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Lea Anthony 2025-12-14 22:10:41 +11:00
commit 272a316db6
25 changed files with 365 additions and 203 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -7,8 +7,8 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
<script type="module" crossorigin src="/assets/index-CdeMD05J.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-owjaKB1W.css">
<script type="module" crossorigin src="/assets/index-aGFUz6Rg.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-sn0oTu7c.css">
</head>
<body>
<div id="root"></div>

View file

@ -0,0 +1 @@
<svg fill="#F7DF1E" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>JavaScript</title><path d="M0 0h24v24H0V0zm22.034 18.276c-.175-1.095-.888-2.015-3.003-2.873-.736-.345-1.554-.585-1.797-1.14-.091-.33-.105-.51-.046-.705.15-.646.915-.84 1.515-.66.39.12.75.42.976.9 1.034-.676 1.034-.676 1.755-1.125-.27-.42-.404-.601-.586-.78-.63-.705-1.469-1.065-2.834-1.034l-.705.089c-.676.165-1.32.525-1.71 1.005-1.14 1.291-.811 3.541.569 4.471 1.365 1.02 3.361 1.244 3.616 2.205.24 1.17-.87 1.545-1.966 1.41-.811-.18-1.26-.586-1.755-1.336l-1.83 1.051c.21.48.45.689.81 1.109 1.74 1.756 6.09 1.666 6.871-1.004.029-.09.24-.705.074-1.65l.046.067zm-8.983-7.245h-2.248c0 1.938-.009 3.864-.009 5.805 0 1.232.063 2.363-.138 2.711-.33.689-1.18.601-1.566.48-.396-.196-.597-.466-.83-.855-.063-.105-.11-.196-.127-.196l-1.825 1.125c.305.63.75 1.172 1.324 1.517.855.51 2.004.675 3.207.405.783-.226 1.458-.691 1.811-1.411.51-.93.402-2.07.397-3.346.012-2.054 0-4.109 0-6.179l.004-.056z"/></svg>

After

Width:  |  Height:  |  Size: 989 B

View file

@ -0,0 +1 @@
<svg fill="#324FFF" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Lit</title><path d="M2.4 9.6l4.8 4.8V24l-4.8-4.8V9.6zm4.8-4.8v9.6L12 9.6V0L7.2 4.8zM12 9.6v9.6l4.8-4.8V4.8L12 9.6zm4.8 4.8V24l4.8-4.8V9.6l-4.8 4.8z"/></svg>

After

Width:  |  Height:  |  Size: 249 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.1 KiB

View file

@ -0,0 +1 @@
<svg fill="#AC7EF4" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Qwik</title><path d="M7.5469 0a2.957 2.957 0 0 0-2.5606 1.4785L.5332 9.1915a2.957 2.957 0 0 0 0 2.957l4.4531 7.7128A2.955 2.955 0 0 0 7.547 21.338H12l8.5938 2.6484c.2409.0742.4512-.1782.3359-.4023l-1.916-3.7227 4.4531-7.7129a2.957 2.957 0 0 0 0-2.957l-4.4531-7.7129A2.957 2.957 0 0 0 16.453 0zm0 .7656L17.7324 10.67l-1.8965 1.8985.5782 7.5332L6.2676 10.67l2.371-2.373z"/></svg>

After

Width:  |  Height:  |  Size: 470 B

View file

@ -0,0 +1 @@
<svg fill="#61DAFB" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>React</title><path d="M14.23 12.004a2.236 2.236 0 0 1-2.235 2.236 2.236 2.236 0 0 1-2.236-2.236 2.236 2.236 0 0 1 2.235-2.236 2.236 2.236 0 0 1 2.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38-.318-.184-.688-.277-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44-.96-.236-2.006-.417-3.107-.534-.66-.905-1.345-1.727-2.035-2.447 1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442-1.107.117-2.154.298-3.113.538-.112-.49-.195-.964-.254-1.42-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87-.728.063-1.466.098-2.21.098-.74 0-1.477-.035-2.202-.093-.406-.582-.802-1.204-1.183-1.86-.372-.64-.71-1.29-1.018-1.946.303-.657.646-1.313 1.013-1.954.38-.66.773-1.286 1.18-1.868.728-.064 1.466-.098 2.21-.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933-.2-.39-.41-.783-.64-1.174-.225-.392-.465-.774-.705-1.146zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493-.28-.958-.646-1.956-1.1-2.98.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98-.45 1.017-.812 2.01-1.086 2.964-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39.24-.375.48-.762.705-1.158.225-.39.435-.788.636-1.18zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143-.695-.102-1.365-.23-2.006-.386.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295-.22-.005-.406-.05-.553-.132-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z"/></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1 @@
<svg fill="#2C4F7C" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Solid</title><path d="M11.558.788A9.082 9.082 0 0 0 9.776.99l-.453.15c-.906.303-1.656.755-2.1 1.348l-.301.452-2.035 3.528c.426-.387.974-.698 1.643-.894h.001l.613-.154h.001a8.82 8.82 0 0 1 1.777-.206c2.916-.053 6.033 1.148 8.423 2.36 2.317 1.175 3.888 2.32 3.987 2.39L24 5.518c-.082-.06-1.66-1.21-3.991-2.386-2.393-1.206-5.521-2.396-8.45-2.343zM8.924 5.366a8.634 8.634 0 0 0-1.745.203l-.606.151c-1.278.376-2.095 1.16-2.43 2.108-.334.948-.188 2.065.487 3.116.33.43.747.813 1.216 1.147L12.328 10h.001a6.943 6.943 0 0 1 6.013 1.013l2.844-.963c-.17-.124-1.663-1.2-3.91-2.34-2.379-1.206-5.479-2.396-8.352-2.344zm5.435 4.497a6.791 6.791 0 0 0-1.984.283L2.94 13.189 0 18.334l9.276-2.992a6.945 6.945 0 0 1 7.408 2.314v.001c.695.903.89 1.906.66 2.808l2.572-4.63c.595-1.041.45-2.225-.302-3.429a6.792 6.792 0 0 0-5.255-2.543zm-3.031 5.341a6.787 6.787 0 0 0-2.006.283L.008 18.492c.175.131 2.02 1.498 4.687 2.768 2.797 1.332 6.37 2.467 9.468 1.712l.454-.152h.002c1.278-.376 2.134-1.162 2.487-2.09.353-.93.207-2.004-.541-2.978a6.791 6.791 0 0 0-5.237-2.548z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1 @@
<svg fill="#FF3E00" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Svelte</title><path d="M10.354 21.125a4.44 4.44 0 0 1-4.765-1.767 4.109 4.109 0 0 1-.703-3.107 3.898 3.898 0 0 1 .134-.522l.105-.321.287.21a7.21 7.21 0 0 0 2.186 1.092l.208.063-.02.208a1.253 1.253 0 0 0 .226.83 1.337 1.337 0 0 0 1.435.533 1.231 1.231 0 0 0 .343-.15l5.59-3.562a1.164 1.164 0 0 0 .524-.778 1.242 1.242 0 0 0-.211-.937 1.338 1.338 0 0 0-1.435-.533 1.23 1.23 0 0 0-.343.15l-2.133 1.36a4.078 4.078 0 0 1-1.135.499 4.44 4.44 0 0 1-4.765-1.766 4.108 4.108 0 0 1-.702-3.108 3.855 3.855 0 0 1 1.742-2.582l5.589-3.563a4.072 4.072 0 0 1 1.135-.499 4.44 4.44 0 0 1 4.765 1.767 4.109 4.109 0 0 1 .703 3.107 3.943 3.943 0 0 1-.134.522l-.105.321-.286-.21a7.204 7.204 0 0 0-2.187-1.093l-.208-.063.02-.207a1.255 1.255 0 0 0-.226-.831 1.337 1.337 0 0 0-1.435-.532 1.231 1.231 0 0 0-.343.15L8.62 9.368a1.162 1.162 0 0 0-.524.778 1.24 1.24 0 0 0 .211.937 1.338 1.338 0 0 0 1.435.533 1.235 1.235 0 0 0 .344-.151l2.132-1.36a4.067 4.067 0 0 1 1.135-.498 4.44 4.44 0 0 1 4.765 1.766 4.108 4.108 0 0 1 .702 3.108 3.857 3.857 0 0 1-1.742 2.583l-5.589 3.562a4.072 4.072 0 0 1-1.135.499m10.358-17.95C18.484-.015 14.082-.96 10.9 1.068L5.31 4.63a6.412 6.412 0 0 0-2.896 4.295 6.753 6.753 0 0 0 .666 4.336 6.43 6.43 0 0 0-.96 2.396 6.833 6.833 0 0 0 1.168 5.167c2.229 3.19 6.63 4.135 9.812 2.108l5.59-3.562a6.41 6.41 0 0 0 2.896-4.295 6.756 6.756 0 0 0-.665-4.336 6.429 6.429 0 0 0 .958-2.396 6.831 6.831 0 0 0-1.167-5.168Z"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1 @@
<svg fill="#3178C6" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>TypeScript</title><path d="M1.125 0C.502 0 0 .502 0 1.125v21.75C0 23.498.502 24 1.125 24h21.75c.623 0 1.125-.502 1.125-1.125V1.125C24 .502 23.498 0 22.875 0zm17.363 9.75c.612 0 1.154.037 1.627.111a6.38 6.38 0 0 1 1.306.34v2.458a3.95 3.95 0 0 0-.643-.361 5.093 5.093 0 0 0-.717-.26 5.453 5.453 0 0 0-1.426-.2c-.3 0-.573.028-.819.086a2.1 2.1 0 0 0-.623.242c-.17.104-.3.229-.393.374a.888.888 0 0 0-.14.49c0 .196.053.373.156.529.104.156.252.304.443.444s.423.276.696.41c.273.135.582.274.926.416.47.197.892.407 1.266.628.374.222.695.473.963.753.268.279.472.598.614.957.142.359.214.776.214 1.253 0 .657-.125 1.21-.373 1.656a3.033 3.033 0 0 1-1.012 1.085 4.38 4.38 0 0 1-1.487.596c-.566.12-1.163.18-1.79.18a9.916 9.916 0 0 1-1.84-.164 5.544 5.544 0 0 1-1.512-.493v-2.63a5.033 5.033 0 0 0 3.237 1.2c.333 0 .624-.03.872-.09.249-.06.456-.144.623-.25.166-.108.29-.234.373-.38a1.023 1.023 0 0 0-.074-1.089 2.12 2.12 0 0 0-.537-.5 5.597 5.597 0 0 0-.807-.444 27.72 27.72 0 0 0-1.007-.436c-.918-.383-1.602-.852-2.053-1.405-.45-.553-.676-1.222-.676-2.005 0-.614.123-1.141.369-1.582.246-.441.58-.804 1.004-1.089a4.494 4.494 0 0 1 1.47-.629 7.536 7.536 0 0 1 1.77-.201zm-15.113.188h9.563v2.166H9.506v9.646H6.789v-9.646H3.375z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1 @@
<svg fill="#4FC08D" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Vue.js</title><path d="M24,1.61H14.06L12,5.16,9.94,1.61H0L12,22.39ZM12,14.08,5.16,2.23H9.59L12,6.41l2.41-4.18h4.43Z"/></svg>

After

Width:  |  Height:  |  Size: 217 B

View file

@ -0,0 +1 @@
<svg fill="#F7DF1E" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>JavaScript</title><path d="M0 0h24v24H0V0zm22.034 18.276c-.175-1.095-.888-2.015-3.003-2.873-.736-.345-1.554-.585-1.797-1.14-.091-.33-.105-.51-.046-.705.15-.646.915-.84 1.515-.66.39.12.75.42.976.9 1.034-.676 1.034-.676 1.755-1.125-.27-.42-.404-.601-.586-.78-.63-.705-1.469-1.065-2.834-1.034l-.705.089c-.676.165-1.32.525-1.71 1.005-1.14 1.291-.811 3.541.569 4.471 1.365 1.02 3.361 1.244 3.616 2.205.24 1.17-.87 1.545-1.966 1.41-.811-.18-1.26-.586-1.755-1.336l-1.83 1.051c.21.48.45.689.81 1.109 1.74 1.756 6.09 1.666 6.871-1.004.029-.09.24-.705.074-1.65l.046.067zm-8.983-7.245h-2.248c0 1.938-.009 3.864-.009 5.805 0 1.232.063 2.363-.138 2.711-.33.689-1.18.601-1.566.48-.396-.196-.597-.466-.83-.855-.063-.105-.11-.196-.127-.196l-1.825 1.125c.305.63.75 1.172 1.324 1.517.855.51 2.004.675 3.207.405.783-.226 1.458-.691 1.811-1.411.51-.93.402-2.07.397-3.346.012-2.054 0-4.109 0-6.179l.004-.056z"/></svg>

After

Width:  |  Height:  |  Size: 989 B

View file

@ -0,0 +1 @@
<svg fill="#324FFF" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Lit</title><path d="M2.4 9.6l4.8 4.8V24l-4.8-4.8V9.6zm4.8-4.8v9.6L12 9.6V0L7.2 4.8zM12 9.6v9.6l4.8-4.8V4.8L12 9.6zm4.8 4.8V24l4.8-4.8V9.6l-4.8 4.8z"/></svg>

After

Width:  |  Height:  |  Size: 249 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.1 KiB

View file

@ -0,0 +1 @@
<svg fill="#AC7EF4" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Qwik</title><path d="M7.5469 0a2.957 2.957 0 0 0-2.5606 1.4785L.5332 9.1915a2.957 2.957 0 0 0 0 2.957l4.4531 7.7128A2.955 2.955 0 0 0 7.547 21.338H12l8.5938 2.6484c.2409.0742.4512-.1782.3359-.4023l-1.916-3.7227 4.4531-7.7129a2.957 2.957 0 0 0 0-2.957l-4.4531-7.7129A2.957 2.957 0 0 0 16.453 0zm0 .7656L17.7324 10.67l-1.8965 1.8985.5782 7.5332L6.2676 10.67l2.371-2.373z"/></svg>

After

Width:  |  Height:  |  Size: 470 B

View file

@ -0,0 +1 @@
<svg fill="#61DAFB" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>React</title><path d="M14.23 12.004a2.236 2.236 0 0 1-2.235 2.236 2.236 2.236 0 0 1-2.236-2.236 2.236 2.236 0 0 1 2.235-2.236 2.236 2.236 0 0 1 2.236 2.236zm2.648-10.69c-1.346 0-3.107.96-4.888 2.622-1.78-1.653-3.542-2.602-4.887-2.602-.41 0-.783.093-1.106.278-1.375.793-1.683 3.264-.973 6.365C1.98 8.917 0 10.42 0 12.004c0 1.59 1.99 3.097 5.043 4.03-.704 3.113-.39 5.588.988 6.38.32.187.69.275 1.102.275 1.345 0 3.107-.96 4.888-2.624 1.78 1.654 3.542 2.603 4.887 2.603.41 0 .783-.09 1.106-.275 1.374-.792 1.683-3.263.973-6.365C22.02 15.096 24 13.59 24 12.004c0-1.59-1.99-3.097-5.043-4.032.704-3.11.39-5.587-.988-6.38-.318-.184-.688-.277-1.092-.278zm-.005 1.09v.006c.225 0 .406.044.558.127.666.382.955 1.835.73 3.704-.054.46-.142.945-.25 1.44-.96-.236-2.006-.417-3.107-.534-.66-.905-1.345-1.727-2.035-2.447 1.592-1.48 3.087-2.292 4.105-2.295zm-9.77.02c1.012 0 2.514.808 4.11 2.28-.686.72-1.37 1.537-2.02 2.442-1.107.117-2.154.298-3.113.538-.112-.49-.195-.964-.254-1.42-.23-1.868.054-3.32.714-3.707.19-.09.4-.127.563-.132zm4.882 3.05c.455.468.91.992 1.36 1.564-.44-.02-.89-.034-1.345-.034-.46 0-.915.01-1.36.034.44-.572.895-1.096 1.345-1.565zM12 8.1c.74 0 1.477.034 2.202.093.406.582.802 1.203 1.183 1.86.372.64.71 1.29 1.018 1.946-.308.655-.646 1.31-1.013 1.95-.38.66-.773 1.288-1.18 1.87-.728.063-1.466.098-2.21.098-.74 0-1.477-.035-2.202-.093-.406-.582-.802-1.204-1.183-1.86-.372-.64-.71-1.29-1.018-1.946.303-.657.646-1.313 1.013-1.954.38-.66.773-1.286 1.18-1.868.728-.064 1.466-.098 2.21-.098zm-3.635.254c-.24.377-.48.763-.704 1.16-.225.39-.435.782-.635 1.174-.265-.656-.49-1.31-.676-1.947.64-.15 1.315-.283 2.015-.386zm7.26 0c.695.103 1.365.23 2.006.387-.18.632-.405 1.282-.66 1.933-.2-.39-.41-.783-.64-1.174-.225-.392-.465-.774-.705-1.146zm3.063.675c.484.15.944.317 1.375.498 1.732.74 2.852 1.708 2.852 2.476-.005.768-1.125 1.74-2.857 2.475-.42.18-.88.342-1.355.493-.28-.958-.646-1.956-1.1-2.98.45-1.017.81-2.01 1.085-2.964zm-13.395.004c.278.96.645 1.957 1.1 2.98-.45 1.017-.812 2.01-1.086 2.964-.484-.15-.944-.318-1.37-.5-1.732-.737-2.852-1.706-2.852-2.474 0-.768 1.12-1.742 2.852-2.476.42-.18.88-.342 1.356-.494zm11.678 4.28c.265.657.49 1.312.676 1.948-.64.157-1.316.29-2.016.39.24-.375.48-.762.705-1.158.225-.39.435-.788.636-1.18zm-9.945.02c.2.392.41.783.64 1.175.23.39.465.772.705 1.143-.695-.102-1.365-.23-2.006-.386.18-.63.406-1.282.66-1.933zM17.92 16.32c.112.493.2.968.254 1.423.23 1.868-.054 3.32-.714 3.708-.147.09-.338.128-.563.128-1.012 0-2.514-.807-4.11-2.28.686-.72 1.37-1.536 2.02-2.44 1.107-.118 2.154-.3 3.113-.54zm-11.83.01c.96.234 2.006.415 3.107.532.66.905 1.345 1.727 2.035 2.446-1.595 1.483-3.092 2.295-4.11 2.295-.22-.005-.406-.05-.553-.132-.666-.38-.955-1.834-.73-3.703.054-.46.142-.944.25-1.438zm4.56.64c.44.02.89.034 1.345.034.46 0 .915-.01 1.36-.034-.44.572-.895 1.095-1.345 1.565-.455-.47-.91-.993-1.36-1.565z"/></svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View file

@ -0,0 +1 @@
<svg fill="#2C4F7C" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Solid</title><path d="M11.558.788A9.082 9.082 0 0 0 9.776.99l-.453.15c-.906.303-1.656.755-2.1 1.348l-.301.452-2.035 3.528c.426-.387.974-.698 1.643-.894h.001l.613-.154h.001a8.82 8.82 0 0 1 1.777-.206c2.916-.053 6.033 1.148 8.423 2.36 2.317 1.175 3.888 2.32 3.987 2.39L24 5.518c-.082-.06-1.66-1.21-3.991-2.386-2.393-1.206-5.521-2.396-8.45-2.343zM8.924 5.366a8.634 8.634 0 0 0-1.745.203l-.606.151c-1.278.376-2.095 1.16-2.43 2.108-.334.948-.188 2.065.487 3.116.33.43.747.813 1.216 1.147L12.328 10h.001a6.943 6.943 0 0 1 6.013 1.013l2.844-.963c-.17-.124-1.663-1.2-3.91-2.34-2.379-1.206-5.479-2.396-8.352-2.344zm5.435 4.497a6.791 6.791 0 0 0-1.984.283L2.94 13.189 0 18.334l9.276-2.992a6.945 6.945 0 0 1 7.408 2.314v.001c.695.903.89 1.906.66 2.808l2.572-4.63c.595-1.041.45-2.225-.302-3.429a6.792 6.792 0 0 0-5.255-2.543zm-3.031 5.341a6.787 6.787 0 0 0-2.006.283L.008 18.492c.175.131 2.02 1.498 4.687 2.768 2.797 1.332 6.37 2.467 9.468 1.712l.454-.152h.002c1.278-.376 2.134-1.162 2.487-2.09.353-.93.207-2.004-.541-2.978a6.791 6.791 0 0 0-5.237-2.548z"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1 @@
<svg fill="#FF3E00" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Svelte</title><path d="M10.354 21.125a4.44 4.44 0 0 1-4.765-1.767 4.109 4.109 0 0 1-.703-3.107 3.898 3.898 0 0 1 .134-.522l.105-.321.287.21a7.21 7.21 0 0 0 2.186 1.092l.208.063-.02.208a1.253 1.253 0 0 0 .226.83 1.337 1.337 0 0 0 1.435.533 1.231 1.231 0 0 0 .343-.15l5.59-3.562a1.164 1.164 0 0 0 .524-.778 1.242 1.242 0 0 0-.211-.937 1.338 1.338 0 0 0-1.435-.533 1.23 1.23 0 0 0-.343.15l-2.133 1.36a4.078 4.078 0 0 1-1.135.499 4.44 4.44 0 0 1-4.765-1.766 4.108 4.108 0 0 1-.702-3.108 3.855 3.855 0 0 1 1.742-2.582l5.589-3.563a4.072 4.072 0 0 1 1.135-.499 4.44 4.44 0 0 1 4.765 1.767 4.109 4.109 0 0 1 .703 3.107 3.943 3.943 0 0 1-.134.522l-.105.321-.286-.21a7.204 7.204 0 0 0-2.187-1.093l-.208-.063.02-.207a1.255 1.255 0 0 0-.226-.831 1.337 1.337 0 0 0-1.435-.532 1.231 1.231 0 0 0-.343.15L8.62 9.368a1.162 1.162 0 0 0-.524.778 1.24 1.24 0 0 0 .211.937 1.338 1.338 0 0 0 1.435.533 1.235 1.235 0 0 0 .344-.151l2.132-1.36a4.067 4.067 0 0 1 1.135-.498 4.44 4.44 0 0 1 4.765 1.766 4.108 4.108 0 0 1 .702 3.108 3.857 3.857 0 0 1-1.742 2.583l-5.589 3.562a4.072 4.072 0 0 1-1.135.499m10.358-17.95C18.484-.015 14.082-.96 10.9 1.068L5.31 4.63a6.412 6.412 0 0 0-2.896 4.295 6.753 6.753 0 0 0 .666 4.336 6.43 6.43 0 0 0-.96 2.396 6.833 6.833 0 0 0 1.168 5.167c2.229 3.19 6.63 4.135 9.812 2.108l5.59-3.562a6.41 6.41 0 0 0 2.896-4.295 6.756 6.756 0 0 0-.665-4.336 6.429 6.429 0 0 0 .958-2.396 6.831 6.831 0 0 0-1.167-5.168Z"/></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1 @@
<svg fill="#3178C6" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>TypeScript</title><path d="M1.125 0C.502 0 0 .502 0 1.125v21.75C0 23.498.502 24 1.125 24h21.75c.623 0 1.125-.502 1.125-1.125V1.125C24 .502 23.498 0 22.875 0zm17.363 9.75c.612 0 1.154.037 1.627.111a6.38 6.38 0 0 1 1.306.34v2.458a3.95 3.95 0 0 0-.643-.361 5.093 5.093 0 0 0-.717-.26 5.453 5.453 0 0 0-1.426-.2c-.3 0-.573.028-.819.086a2.1 2.1 0 0 0-.623.242c-.17.104-.3.229-.393.374a.888.888 0 0 0-.14.49c0 .196.053.373.156.529.104.156.252.304.443.444s.423.276.696.41c.273.135.582.274.926.416.47.197.892.407 1.266.628.374.222.695.473.963.753.268.279.472.598.614.957.142.359.214.776.214 1.253 0 .657-.125 1.21-.373 1.656a3.033 3.033 0 0 1-1.012 1.085 4.38 4.38 0 0 1-1.487.596c-.566.12-1.163.18-1.79.18a9.916 9.916 0 0 1-1.84-.164 5.544 5.544 0 0 1-1.512-.493v-2.63a5.033 5.033 0 0 0 3.237 1.2c.333 0 .624-.03.872-.09.249-.06.456-.144.623-.25.166-.108.29-.234.373-.38a1.023 1.023 0 0 0-.074-1.089 2.12 2.12 0 0 0-.537-.5 5.597 5.597 0 0 0-.807-.444 27.72 27.72 0 0 0-1.007-.436c-.918-.383-1.602-.852-2.053-1.405-.45-.553-.676-1.222-.676-2.005 0-.614.123-1.141.369-1.582.246-.441.58-.804 1.004-1.089a4.494 4.494 0 0 1 1.47-.629 7.536 7.536 0 0 1 1.77-.201zm-15.113.188h9.563v2.166H9.506v9.646H6.789v-9.646H3.375z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1 @@
<svg fill="#4FC08D" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Vue.js</title><path d="M24,1.61H14.06L12,5.16,9.94,1.61H0L12,22.39ZM12,14.08,5.16,2.23H9.59L12,6.41l2.41-4.18h4.43Z"/></svg>

After

Width:  |  Height:  |  Size: 217 B

View file

@ -14,10 +14,21 @@ type OOBEStep =
| 'cross-platform'
| 'docker-setup'
| 'projects'
| 'language-select'
| 'template-select'
| 'complete';
// Framework template info
type FrameworkTemplate = {
id: string;
name: string;
description: string;
color: string;
icon: string;
};
// Wizard stages for sidebar progress display
type WizardStage = 'welcome' | 'dependencies' | 'platform' | 'identity' | 'complete';
type WizardStage = 'welcome' | 'dependencies' | 'platform' | 'identity' | 'templates' | 'complete';
// Map OOBE steps to wizard stages
function getWizardStage(step: OOBEStep): WizardStage {
@ -33,6 +44,9 @@ function getWizardStage(step: OOBEStep): WizardStage {
return 'platform';
case 'projects':
return 'identity';
case 'language-select':
case 'template-select':
return 'templates';
case 'complete':
return 'complete';
default:
@ -40,9 +54,9 @@ function getWizardStage(step: OOBEStep): WizardStage {
}
}
// Get stage index for progress tracking (1-5)
// Get stage index for progress tracking (1-6)
function getStageIndex(stage: WizardStage): number {
const stages: WizardStage[] = ['welcome', 'dependencies', 'platform', 'identity', 'complete'];
const stages: WizardStage[] = ['welcome', 'dependencies', 'platform', 'identity', 'templates', 'complete'];
return stages.indexOf(stage) + 1;
}
@ -75,6 +89,7 @@ function Sidebar({ currentStep }: { currentStep: OOBEStep }) {
{ key: 'dependencies' as const, label: 'Dependencies' },
{ key: 'platform' as const, label: 'Platform' },
{ key: 'identity' as const, label: 'Projects' },
{ key: 'templates' as const, label: 'Templates' },
{ key: 'complete' as const, label: 'Complete' },
];
@ -193,6 +208,33 @@ function PageTemplate({
secondaryLabel?: string;
primaryDisabled?: boolean;
}) {
// Render actions as a render prop so parent can place them where needed
const actionsElement = (primaryAction || secondaryAction) ? (
<div className="flex-shrink-0 pt-4 pb-6 flex flex-col items-center gap-1.5">
{primaryAction && primaryLabel && (
<button
onClick={primaryAction}
disabled={primaryDisabled}
className={`px-5 py-2 rounded-lg text-sm font-medium transition-colors border ${
primaryDisabled
? 'border-gray-300 dark:border-gray-700 text-gray-400 cursor-not-allowed'
: 'border-red-500 text-red-600 dark:text-red-400 hover:bg-red-500/10'
}`}
>
{primaryLabel}
</button>
)}
{secondaryAction && secondaryLabel && (
<button
onClick={secondaryAction}
className="text-xs text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
>
{secondaryLabel}
</button>
)}
</div>
) : null;
return (
<motion.div
variants={pageVariants}
@ -200,45 +242,21 @@ function PageTemplate({
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
className="h-full flex flex-col"
className="flex-1 flex flex-col"
>
{/* Header - centered */}
<div className="text-center mb-6 flex-shrink-0">
{/* Header - centered with horizontal padding */}
<div className="text-center mb-6 flex-shrink-0 px-10 pt-10">
<h1 className="text-2xl font-semibold text-gray-900 dark:text-white mb-1.5 tracking-tight">{title}</h1>
<p className="text-base text-gray-500 dark:text-gray-400">{subtitle}</p>
</div>
{/* Scrollable content area */}
<div className="flex-1 overflow-y-auto scrollbar-thin min-h-0">
{/* Scrollable content area with horizontal padding */}
<div className="flex-1 overflow-y-auto scrollbar-thin min-h-0 px-10">
{children}
</div>
{/* Actions - only shown if provided */}
{(primaryAction || secondaryAction) && (
<div className="flex-shrink-0 pt-4 flex flex-col items-center gap-1.5">
{primaryAction && primaryLabel && (
<button
onClick={primaryAction}
disabled={primaryDisabled}
className={`px-5 py-2 rounded-lg text-sm font-medium transition-colors border ${
primaryDisabled
? 'border-gray-300 dark:border-gray-700 text-gray-400 cursor-not-allowed'
: 'border-red-500 text-red-600 dark:text-red-400 hover:bg-red-500/10'
}`}
>
{primaryLabel}
</button>
)}
{secondaryAction && secondaryLabel && (
<button
onClick={secondaryAction}
className="text-xs text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
>
{secondaryLabel}
</button>
)}
</div>
)}
{/* Actions - anchored to bottom */}
{actionsElement}
</motion.div>
);
}
@ -254,7 +272,7 @@ function SplashPage({ onNext }: { onNext: () => void }) {
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
className="h-full flex flex-col items-center justify-center"
className="flex-1 flex flex-col items-center justify-center"
>
{/* Logo with glow effect */}
<motion.div
@ -312,7 +330,7 @@ function CheckingPage() {
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
className="h-full flex flex-col items-center justify-center"
className="flex-1 flex flex-col items-center justify-start pt-[30%]"
>
<motion.div
className="w-12 h-12 border-3 border-gray-300 dark:border-gray-600 border-t-red-500 rounded-full mb-6"
@ -338,7 +356,7 @@ function DepsReadyPage({ onNext }: { onNext: () => void }) {
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
className="h-full flex flex-col items-center justify-center"
className="flex-1 flex flex-col items-center justify-center"
>
{/* Animated checkmark */}
<motion.div
@ -512,7 +530,7 @@ function CrossPlatformPage({
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
className="h-full flex flex-col items-center justify-center"
className="flex-1 flex flex-col items-center justify-center"
>
{isReady ? (
<>
@ -631,7 +649,7 @@ function DockerSetupPage({
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
className="h-full flex flex-col items-center justify-center"
className="flex-1 flex flex-col items-center justify-center"
>
<div className="w-16 h-16 rounded-2xl bg-blue-500/20 flex items-center justify-center mb-6">
<svg className="w-10 h-10" viewBox="0 0 756.26 596.9">
@ -690,7 +708,7 @@ function DockerSetupPage({
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
className="h-full flex flex-col items-center justify-center"
className="flex-1 flex flex-col items-center justify-center"
>
<div className="w-16 h-16 rounded-2xl bg-gray-200 dark:bg-gray-800 flex items-center justify-center mb-6 opacity-50">
<svg className="w-10 h-10" viewBox="0 0 756.26 596.9">
@ -733,7 +751,7 @@ function DockerSetupPage({
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
className="h-full flex flex-col items-center justify-center"
className="flex-1 flex flex-col items-center justify-center"
>
<div className="w-16 h-16 rounded-2xl bg-blue-500/20 flex items-center justify-center mb-6">
<svg className="w-10 h-10" viewBox="0 0 756.26 596.9">
@ -781,7 +799,7 @@ function DockerSetupPage({
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
className="h-full flex flex-col items-center justify-center"
className="flex-1 flex flex-col items-center justify-center"
>
<motion.div
initial={{ scale: 0 }}
@ -819,7 +837,7 @@ function DockerSetupPage({
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
className="h-full flex flex-col items-center justify-center"
className="flex-1 flex flex-col items-center justify-center"
>
<div className="w-16 h-16 rounded-2xl bg-blue-500/20 flex items-center justify-center mb-6">
<svg className="w-10 h-10" viewBox="0 0 756.26 596.9">
@ -855,6 +873,144 @@ function DockerSetupPage({
);
}
// Available framework templates
const FRAMEWORKS: FrameworkTemplate[] = [
{ id: 'vanilla', name: 'Vanilla', description: 'Plain JavaScript/TypeScript', color: '#f7df1e', icon: 'javascript' },
{ id: 'react', name: 'React', description: 'React with Vite', color: '#61dafb', icon: 'react' },
{ id: 'vue', name: 'Vue', description: 'Vue 3 with Vite', color: '#42b883', icon: 'vue' },
{ id: 'svelte', name: 'Svelte', description: 'Svelte with Vite', color: '#ff3e00', icon: 'svelte' },
{ id: 'preact', name: 'Preact', description: 'Lightweight React alternative', color: '#673ab8', icon: 'preact' },
{ id: 'lit', name: 'Lit', description: 'Web Components with Lit', color: '#324fff', icon: 'lit' },
{ id: 'solid', name: 'Solid', description: 'Solid.js with Vite', color: '#2c4f7c', icon: 'solid' },
{ id: 'qwik', name: 'Qwik', description: 'Qwik with Vite', color: '#18b6f6', icon: 'qwik' },
];
// Language Select Page - TypeScript or JavaScript
function LanguageSelectPage({
preferTypeScript,
onSelect,
onNext,
}: {
preferTypeScript: boolean;
onSelect: (useTypeScript: boolean) => void;
onNext: () => void;
}) {
return (
<motion.div
variants={pageVariants}
initial="initial"
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
className="flex-1 flex flex-col"
>
{/* Main content - centered */}
<div className="flex-1 flex flex-col items-center justify-center">
<h2 className="text-2xl font-semibold text-gray-900 dark:text-white mb-2 text-center">
Language Preference
</h2>
<p className="text-gray-500 dark:text-gray-400 mb-8 text-center max-w-md">
Choose your preferred language for new projects
</p>
<div className="flex gap-4">
{/* JavaScript card */}
<button
onClick={() => onSelect(false)}
className={`w-40 h-48 rounded-xl p-5 flex flex-col items-center justify-center gap-3 transition-all border-2 ${
!preferTypeScript
? 'border-yellow-400 bg-yellow-400/10 shadow-lg shadow-yellow-400/20'
: 'border-white/10 bg-white/5 hover:bg-white/10'
}`}
>
<div className="w-16 h-16 flex items-center justify-center">
<img src="/logos/javascript.svg" alt="JavaScript" className="w-14 h-14" />
</div>
<span className="text-lg font-semibold text-white">JavaScript</span>
<span className="text-xs text-white/50">Dynamic typing</span>
</button>
{/* TypeScript card */}
<button
onClick={() => onSelect(true)}
className={`w-40 h-48 rounded-xl p-5 flex flex-col items-center justify-center gap-3 transition-all border-2 ${
preferTypeScript
? 'border-blue-400 bg-blue-400/10 shadow-lg shadow-blue-400/20'
: 'border-white/10 bg-white/5 hover:bg-white/10'
}`}
>
<div className="w-16 h-16 flex items-center justify-center">
<img src="/logos/typescript.svg" alt="TypeScript" className="w-14 h-14" />
</div>
<span className="text-lg font-semibold text-white">TypeScript</span>
<span className="text-xs text-white/50">Type safety</span>
</button>
</div>
</div>
{/* Button area - sibling below main content */}
<div className="flex justify-center pb-6">
<button
onClick={onNext}
className="px-5 py-2 rounded-lg border border-red-500 text-red-600 dark:text-red-400 text-sm font-medium hover:bg-red-500/10 transition-colors"
>
Continue
</button>
</div>
</motion.div>
);
}
// Template Select Page - Framework cards grid
function TemplateSelectPage({
selectedFramework,
preferTypeScript,
onSelect,
onNext,
onSkip,
}: {
selectedFramework: string;
preferTypeScript: boolean;
onSelect: (frameworkId: string) => void;
onNext: () => void;
onSkip: () => void;
}) {
return (
<PageTemplate
title="Default Template"
subtitle="Choose a framework for new projects"
primaryAction={onNext}
primaryLabel="Continue"
secondaryAction={onSkip}
secondaryLabel="Skip"
>
<div className="grid grid-cols-4 gap-3 max-w-2xl mx-auto">
{FRAMEWORKS.map((framework) => (
<button
key={framework.id}
onClick={() => onSelect(framework.id)}
className={`aspect-square rounded-xl p-4 flex flex-col items-center justify-center gap-2 transition-all border-2 ${
selectedFramework === framework.id
? 'border-red-500 bg-red-500/10 shadow-lg shadow-red-500/10'
: 'border-white/10 bg-white/5 hover:bg-white/10'
}`}
>
<img
src={`/logos/${framework.id === 'vanilla' ? (preferTypeScript ? 'typescript' : 'javascript') : framework.icon}.svg`}
alt={framework.name}
className="w-12 h-12"
/>
<span className="text-sm font-medium text-white">{framework.name}</span>
</button>
))}
</div>
<p className="text-xs text-white/40 mt-4 text-center">
This sets the default template for new projects
</p>
</PageTemplate>
);
}
// Projects Page - Company and Bundle ID (no template)
function ProjectsPage({
defaults,
@ -1022,31 +1178,49 @@ function CompletePage({ onClose }: { onClose: () => void }) {
animate="animate"
exit="exit"
transition={{ duration: 0.3 }}
className="h-full flex flex-col items-center justify-center"
className="flex-1 flex flex-col items-center justify-center px-8"
>
<motion.div
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{ type: 'spring', stiffness: 200, damping: 15 }}
className="w-20 h-20 rounded-full bg-green-500/20 flex items-center justify-center mb-6"
>
<svg className="w-10 h-10 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M5 13l4 4L19 7" />
</svg>
</motion.div>
{/* Header with check and title - compact */}
<div className="flex items-center gap-3 mb-4">
<motion.div
initial={{ scale: 0 }}
animate={{ scale: 1 }}
transition={{ type: 'spring', stiffness: 200, damping: 15 }}
className="w-8 h-8 rounded-full bg-green-500/20 flex items-center justify-center"
>
<svg className="w-4 h-4 text-green-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M5 13l4 4L19 7" />
</svg>
</motion.div>
<h2 className="text-lg font-semibold text-gray-900 dark:text-white">
You're ready to build!
</h2>
</div>
<h2 className="text-2xl font-semibold text-gray-900 dark:text-white mb-2">
You're ready to build!
</h2>
<p className="text-gray-500 dark:text-gray-400 mb-8 text-center max-w-sm">
Your development environment is all set up
</p>
<div className="bg-gray-100 dark:bg-gray-900/50 rounded-xl p-5 mb-8 w-full max-w-sm">
<div className="space-y-4">
<CopyableCommand command="wails3 init -n myapp" label="Create your first app:" />
<CopyableCommand command="cd myapp && wails3 dev" label="Start developing:" />
<CopyableCommand command="wails3 build" label="Build for production:" />
{/* Terminal-style command display */}
<div className="bg-gray-900 dark:bg-black/50 rounded-lg p-4 mb-6 w-full max-w-md font-mono text-xs border border-gray-700/50">
<div className="flex items-center gap-2 mb-3 pb-2 border-b border-gray-700/50">
<div className="w-2.5 h-2.5 rounded-full bg-red-500/80" />
<div className="w-2.5 h-2.5 rounded-full bg-yellow-500/80" />
<div className="w-2.5 h-2.5 rounded-full bg-green-500/80" />
<span className="text-gray-500 text-[10px] ml-2">terminal</span>
</div>
<div className="space-y-2 text-gray-300">
<div className="flex items-start gap-2">
<span className="text-green-400 select-none">$</span>
<span className="text-gray-100">wails3 init -n myapp</span>
<span className="text-gray-500 ml-auto text-[10px]"># create app</span>
</div>
<div className="flex items-start gap-2">
<span className="text-green-400 select-none">$</span>
<span className="text-gray-100">cd myapp && wails3 dev</span>
<span className="text-gray-500 ml-auto text-[10px]"># develop</span>
</div>
<div className="flex items-start gap-2">
<span className="text-green-400 select-none">$</span>
<span className="text-gray-100">wails3 build</span>
<span className="text-gray-500 ml-auto text-[10px]"># build</span>
</div>
</div>
</div>
@ -1069,73 +1243,6 @@ function CompletePage({ onClose }: { onClose: () => void }) {
);
}
// Persistent Docker status indicator
function DockerStatusIndicator({
status,
visible
}: {
status: DockerStatus | null;
visible: boolean;
}) {
if (!visible || !status) return null;
if (!status.installed || !status.running) return null;
if (status.imageBuilt && status.pullStatus !== 'pulling') return null;
const isPulling = status.pullStatus === 'pulling';
const progress = status.pullProgress || 0;
return (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 10 }}
className="bg-white/95 dark:bg-gray-900/95 border border-gray-200 dark:border-gray-700 rounded-lg shadow-lg px-3 py-2 backdrop-blur-sm min-w-[200px]"
>
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-blue-500/20 flex items-center justify-center flex-shrink-0">
<svg className="w-5 h-5" viewBox="0 0 756.26 596.9">
<path fill="#1d63ed" d="M743.96,245.25c-18.54-12.48-67.26-17.81-102.68-8.27-1.91-35.28-20.1-65.01-53.38-90.95l-12.32-8.27-8.21,12.4c-16.14,24.5-22.94,57.14-20.53,86.81,1.9,18.28,8.26,38.83,20.53,53.74-46.1,26.74-88.59,20.67-276.77,20.67H.06c-.85,42.49,5.98,124.23,57.96,190.77,5.74,7.35,12.04,14.46,18.87,21.31,42.26,42.32,106.11,73.35,201.59,73.44,145.66.13,270.46-78.6,346.37-268.97,24.98.41,90.92,4.48,123.19-57.88.79-1.05,8.21-16.54,8.21-16.54l-12.3-8.27ZM189.67,206.39h-81.7v81.7h81.7v-81.7ZM295.22,206.39h-81.7v81.7h81.7v-81.7ZM400.77,206.39h-81.7v81.7h81.7v-81.7ZM506.32,206.39h-81.7v81.7h81.7v-81.7ZM84.12,206.39H2.42v81.7h81.7v-81.7ZM189.67,103.2h-81.7v81.7h81.7v-81.7ZM295.22,103.2h-81.7v81.7h81.7v-81.7ZM400.77,103.2h-81.7v81.7h81.7v-81.7ZM400.77,0h-81.7v81.7h81.7V0Z"/>
</svg>
</div>
<div className="flex-1 min-w-0">
{isPulling ? (
<>
<div className="flex items-center gap-2 text-blue-600 dark:text-blue-400 text-sm mb-1">
<motion.span
className="w-3 h-3 border-2 border-blue-600 dark:border-blue-400 border-t-transparent rounded-full"
animate={{ rotate: 360 }}
transition={{ duration: 1, repeat: Infinity, ease: 'linear' }}
/>
<span className="truncate">Building image...</span>
</div>
<div className="flex items-center gap-2">
<div className="flex-1 h-1.5 bg-gray-200 dark:bg-gray-700 rounded-full overflow-hidden">
<motion.div
className="h-full bg-blue-500"
animate={{ width: `${progress}%` }}
/>
</div>
<span className="text-xs text-gray-500 tabular-nums">{progress}%</span>
</div>
</>
) : status.imageBuilt ? (
<div className="flex items-center gap-2 text-green-600 dark:text-green-400 text-sm">
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
<span>Docker image ready</span>
</div>
) : (
<div className="text-sm text-gray-600 dark:text-gray-400">
Preparing Docker build...
</div>
)}
</div>
</div>
</motion.div>
);
}
// Main App
export default function App() {
const [step, setStep] = useState<OOBEStep>('splash');
@ -1155,6 +1262,8 @@ export default function App() {
});
const [savingDefaults, setSavingDefaults] = useState(false);
const [backgroundDockerStarted, setBackgroundDockerStarted] = useState(false);
const [preferTypeScript, setPreferTypeScript] = useState(true);
const [selectedFramework, setSelectedFramework] = useState('vanilla');
const [theme, setTheme] = useState<Theme>(() => {
if (typeof window !== 'undefined') {
const saved = localStorage.getItem('wails-setup-theme');
@ -1282,14 +1391,45 @@ export default function App() {
setStep('projects');
};
const handleProjectsNext = async () => {
const handleProjectsNext = () => {
setStep('language-select');
};
const handleProjectsSkip = () => {
setStep('language-select');
};
const handleLanguageSelectNext = () => {
setStep('template-select');
};
const handleTemplateSelectNext = async () => {
// Build template name with TS suffix if needed
const templateName = preferTypeScript && selectedFramework !== 'vanilla'
? `${selectedFramework}-ts`
: preferTypeScript && selectedFramework === 'vanilla'
? 'vanilla-ts'
: selectedFramework;
// Update defaults with selected template
const updatedDefaults = {
...defaults,
project: {
...defaults.project,
defaultTemplate: templateName
}
};
setSavingDefaults(true);
await saveDefaults(defaults);
await saveDefaults(updatedDefaults);
setSavingDefaults(false);
setStep('complete');
};
const handleProjectsSkip = () => {
const handleTemplateSelectSkip = async () => {
setSavingDefaults(true);
await saveDefaults(defaults);
setSavingDefaults(false);
setStep('complete');
};
@ -1315,8 +1455,6 @@ export default function App() {
}
}, [backgroundDockerStarted, buildingImage, dockerStatus?.pullStatus]);
const showDockerIndicator = backgroundDockerStarted && step !== 'docker-setup' && step !== 'splash' && step !== 'checking';
return (
<ThemeContext.Provider value={{ theme, toggleTheme }}>
<div className="min-h-screen bg-gray-50 dark:bg-[#0f0f0f] flex items-center justify-center p-4 transition-colors relative overflow-hidden">
@ -1335,7 +1473,7 @@ export default function App() {
{/* Content area - distinct from sidebar in dark mode */}
<div className="flex-1 flex flex-col min-w-0 bg-white/50 dark:bg-white/[0.03]">
<div className="flex-1 flex flex-col p-10 min-h-0">
<div className="flex-1 flex flex-col min-h-0">
<AnimatePresence mode="wait">
{step === 'splash' && (
<SplashPage key="splash" onNext={handleSplashNext} />
@ -1383,23 +1521,29 @@ export default function App() {
saving={savingDefaults}
/>
)}
{step === 'language-select' && (
<LanguageSelectPage
key="language-select"
preferTypeScript={preferTypeScript}
onSelect={setPreferTypeScript}
onNext={handleLanguageSelectNext}
/>
)}
{step === 'template-select' && (
<TemplateSelectPage
key="template-select"
selectedFramework={selectedFramework}
preferTypeScript={preferTypeScript}
onSelect={setSelectedFramework}
onNext={handleTemplateSelectNext}
onSkip={handleTemplateSelectSkip}
/>
)}
{step === 'complete' && (
<CompletePage key="complete" onClose={handleClose} />
)}
</AnimatePresence>
</div>
{/* Docker status indicator - bottom left of content area */}
<div className="flex-shrink-0 px-6 pb-6 pt-2">
<AnimatePresence>
{showDockerIndicator && (
<DockerStatusIndicator
status={dockerStatus}
visible={showDockerIndicator}
/>
)}
</AnimatePresence>
</div>
</div>
</div>
</div>

View file

@ -50,7 +50,7 @@ html, body, #root {
/* Glass sidebar - blurred to show background through */
.glass-sidebar {
background: rgba(5, 7, 12, 0.75);
background: rgba(5, 7, 12, 0.55);
backdrop-filter: blur(30px);
-webkit-backdrop-filter: blur(30px);
border-right: 1px solid var(--glass-border);