Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
2918c17
Adding highlighted expressions to syntax
melissachen2000 May 8, 2026
fcebd43
Add instructions to the guide
melissachen2000 May 8, 2026
5c58afb
Adding buttons to formattededitor
melissachen2000 May 8, 2026
260e5b6
Only allow inserting of doc if in example
melissachen2000 May 8, 2026
b24a521
Remove unnecessary (?) formatting
melissachen2000 May 8, 2026
1ea687c
Consolidating code + don't allow doc if not inside example
melissachen2000 May 8, 2026
0caf560
collision detection more reliable and less flickery
amyjko May 9, 2026
b94ec78
made Phrases with custom characters also eligible to drag, rotate, an…
amyjko May 9, 2026
468fc9e
Bump hono from 4.12.16 to 4.12.18
dependabot[bot] May 9, 2026
2a05187
Revised semantics of Block.
amyjko May 9, 2026
11e848e
(Finally) added a background to the dialog close button.
amyjko May 9, 2026
855644f
Fixed #687: UI tutorials.
amyjko May 9, 2026
eadc5f8
fixed the region on the Swedish locale
amyjko May 9, 2026
b66fbf0
Other Swedish fixes.
amyjko May 9, 2026
04ca348
Improved link contrast.
amyjko May 9, 2026
4ffed96
Improved salience of confirm buttons.
amyjko May 9, 2026
e7deb4e
Feedback on project creation.
amyjko May 9, 2026
a6ddc86
Merge pull request #1109 from wordplaydev/dependabot/npm_and_yarn/hon…
amyjko May 9, 2026
87053c8
Updated dependencies.
amyjko May 9, 2026
f504729
Merge branch 'main' of https://github.com/wordplaydev/wordplay
amyjko May 9, 2026
1896015
Added translations, changelog.
amyjko May 9, 2026
a6754fd
Adding highlighted expressions to syntax
melissachen2000 May 8, 2026
7c5981d
Add instructions to the guide
melissachen2000 May 8, 2026
8bed194
Adding buttons to formattededitor
melissachen2000 May 8, 2026
d70a154
Only allow inserting of doc if in example
melissachen2000 May 8, 2026
af2c02f
Remove unnecessary (?) formatting
melissachen2000 May 8, 2026
2de0dcb
Consolidating code + don't allow doc if not inside example
melissachen2000 May 8, 2026
9be62db
Added translations, changelog.
amyjko May 9, 2026
678b9a5
Merge branch '1068-line-highlighting' of https://github.com/melissach…
amyjko May 9, 2026
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
16 changes: 13 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,35 @@ These notes are publicly posted in [production](https://wordplay.dev/updates), s

### Added

- We added a new "tour" help feature for each tile in the project view, explaining its purpose and core features. Try them out and let us know if we should expand the explanations! (#687).
- We added a machine translated Tagalog locale (#1089).
- We added additional keywords to all emojis to improve searching (#1090), but also translated all of those keywords, so that works in all supported locales (#639).
- We added much more robust menu suggestions for locales and locale parts (#1099).
- We added better unit suggestions in the autocomplete menu.
- We added a setting to control the spacing in blocks mode, for accessibility.
- We added a way to highlight expressions by adding 👀 inside some code's preceding explanatio, e.g., \¶👀¶"I'm highlighted!" This is helpful for how-to authors who want to emphasize some code.

### Changed

- We made the toolbar wrapping a bit better.
- We made the tile toolbar wrapping a bit better.
- We rearranged the project view footer to make the layout work better on smaller devices.
- We improved the list expand/collapse behavior when there are more than 10 items.
- We improved layout in blocks mode.
- We changed how blocks evaluate! Now, a Block with multiple non-`Bind` expressions will wrap the values in a list, instead of giving a warning and only evaluating to the last value. If your program had several expressions in a row and you only meant the last to be the result, wrap the earlier ones in `Bind` statements (or remove them). This will make it easier to create lists of values, including multiple `Phrase`s in a `Group`.
- We upgraded internal tooling for stability.

### Fixed

- We found and fixed a problem where the autocomplete menu wouldn't appear when activated in the menu.
- We removed some unnecessary scroll bars (#1098).
- We fixed a problem with pasting in Edge (#1092).
- We fixed a problem with duplicate translations crashing.
- We made copy and paste within the app more reliable and fast.
- We made collision detection more reliable and less flickery.
- We made Phrases with custom characters also eligible to drag, rotate, and scale.
- We fixed the region on the Swedish locale.
- We improved the contrast of links in light mode.
- We added loading feedback when a new project is greated on the projects or gallery page.

## 0.17.8 - 2026-05-02

Expand Down Expand Up @@ -52,8 +64,6 @@ These notes are publicly posted in [production](https://wordplay.dev/updates), s
- We fixed the contrast of the text cursor when the editor is in read only mode.
- We fixed a problem with how to errors crashing the browser.
- We separated the updates of the example views and the project views to prevent lag (#1093).
- We fixed a problem with duplicate translations crashing.
- We made copy and paste within the app more reliable and fast.

## 0.17.7 - 2026-04-25

Expand Down
8 changes: 8 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ Text input → **Parser** ([src/parser/](src/parser/)) → AST nodes ([src/nodes

All user-visible strings live in locale JSON files ([static/locales/](static/locales/), 38+ languages) validated against a schema. `Database` exposes the active locale as a Svelte store. Nodes, conflicts, values, and APIs all define localized descriptions via `Locale.ts`. Run `npm run locales` to verify and `npm run locales-fix` to repair issues.

**After every edit to a locale or tutorial JSON file** (anything under [static/locales/](static/locales/) — including the per-locale `*-tutorial.json` and `*-emojis.json` files — or [src/locale/en-US.json](src/locale/en-US.json)), run prettier on the changed files:

```bash
npx prettier --write '<changed files>'
```

Translation tools (e.g. `npm run locales-translate`) and direct script edits often produce inconsistent indentation, trailing newlines, or escape styles that diverge from the rest of the codebase. Running prettier keeps diffs clean and avoids spurious churn on later edits.

### Immutability convention

Immutable data structures and pure functions are the norm everywhere except: Svelte components (internal state + global context), `Evaluator` (stack-based evaluation state), and `Database` (persistence). Most bugs will be in those three areas.
Expand Down
1,561 changes: 814 additions & 747 deletions package-lock.json

Large diffs are not rendered by default.

27 changes: 22 additions & 5 deletions src/app.html
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,31 @@
match the @font-face rules in /fonts.css exactly — including the
crossorigin attribute — for the browser to reuse the preloaded bytes.
-->
<link rel="preload" href="/fonts/NotoSans/NotoSans-400-7.woff2" as="font" type="font/woff2" crossorigin />
<link rel="preload" href="/fonts/NotoSans/NotoSans-700-7.woff2" as="font" type="font/woff2" crossorigin />
<link rel="preload" href="/fonts/NotoEmoji/NotoEmoji-400.woff2" as="font" type="font/woff2" crossorigin />
<link
rel="preload"
href="/fonts/NotoSans/NotoSans-400-7.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<link
rel="preload"
href="/fonts/NotoSans/NotoSans-700-7.woff2"
as="font"
type="font/woff2"
crossorigin
/>
<link
rel="preload"
href="/fonts/NotoEmoji/NotoEmoji-400.woff2"
as="font"
type="font/woff2"
crossorigin
/>

<link rel="stylesheet" href="/fonts.css" />

<style>

:root {
--color-blue: #648fff;
--color-blue-transparent: color-mix(
Expand All @@ -80,7 +97,7 @@
);
--color-orange: #fe6100;
--color-orange-transparent: #fe61004b;
--color-yellow: #ffb000;
--color-yellow: #c88800;
--color-yellow-transparent: #ffb0004b;
--color-white: #ffffff;
--color-black: #000000;
Expand Down
22 changes: 15 additions & 7 deletions src/components/app/AddProject.svelte
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script lang="ts">
import Spinning from '@components/app/Spinning.svelte';
import Button from '@components/widgets/Button.svelte';
import { locales } from '@db/Database';
import Project from '@db/projects/Project';
Expand All @@ -10,7 +11,10 @@

let { add }: Props = $props();

let creating = $state(false);

async function newProject() {
creating = true;
add(
Project.make(
null,
Expand All @@ -29,11 +33,15 @@
</script>

<p class="add">
<Button
tip={(l) => l.ui.page.projects.button.newproject}
action={newProject}
testid="addproject"
large
icon="+"
></Button></p
{#if creating}
<Spinning />
{:else}
<Button
tip={(l) => l.ui.page.projects.button.newproject}
action={newProject}
testid="addproject"
large
icon="+"
></Button>
{/if}</p
>
2 changes: 1 addition & 1 deletion src/components/app/ProjectPreview.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@
.name {
display: flex;
flex-direction: column;
gap: var(--wordplay-spacing);
}

.untitled {
Expand Down Expand Up @@ -383,7 +384,6 @@
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-block-start: var(--wordplay-spacing);
gap: var(--wordplay-spacing);
row-gap: var(--wordplay-spacing);
}
Expand Down
3 changes: 3 additions & 0 deletions src/components/app/ProjectPreviewSet.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -77,16 +77,19 @@
tip={edit.description}
action={() => (edit ? edit.action(project) : undefined)}
icon={edit.label}
background
></Button>{/if}{#if copy}<Button
tip={copy.description}
action={() => copy.action(project)}
icon={copy.label}
background
></Button>{/if}{#if removeMeta}<ConfirmButton
prompt={removeMeta.prompt}
tip={removeMeta.description}
action={() =>
removeMeta ? removeMeta.action() : undefined}
icon={removeMeta.label}
background
></ConfirmButton>{/if}</div
>{@render children?.()}</ProjectPreview
>
Expand Down
124 changes: 69 additions & 55 deletions src/components/app/chat/CollaborateView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
{:else}
<section
class="collab"
data-uiid="collaborate"
aria-label={$locales.getPlainText((l) => l.ui.collaborate.label)}
>
<MarkupHTMLView
Expand Down Expand Up @@ -99,60 +100,70 @@

<!-- Show all of the collaborators -->
{#if owner == $user?.uid || project.getCollaborators().length > 0}
<Labeled label={(l) => l.ui.collaborate.role.collaborators}>
<CreatorList
anonymize={false}
uids={project.getCollaborators()}
{editable}
add={(userID) =>
Projects.reviseProject(
project.withCollaborator(userID),
)}
remove={(userID) =>
Projects.reviseProject(
project.withoutCollaborator(userID),
)}
removable={() => true}
/>
</Labeled>
<div data-uiid="collaborators">
<Labeled
label={(l) => l.ui.collaborate.role.collaborators}
>
<CreatorList
anonymize={false}
uids={project.getCollaborators()}
{editable}
add={(userID) =>
Projects.reviseProject(
project.withCollaborator(userID),
)}
remove={(userID) =>
Projects.reviseProject(
project.withoutCollaborator(userID),
)}
removable={() => true}
/>
</Labeled>
</div>
{/if}

<!-- Show all of the commenters -->
{#if owner === $user?.uid || project.getCommenters().length > 0}
<Labeled label={(l) => l.ui.collaborate.role.commenters}>
<CreatorList
anonymize={false}
uids={project.getCommenters()}
{editable}
add={(userID) =>
Projects.reviseProject(
project.withCommenter(userID),
)}
remove={(userID) =>
Projects.reviseProject(
project.withoutCommenter(userID),
)}
removable={() => true}
/>
</Labeled>
<div data-uiid="commenters">
<Labeled label={(l) => l.ui.collaborate.role.commenters}>
<CreatorList
anonymize={false}
uids={project.getCommenters()}
{editable}
add={(userID) =>
Projects.reviseProject(
project.withCommenter(userID),
)}
remove={(userID) =>
Projects.reviseProject(
project.withoutCommenter(userID),
)}
removable={() => true}
/>
</Labeled>
</div>
{/if}

<!-- Show all of the viewers -->
{#if owner === $user?.uid || project.getViewers().length > 0}
<Labeled label={(l) => l.ui.collaborate.role.viewers}>
<CreatorList
anonymize={false}
uids={project.getViewers()}
{editable}
add={(userID) =>
Projects.reviseProject(project.withViewer(userID))}
remove={(userID) =>
Projects.reviseProject(
project.withoutViewer(userID),
)}
removable={() => true}
/>
</Labeled>
<div data-uiid="viewers">
<Labeled label={(l) => l.ui.collaborate.role.viewers}>
<CreatorList
anonymize={false}
uids={project.getViewers()}
{editable}
add={(userID) =>
Projects.reviseProject(
project.withViewer(userID),
)}
remove={(userID) =>
Projects.reviseProject(
project.withoutViewer(userID),
)}
removable={() => true}
/>
</Labeled>
</div>
{/if}

{#if gallery}
Expand All @@ -175,15 +186,18 @@

<!-- Allow user to restrict access to non-curators -->
{#if owner === $user?.uid}
<Mode
modes={(l) =>
l.ui.collaborate.restrictGalleryCreatorAccess.mode}
choice={project.getRestrictedGallery() ? 1 : 0}
select={(index) =>
Projects.reviseProject(
project.withRestrictedGallery(index === 1),
)}
/>
<span data-uiid="restrictGallery">
<Mode
modes={(l) =>
l.ui.collaborate.restrictGalleryCreatorAccess
.mode}
choice={project.getRestrictedGallery() ? 1 : 0}
select={(index) =>
Projects.reviseProject(
project.withRestrictedGallery(index === 1),
)}
/>
</span>
{/if}
{/if}
</div>
Expand Down
Loading