Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2db2388
[UPDATE]: modified header padding
jcasben May 11, 2025
88ddced
[FIX]: corrected bug when cancelling mode change still redirected to …
jcasben May 11, 2025
3f2590b
[MOVED]: moved button component to layout folder
jcasben May 11, 2025
4dbcb0a
[MOVED]: changed import of button component
jcasben May 11, 2025
02d4ebe
[UPDATE]: changed init size of the canvas
jcasben May 11, 2025
9b4a940
[UPDATE]: changed size of the canvas and scene objects grid
jcasben May 11, 2025
eadef6d
[UPDATE]: added context menu for scene objects
jcasben May 13, 2025
9c13457
[UPDATE]: fixed problem switching to selected object when duplicating
jcasben May 13, 2025
33298f8
[UPDATE]: added inputs to change manually the values of the object
jcasben May 13, 2025
9f0d406
[UPDATE]: implemented rotation
jcasben May 13, 2025
358ae50
[UPDATE]: added thumbnail to activities representation in activity list
jcasben May 13, 2025
d42ecfa
[NEW]: added backgrounds and character sprites
jcasben May 14, 2025
0d1bd98
[UPDATE]: changed evaluate task button on teacher mode
jcasben May 14, 2025
ef88107
[UPDATE]: modified grid size
jcasben May 14, 2025
8f552d9
[UPDATE]: changed context menu to only be visible in teacher mode
jcasben May 14, 2025
e6a9ab6
[UPDATE]: added loading of background images
jcasben May 14, 2025
58777c0
[UPDATE]: disabled in student mode
jcasben May 14, 2025
7be3266
[NEW]: added modal for selecting character/background
jcasben May 14, 2025
b6e7b26
[NEW]: added mode service
jcasben May 14, 2025
c8d5a71
[UPDATE]: added code to open images modal
jcasben May 14, 2025
9f21ab7
[UPDATE]: fixed failing tests
jcasben May 14, 2025
626f454
[UPDATE]: changed text where mentioned task to say activity
jcasben May 14, 2025
11f5e44
[UPDATE]: swaped import and create buttons for consistency
jcasben May 15, 2025
a4a1597
[NEW]: abstracted method to load an image and get its html image repr…
jcasben May 15, 2025
ecaa5e2
[UPDATE]: changed scene object definition to have attribute size inst…
jcasben May 15, 2025
ee6597a
[FEAT]: implemented a button that allows the teacher changing the bac…
jcasben May 15, 2025
c887fe0
[FEAT]: the last mode used is now stored to local storage so when the…
jcasben May 15, 2025
800323f
[UPDATE]: modified activity definition to store the background of the…
jcasben May 15, 2025
790524d
[UPDATE]: optimized function to create and duplicate scene objects
jcasben May 15, 2025
8839059
[UPDATE]: optimized the way of loading the scene images for the first…
jcasben May 15, 2025
117b268
[UPDATE]: made images modal to select backgrounds and characters func…
jcasben May 15, 2025
266fdbd
[UPDATE]: converted backgrounds to webp
jcasben May 15, 2025
ee19856
[UPDATE]: added 3 new characters
jcasben May 15, 2025
fbde638
[UPDATE]: changed default character size to 100
jcasben May 15, 2025
b027740
[UPDATE]: extracted tailwindcss style into its own class
jcasben May 15, 2025
827b32b
[UPDATE]: made images modal fully functional
jcasben May 15, 2025
918d58e
[FIXED]: fixed mode service test
jcasben May 15, 2025
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
Binary file added public/backgrounds/desert.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/backgrounds/forest.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/backgrounds/underwater.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/backgrounds/winter.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/characters/bird.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/characters/cat.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/characters/dog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/characters/fish.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/characters/turtle.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
studentStyle="{{style}} text-student border-student"
teacherStyle="{{style}} text-teacher border-teacher"
/>
<div class="my-8 grid grid-cols-1 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6 justify-items-center">
<div class="my-8 grid grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-3 2xl:grid-cols-4 gap-6 justify-items-center">
@for (activity of activityList(); track activity.id) {
<blearn-activity
[activity]="activity"
Expand Down
11 changes: 7 additions & 4 deletions src/app/components/activity/activity.component.html
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
<div class="min-h-52 min-w-80 relative">
<div
class="bg-gray-400 rounded-lg shadow-md w-90 h-52 transition-transform hover:scale-105 hover:cursor-pointer active:scale-95 duration-150"
routerLink="/activity/{{activity.id}}">
@if (activity.thumbnail) {
<img [src]="activity.thumbnail" [alt]="activity.id" routerLink="/activity/{{activity.id}}" class="rounded-lg shadow-md w-90 h-52 transition-transform hover:scale-105 hover:cursor-pointer active:scale-95 duration-150">
} @else {
<div
class="bg-gray-400 rounded-lg shadow-md w-90 h-52 clickable"
routerLink="/activity/{{activity.id}}"></div>
}

</div>
<div class="py-2 px-4">
<div class="flex justify-between items-center relative">
<div>
Expand Down
4 changes: 3 additions & 1 deletion src/app/components/activity/activity.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ describe('ActivityComponent', () => {
toolboxInfo: {
toolboxDefinition: '',
BLOCK_LIMITS: {}
}
},
sceneObjects: [],
thumbnail: ''
};

it('should toggle the menu when clicking the button', async () => {
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/blocks-modal/blocks-modal.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {AfterViewInit, Component, EventEmitter, Input, Output, signal} from '@angular/core';
import {ButtonComponent} from '../button/button.component';
import {ButtonComponent} from '../../layout/button/button.component';
import * as Blockly from 'blockly';

@Component({
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Component, EventEmitter, inject, Input, Output, signal} from '@angular/core';
import {ButtonComponent} from '../button/button.component';
import {ButtonComponent} from '../../layout/button/button.component';
import {Activity} from '../../models/activity';
import {FormsModule} from '@angular/forms';
import {ModeService} from '../../services/mode.service';
Expand Down
20 changes: 20 additions & 0 deletions src/app/components/images-modal/images-modal.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<div class="fixed inset-0 flex justify-center items-center bg-black bg-opacity-50 z-50">
<div class="bg-white rounded-lg shadow-xl w-[50rem] max-h-[100vh]">
<div class="flex flex-row p-6 justify-between shadow-md">
<h2 class="text-4xl">{{ backgrounds ? 'Select the new background' : 'Select the new character' }}</h2>
<blearn-button
icon="xmark"
teacherStyle="bg-red-500 text-white"
(click)="close.emit()"
/>
</div>

<div class="grid grid-cols-3 justify-items-center">
@let paths = backgrounds ? backgroundPaths : charactersPaths;
@for (path of paths; track path) {
<img [src]="path" [ngClass]="[backgrounds ? 'w-[14rem] h-40' : 'w-40 h-40', 'm-4 rounded-md clickable']"
[alt]="path" (click)="imageSelected.emit(path)">
}
</div>
</div>
</div>
32 changes: 32 additions & 0 deletions src/app/components/images-modal/images-modal.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {Component, EventEmitter, Input, Output} from '@angular/core';
import {ButtonComponent} from "../../layout/button/button.component";
import {NgClass} from '@angular/common';

@Component({
selector: 'blearn-images-modal',
imports: [
ButtonComponent,
NgClass
],
templateUrl: './images-modal.component.html',
})
export class ImagesModalComponent {
@Input() backgrounds = false;
@Output() imageSelected = new EventEmitter<string>();
@Output() close = new EventEmitter<void>();

protected backgroundPaths = [
'/backgrounds/desert.webp',
'/backgrounds/forest.webp',
'/backgrounds/winter.webp',
'/backgrounds/underwater.webp',
];

protected charactersPaths = [
'/characters/cat.webp',
'/characters/dog.png',
'/characters/bird.png',
'/characters/turtle.png',
'/characters/fish.png',
];
}
11 changes: 11 additions & 0 deletions src/app/components/scene-input/scene-input.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<label class="flex flex-row items-center space-x-2">
<span>{{ label }}</span>
<input
class="border-2 p-2 w-14 text-center rounded-full"
type="number"
[placeholder]="label"
[value]="value"
(input)="onChange($event)"
[disabled]="modeService.getMode() === 'student'"
>
</label>
26 changes: 26 additions & 0 deletions src/app/components/scene-input/scene-input.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {Component, EventEmitter, inject, Input, Output} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {ModeService} from '../../services/mode.service';

@Component({
selector: 'blearn-scene-input',
imports: [
FormsModule
],
templateUrl: './scene-input.component.html',
})
export class SceneInputComponent {
protected modeService = inject(ModeService);

@Input() label!: string;
@Input() value!: number;

@Output() valueChange = new EventEmitter<number>();

onChange(event: Event) {
const inputElement = event.target as HTMLInputElement;

const parsed = parseFloat(inputElement.value);
if (!isNaN(parsed)) this.valueChange.emit(parsed);
}
}
91 changes: 75 additions & 16 deletions src/app/components/scene/scene.component.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<div #scene class="flex flex-col h-full w-full">
<div class="flex flex-row justify-center">
<main #scene class="flex flex-col h-full w-full px-4 py-2">
<div class="flex flex-row justify-center space-x-2 pb-2">
<blearn-button
icon="play"
studentText="Run"
teacherText="Run"
studentStyle="bg-green-500 text-white"
teacherStyle="bg-green-500 text-white"
studentStyle="bg-green-500 text-white py-2"
teacherStyle="bg-green-500 text-white py-2"
(clicked)="runCode.emit()"
[disabled]="isRunning()"
/>
Expand All @@ -20,22 +20,81 @@
/>
@if (modeService.getMode() === 'teacher') {
<blearn-button
icon="plus"
teacherText="Add"
icon="image"
teacherText="Change background"
teacherStyle="bg-gray-500 text-white"
(clicked)="addObject()"
(clicked)="backgroundChange.emit()"
[disabled]="isRunning()"
/>
}
</div>

<div class="flex flex-row space-x-4">
@for (obj of sceneObjects; track obj.id) {
<img [src]="obj.imgSrc"
[alt]="obj.id"
[ngClass]="['w-24 h-24 rounded', selectedObject() === obj.id ? 'border-4 border-red-500' : '']"
(click)="objectSelected.emit(obj.id)">
<canvas #canvas class="w-[40rem] h-[26rem] border-transparent rounded-lg"></canvas>

<aside class="pt-4">
@let obj = selectedObject();
@if (obj) {
<div class="flex flex-row space-x-8 justify-center">
<blearn-scene-input
[value]="obj.x"
label="x"
(valueChange)="obj.x = $event; drawImages();"
/>

<blearn-scene-input
[value]="obj.y"
label="y"
(valueChange)="obj.y = $event; drawImages();"
/>

<blearn-scene-input
[value]="obj.size"
label="size"
(valueChange)="obj.size = $event; drawImages();"
/>

<blearn-scene-input
[value]="obj.rotation"
label="rotation"
(valueChange)="obj.rotation = $event; drawImages();"
/>
</div>
}
</div>

<canvas #canvas class="w-full h-screen bg-gray-300"></canvas>
</div>
<div>
<h3 class="text-2xl py-4"><strong>Scene Objects</strong></h3>

<div class="grid grid-cols-5 gap-4 justify-items-center">
@for (obj of sceneObjects; track obj.id) {
<img [src]="obj.imgSrc"
[alt]="obj.id"
[ngClass]="['w-24 h-24 rounded clickable', selectedObjectId() === obj.id ? 'border-4 border-red-500' : '']"
(click)="objectSelected.emit(obj.id)"
(contextmenu)="onRightClick($event, obj)"
>
}

@if (modeService.getMode() === 'teacher') {
<div
class="flex w-24 h-24 text-white border-2 border-gray-500 rounded clickable"
(click)="objectAdded.emit()">
<span class="fas fa-plus w-8 h-8 bg-gray-500 p-2 rounded-full m-auto"></span>
</div>
}
</div>
</div>

@if (contextMenuVisible && modeService.getMode() === 'teacher') {
<div
class="absolute z-50 bg-white border border-gray-300 shadow-lg rounded p-2 w-40"
[style.left.px]="contextMenuX"
[style.top.px]="contextMenuY"
>
<button class="w-full text-left px-2 py-1 hover:bg-gray-100" (click)="objectDuplicated.emit(contextMenuObject!.id)">Duplicate</button>
<button class="w-full text-left px-2 py-1 hover:bg-gray-100 text-red-600"
(click)="objectDeleted.emit(contextMenuObject!.id)">Delete
</button>
</div>
}
</aside>
</main>
Loading