Сегодня мы продолжим переписывать $mol Этот демо. Если вы не читали первую часть, я рекомендую вам сначала прочитать BALLSORT на $mol. Часть 1

Напомню задание

гифка

Экраны

  • Старт — стартовый экран с заголовком, кнопкой запуска игры и нижним колонтитулом со ссылками.

  • Игра – при нажатии на кнопку запуска открывается экран с игрой, где нужно рассортировать шарики. В шапке расположены кнопки возврата на стартовый экран и повторного запуска игры, а также счетчик количества пройденных шагов. В центре трубочка с шариками. В футере те же ссылки, что и на первом скрине.

  • Готово – когда шары будут отсортированы, над вторым экраном появится третий экран. Он содержит заголовок «Вы выиграли!», количество пройденных шагов и кнопку «Новая игра», которая открывает стартовый экран.

игровая механика

  1. Нарисовано 6 трубочек, четыре из них заполнены шариками, а две пусты.

  2. Заполненные тубы содержат 4 шарика 4 разных цветов.

  3. Когда вы нажимаете на непустую трубку, она переходит в активное состояние.

  4. Новый щелчок по активной трубке деактивирует ее, мяч переносится обратно в нее

  5. После активации пробирки нажатие на другую пробирку переносит шарик с крышки на другую пробирку, при условии, что другая пробирка пуста или верхний шарик другой пробирки того же цвета, что и шарик на крышке активной пробирки.

  6. Когда все 4 шарика одного цвета находятся в трубке, трубка переходит в состояние готовности, после чего шарики нельзя задвигать/вынимать из нее.

  7. Игра закончится, когда будут готовы 4 трубки.

Отображать

Создадим отдельные модули для отображения:

  • Соединения

  • Кнопки

  • Мера

  • трубка

А потом мы объединим все это в модуль app.

связь

Создать каталог ballsort/link и классифицировать его link.view.tree.

$hype_ballsort_link $mol_view
	dom_name \a
	attr *
		href <= href \
		target <= target \_self
	sub / <= title \

view.tree — это DSL, прежде чем продолжить, я рекомендую вам прочитать эти книги: Состав компонентов, Декларативный состав компонентов

Прочитав документы по ссылкам выше, вы понимаете, что мы описали класс $hype_ballsort_linkкоторый унаследован от базового класса компонента представления $mol_view. Название тега изменено на aузел dom имеет два определенных атрибута href И target на который привязаны одноименные свойства, и как дочерний элемент узла dom мы производим строку из свойства title.

Нарисуем этот компонент. Открыть ссылку в браузере это модуль приложения, который содержит файл index.html. На экране отображается только домашняя линия.

Редактировать файл app/app.view.tree

$hype_ballsort_app $mol_view
	sub /
		<= Components $mol_list
			rows /
				<= Link $hype_ballsort_link
					title \Ссылка
					href \example.com
					target \_blank

$mol_list — это компонент представления торгового центра, для отображения вертикального списка мы будем использовать его временно.

Смотрим в браузере:

связь

связь

Добавляйте стили, создавайте в link подать link.view.css.ts

namespace $.$$ {
	
	$mol_style_define( $hype_ballsort_link, {
		
		color: 'lightgray',
		padding: ['0.25rem', '1rem'],
		
	} )
	
}

В отношении css.ts можно прочитать здесь: Каскадные стили компонентов, Расширенный CSS в TS, $mol_style readme.md

Готово, компонент ссылки теперь имеет необходимую функциональность и выглядит так же, как в исходном приложении.

кнопка

Мы делаем то же самое для компонента кнопки.

В файл ballsort/button/button.view.tree:

$hype_ballsort_button $mol_view
	dom_name \button
	sub / <= title \
	event *
		click? <=> click? null

Поднесите кнопку к app:

$hype_ballsort_app $mol_view
	sub /
		<= Components $mol_list
			rows /
				<= Link $hypr_ballsort_link
					title \Ссылка
					href \example.com
					target \_blank
				<= Button $hype_ballsort_button
					title \Кнопка

Убеждаемся, что кнопка подтянута:

Кнопка

Кнопка

Добавление стилей в файл button.view.css.ts:

namespace $.$$ {

	$mol_style_define( $hype_ballsort_button, {

		width: 'fit-content',
		backgroundColor: 'white',
		color: 'black',
		padding: ['0.6rem', '1rem'],
		fontSize: '1.3rem',
		margin: [0, '0.2rem'],
		border: {
			width: '2px',
			style: 'solid',
			color: 'lightgray',
		},
		cursor: 'pointer',
		position: 'relative',

		':hover': {
			backgroundColor: '#f1f1f1',
		},

		':focus': {
			outline: 'none',
			boxShadow: '0 0 0 4px lightblue',
			borderColor: 'lightblue',
		},

	} )

}
Кнопка со стилями

Кнопка со стилями

мяч

Теперь давайте создадим компонент для мяча. Имя $hype_ballsort_ball уже занят в классе модели, поместим рамку вида шара в $hype_ballsort_ball_view.

Создать файл ballsort/ball/view/view.view.tree

Комментарии в view.tree начинаются со знака минус

$hype_ballsort_ball_view $mol_view
	- Компонент шара будет принимать модель шара, из которой он достает цвет
	ball $hype_ballsort_ball
	- Для раскраски шара будет использоваться радиальный градиент из двух цветов
	style *
		--main-color <= color_main \
		--light-color <= color_light \
	- Цвета заранее заготовлены в массиве, такие же как в оригинальном приложении
	- Всего предусмотрено 12 цветов, индексы от 0 до 11
	- цвет по индексу 0 - основной цвет - color_main
	- цвет по индексу 0 + 1 - второй цвет - color_light
	colors /
		\#8F7E22
		\#FFE600
		\#247516
		\#70FF00
		\#466799
		\#00B2FF
		\#29777C
		\#00FFF0
		\#17206F
		\#4A72FF
		\#BABABA
		\#FFFFFF
		\#4C3283
		\#9D50FF
		\#8B11C5
		\#FF00F5
		\#9D0D41
		\#FF60B5
		\#4B0000
		\#FF0000
		\#79480F
		\#FF7A00
		\#343434
		\#B1B1B1

Рисуем шарик в app

$hype_ballsort_app $mol_view
	sub /
		<= Components $mol_list
			rows /
				<= Link $hype_ballsort_link
					title \Ссылка
					href \example.com
					target \_blank
				<= Button $hype_ballsort_button
					title \Кнопка
				<= Ball $hype_ballsort_ball_view

И мы его не видим, но он есть

ЧИТАТЬ   Пользователи TikTok подали иск, чтобы заблокировать запрет Монтаны на приложение: подробности
невидимая пуля

невидимая пуля

Добавьте к нему стили, создайте файл ball/view/view.view.css.ts

namespace $.$$ {

	$mol_style_define( $hype_ballsort_ball_view, {

		width: '2rem',
		height: '2rem',
		boxSizing: 'content-box',

		border: {
			radius: '50%',
			width: '2px',
			style: 'solid',
			color: 'black',
		},

		margin: '1px',
		position: 'relative',
		backgroundImage: 'radial-gradient(circle at 65% 15%, white 1px, var(--light-color) 3%, var(--main-color) 60%, var(--light-color) 100%)',

	} )

}
что-то появилось

что-то появилось

Теперь нам нужно научить мяч принимать правильные цвета, давайте добавим немного логики. Создать файл view.view.ts.

namespace $.$$ {
	export class $hype_ballsort_ball_view extends $.$hype_ballsort_ball_view {

		// В свойстве ball хранится инстанс модели шара
		// из модели достаем цвет `color()` и умножаем на 2
		// чтобы получить правильный индекс в массиве цветов
		color_index() {
			return this.ball().color() * 2
		}
		
		// Достаем из массива основной цвет по посчитанному индексу
		// На случай если нам пришел индекс выходящий за массив с цветами
		// выводим красный цвет
		color_main() {
			return this.colors()[ this.color_index() ] ?? 'red'
		}

		// Достаем второй цвет по индексу + 1
		// и устанавливаем значение по умолчанию
		color_light() {
			return this.colors()[ this.color_index() + 1 ] ?? 'white'
		}

	}
}

А так как в модели по умолчанию цвет равен 0, мы видим первый цвет массива

ЖЕЛТЫЙ

ЖЕЛТЫЙ

трубка

Нам еще нужно создать компонент для трубы. По аналогии с шариком создаем файл tube/view/view.view.tree

Сделаем это на основе $mol_listпотому что он состоит из двух вертикальных частей

$hype_ballsort_tube_view $mol_list
	tube $hype_ballsort_tube
	active false
	event *
		click? <=> click? null
	rows /
		<= Roof $mol_view sub / <= roof null
		<= Balls $mol_list
			style * min-height \10rem
			attr *
				data-complete <= complete false
			rows <= balls /
				<= Ball*0 $hype_ballsort_ball_view
					ball <= ball* $hype_ballsort_ball

  • tube $hype_ballsort_tube – так же, как компонент шара, он будет хранить модель трубы

  • active false – свойство типа boolean нужно показать активацию

  • event * click? <=> click? null – биндим свойство click по событию клика

  • rows / – отображать детей на $mol_list предоставленное имущество rowsНо нет sub как $mol_view

  • <= Roof $mol_view sub / <= roof null – в собственности Roof подкомпонент будет найден $mol_viewкоторый отображает содержимое свойства roof – это по умолчанию null. Но когда трубка активирована roof вернет взгляд на мяч

  • <= Balls $mol_list – в собственности Balls на основе подкомпонентов $mol_list покажет шарики в трубе

  • style * min-height \10rem – минимальная высота указана style

  • attr * data-complete <= complete false – для отображения состояния готовности мы будем использовать атрибут данных

  • rows <= balls / – в подкомпоненте Balls свойство rows заменить на нашу собственность balls который вернет массив шаров просмотра

О последней части я расскажу отдельно.

<= Ball*0 $hype_ballsort_ball_view
	ball <= ball* $hype_ballsort_ball

Свойство Ball – это фабрика, которая в сгенерированном классе будет помечена декоратором $mol_mem_key. Те. он будет создавать и возвращать экземпляры шаров просмотра так же, как мы делали это вручную в $hype_ballsort_game. Кроме того, свойство созданного мгновения будет изменено ball к нашему.

Пример из модели:

		@$mol_mem_key
		Tube( index: number ) {
			const obj = new $hype_ballsort_tube
			obj.size = () => this.tube_size()
			return obj
		}

И это будет сгенерировано из view.tree описания:

		@ $mol_mem_key
		Ball(id: any) {
			const obj = new this.$.$hype_ballsort_ball_view()
			
			obj.ball = () => this.ball(id)
			
			return obj
		}

Поднимите трубку для app:

$hype_ballsort_app $mol_view
	sub /
		<= Components $mol_list
			rows /
				<= Link $hype_ballsort_link
					title \Ссылка
					href \example.com
					target \_blank
				<= Button $hype_ballsort_button
					title \Кнопка
				<= Ball $hype_ballsort_ball_view
				<= Tube $hype_ballsort_tube_view
					balls /
						<= Ball1 $hype_ballsort_ball_view
							color_index 2
						<= Ball2 $hype_ballsort_ball_view
							color_index 4
						<= Ball3 $hype_ballsort_ball_view
							color_index 6

И переопределить его собственность balls видеть пули. А чтобы шарики были разного цвета, для каждого шарика переопределяем свойство color_index.

Не похоже на трубку.

Не похоже на трубку.

Создать файл tube/view/view.view.css.ts

namespace $.$$ {

	$mol_style_define( $hype_ballsort_tube_view, {

		// В оригинальном приложении box-sizing = content-box
		// а у $mol_view по дефолту стоит border-box
		// поэтому меняем
		boxSizing: 'content-box',
		width: 'fit-content',

		Roof: {
			boxSizing: 'content-box',
			height: '3rem',
			alignItems: 'center',
			justifyContent: 'center',
			border: {
				bottom: {
					style: 'solid',
					color: 'lightgray',
				},
			},
		},

		Balls: {
			boxSizing: 'content-box',
			width: '3rem',
			flex: {
				direction: 'column-reverse',
			},
			justifyContent: 'flex-start',
			alignItems: 'center',

			border: {
				width: '2px',
				style: 'solid',
				color: 'lightgray',
			},

			padding: {
				bottom: '0.4rem',
				top: '0.4rem',
			},

			borderRadius: '0 0 2.4rem 2.4rem',

			'@': {
				'data-complete': {
					true: {
						// Когда data-complete=true
						backgroundColor: 'lightgray',
					},
				},
			},
		},

	} )

}
Теперь что-то вроде

Теперь что-то вроде

В $hype_ballsort_app добавьте мяч в верхнюю часть трубки:

				- ...
				<= Tube $hype_ballsort_tube_view
					balls /
						<= Ball1 $hype_ballsort_ball_view
							color_index 2
						<= Ball2 $hype_ballsort_ball_view
							color_index 4
						<= Ball3 $hype_ballsort_ball_view
							color_index 6
					roof <= Ball4 $hype_ballsort_ball_view
						color_index 8
Мяч на кепке отображается

Мяч на кепке отображается

Осталось только добавить поведение, создать файл tube/view/view.view.ts

namespace $.$$ {

	export class $hype_ballsort_tube_view extends $.$hype_ballsort_tube_view {

		// Шар на крышке
		@ $mol_mem
		roof() {
			// Получаем индекс последнего шара, напомню что this.tube() возвращает модель трубки
			// Через фабрику получаем инстанс компонента шара который возвращаем
			// Или возвращаем null
			const index = this.tube().balls().length - 1
			return this.active() ? this.Ball( index ) : null
		}

		// Массив компонентов шаров, которые будут отображаться в трубке
		@ $mol_mem
		balls() {
			// В зависимости от активности трубки получаем список моделей шаров
			const last_ball = this.tube().balls().at(-1)
			const list = this.active() ? [last_ball] : this.tube().balls()
			
			// Превращаем его в список компонентов шаров
			return list.map((_, index) => this.Ball(index))
		}

		// Получаем модель шара по индексу
		ball(index: number) {
			return this.tube().balls()[index]
		}

		// Вытаскиваем из трубки состояние статуса готово
		complete() {
			return this.tube().complete()
		}

	}

}

заголовок

Давайте создадим подкомпонент для отображения заголовка.

ЧИТАТЬ   Бывший американский наемник высказался о продаже оружия из Украины
Само название

Само название

Мы не будем выносить его в отдельный модуль. Давайте добавим его как подкомпонент к app.view.tree

$hype_ballsort_app $mol_view
	sub /
		<= Components $mol_list
			rows /
				- ...
				<= Title $mol_view
					dom_name \h2
					sub /
						<= Title_begin $mol_view sub / \BALL
						<= Title_end $mol_view sub / \SORT

Давай посмотрим что происходит

Давай посмотрим что происходит

Добавьте к нему стили, создайте файл app.view.css.ts

namespace $.$$ {

	$mol_style_define( $hype_ballsort_app, {

		Title: {
			font: {
				size: '3rem',
				weight: 300,
			},
		},

		Title_begin: {
			textDecoration: 'underline',
		},

	} )

}

Выглядит как

Выглядит как

приложение

Теперь можем собрать экраны, убрать лишнее app.view.tree и создайте основную структуру:

$hype_ballsort_app $mol_view
	game $hype_ballsort_game
	title \BALL SORT
	Title $mol_view
		dom_name \h2
		sub /
			<= Title_begin $mol_view sub / \BALL
			<= Title_end $mol_view sub / \SORT
	sub /
		<= Start_page $mol_list
		<= Game_page $mol_list
		<= Finish_page $mol_list
  • game $hype_ballsort_game – в собственности game мы будем хранить текущий экземпляр игры

  • title \BALL SORT – что будет отображаться в шапке вкладки

  • Start_page, Game_page, Finish_page заготовки для страниц

Домашняя страница

И давайте сразу украсим заставку:

	- ...
	sub /
		<= Start_page $mol_list
			rows /
				<= Title
				<= Start $hype_ballsort_button
					title \Start game
					click? <=> start? null
				<= Links $mol_view
					sub /
						<= Sources $hype_ballsort_link
							title \Source Code
							href \
							target \_blank
		<= Game_page $mol_list
		<= Finish_page $mol_list
  • Сначала мы отображаем Title

  • Затем кнопка «Пуск» Startщелчок по нему привязывается к свойству startк которому мы добавим поведение позже

  • И отображается блок со ссылками в свойстве Links

Давайте посмотрим, как это выглядит

Почти заставка

Почти заставка

Добавим недостающие стили в app.view.css.tsЯ просто перетаскиваю их из оригинального приложения.

namespace $.$$ {

	$mol_style_define( $hype_ballsort_app, {

		fontFamily: 'system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, Cantarell, Noto Sans, sans-serif, BlinkMacSystemFont, Helvetica, Arial, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol',
		color: '#e1e1e1',
		lineHeight: 'normal',

		padding: {
			top: '1rem',
		},

		justifyContent: 'center',

		background: {
			color: '#101526',
		},

		// Title, Title_begin ...

		Links: {
			padding: {
				top: '1rem',
			},
			justifyContent: 'center',
			flex: {
				wrap: 'wrap',
			},
		},

		Start_page: {
			alignItems: 'center',
		},

	} )

}
Домашняя страница

Домашняя страница

страница_игры

Перейдем на страницу игры, она состоит из трех вертикальных блоков.

  • Кнопки управления + отображение количества шагов

  • Шариковые трубы

  • Те же ссылки, что и на главной странице

Должно быть что-то вроде этого:

Game_page
	Control
		Home - кнопка возврата на стартовый экран
		Restart - кнопка перезапуска игры
		Move - число с количеством шагов
	Tubes - трубки с шариками
	Links - ссылка

Добавьте это в app.view.tree

$hype_ballsort_app $mol_view
	- ...
	sub /
		<= Start_page $mol_list
			- ...
		<= Game_page $mol_list
			rows /
				<= Control $mol_view
					sub /
						<= Home $hype_ballsort_button
							title \←
							click? <=> home? null
						<= Restart $hype_ballsort_button
							title \Restart 
							click? <=> start?
				<= Tubes $mol_view
				<= Links
		<= Finish_page $mol_list
Два экрана сразу

Два экрана сразу

Как мы будем определять, запущена игра или нет?

В view.tree у нас объявлено свойство игры, в котором хранится экземпляр игрового класса. В view.ts мы переопределим его, сделаем изменяемым свойством и по умолчанию оно будет возвращать null. Логика такова:

  • game обратная связь null – показать заставку

  • game вернуть экземпляр игры – показать экран игры

  • Нажатие кнопок запуска и перезагрузки поместит свойство game новая копия игры

  • Нажатие кнопки «Назад» поместит null к собственности game

  • Чтобы понять, что игра окончена, в классе игры есть свойство finish мы будем использовать это

Как мы будем менять экран?

Теперь у нас есть все три экрана, отображаемые в свойстве sub. В view.ts нам нужно переопределить свойство subчтобы он возвращал только один экран за раз.

Создать файл app.view.tsпомните фрагменты кода в VSCode, здесь вам нужен фрагмент logic.

namespace $.$$ {

	export class $hype_ballsort_app extends $.$hype_ballsort_app {

		// Переопределяем свойство game
		// Теперь оно изменяемое и nullable
		@ $mol_mem
		game(next?: $hype_ballsort_game | null) {
			return next ?? null!
		}

		// Кнопки start и restart забиндены на свойство start
		// Тут мы просто помещаем новый инстанс игры в свойство game
		@ $mol_action
		start() {
			this.game( new $hype_ballsort_game )
		}

		// Кнопка возврата забиндена на свойство `home`
		// Тут мы помещаем null в свойство game 
		@ $mol_action
		home() {
			this.game(null)
		}

		// Дети компонента $mol_view берутся из свойства sub
		// Тут мы возвращаем нужный экран в зависимости состояния игры
		@ $mol_mem
		sub() {
			if (!this.game()) return [ this.Start_page() ]
			return [ this.game().finished() === false ? this.Game_page() : this.Finish_page() ]
		}

	}

}
Переходы экрана

Переходы экрана

Трубки и шарики

Теперь настала очередь рисовать трубочки с шариками. Нам нужно взять список труб из игры и отобразить его, завернув каждую модель трубы в компонент представления.

ЧИТАТЬ   Девушка покрасила волосы в Турции и показала неожиданный результат

давай меняться app.view.tree

$hype_ballsort_app $mol_view
	- ...
	sub /
		<= Start_page $mol_list
			- ...
		<= Game_page $mol_list
			rows /
				<= Control $mol_view
					- ...
				<= Tubes $mol_view
					sub <= tubes /
						<= Tube*0 $hype_ballsort_tube_view
							tube <= tube* $hype_ballsort_tube
							click? <=> tube_click*? null
							active <= tube_active* false
				<= Links
		<= Finish_page $mol_list

Что здесь происходит:

  • <= Tubes $mol_view – создаем подкомпонент Tubes на основе базового компонента $mol_view и поместите его в rows / к объекту в собственности Game_page

  • sub <= tubes / свойство sub В Tubes заменяемый имуществом tubes и установите его значение по умолчанию

  • И как ценность мы заменяем фабричную собственность Tube в зависимости от компонента вида трубы, и сразу настроить его, изменив свойства tube, click, active

Приведенный выше код преобразуется в этот код TS:

		@ $mol_mem
		Tubes() {
			const obj = new this.$.$mol_view()
			obj.sub = () => this.tubes()
			return obj
		}

		tubes() {
			return [
				this.Tube("0")
			] as readonly any[]
		}

Мы должны переопределить tubesтак что он берет список каналов из игровой модели и оборачивает его в компонент представления канала. давай меняться app.view.ts

namespace $.$$ {

	export class $hype_ballsort_app extends $.$hype_ballsort_app {

		// ...

		@ $mol_mem
		tubes() {
			return this.game().tubes().map( ( _, index ) => this.Tube( index ) )
		}

	}

}
Нажав на старт мы увидим заполненные пробирки

Нажав на старт мы увидим заполненные пробирки

Добавить реализацию для свойств tube, tube_click, tube_activeчто мы описали в view.tree

tube <= tube* $hype_ballsort_tube
click? <=> tube_click*? null
active <= tube_active* false

давай меняться app.view.ts Снова:

namespace $.$$ {

	export class $hype_ballsort_app extends $.$hype_ballsort_app {

		// ...

		@ $mol_mem
		tubes() {
			return this.game().tubes().map( ( _, index ) => this.Tube( index ) )
		}

		// По индексу достаем инстанс модели трубки из игры
		// декротар тут можно опустить
		tube( index: number ) {
			return this.game().Tube(index)
		}
	
		// По клику вызываем tube_click в игре
		// Передавая туда трубку по которой кликнули
		@ $mol_action
		tube_click( index: number ) {
			this.game().tube_click( this.tube(index) )
		}

		// Проверяем активна ли текущая трубка
		@ $mol_mem_key
		tube_active( index: number ) {
			return this.game().tube_active() === this.tube(index) 
		}
	}

}
мы уже можем играть

мы уже можем играть

Напечатаем количество шагов. давай меняться app.view.tree

$hype_ballsort_app $mol_view
	- ...
	sub /
		<= Start_page $mol_list
			- ...
		<= Game_page $mol_list
			rows /
				<= Control $mol_view
					sub /
						<= Home $hype_ballsort_button
							title \←
							click? <=> home? null
						<= Restart $hype_ballsort_button
							title \Restart 
							click? <=> start?
						- Тут добавим Moves
						<= Moves $mol_view
							sub / <= moves \Moves: {count}
				- ...
		<= Finish_page $mol_list

А в view.ts переопределим свойство movesmoves \Moves: {count}заменять {count} по количеству шагов

namespace $.$$ {

	export class $hype_ballsort_app extends $.$hype_ballsort_app {

		// ...

		@ $mol_mem
		moves() {
			return super.moves().replace( '{count}', `${ this.game().moves() }` )
		}
	}

}
Отображение количества шагов

Отображение количества шагов

И добавьте стили в app.view.css.ts

namespace $.$$ {

	$mol_style_define( $hype_ballsort_app, {

		// ...

		Moves: {
			padding: ['0.6rem', '0.4rem'],
			fontSize: '1.3rem',
		},

		Tubes: {
			justifyContent: 'center',
		},

		Control: {
			justifyContent: 'center',
		},

		Tube: {
			margin: '1rem',
		},

	} )

}
игровой экран

игровой экран

end_page

Осталось только добавить финишный экран. давай меняться app.view.tree:

$hype_ballsort_app $mol_view
	- ...
	sub /
		- ...
		<= Finish_page $mol_list
			rows /
				<= Control
				<= Tubes
				<= Links
				<= Finish $mol_list
					rows /
						<= Finish_title $mol_view
							dom_name \h1
							sub / \You won!
						<= Finish_moves $mol_view
							dom_name \h2
							sub / \In 16 moves
						<= Finish_home $hype_ballsort_button
							title \New game
							click? <=> home?

Экран прибытия, отображается в верхней части игрового экрана. Control, Tubes, Links и после завершения регистраций и кнопки.

Сразу добавить стили для него в app.view.css.ts

namespace $.$$ {

	$mol_style_define( $hype_ballsort_app, {

		Finish: {
			position: 'fixed',
			bottom: 0,
			top: 0,
			left: 0,
			right: 0,
			background: {
				color: $mol_style_func.rgba(255, 255, 255, 0.6),
			},
			backdropFilter: $mol_style_func.blur('6px'),
			alignItems: 'center',
			paddingTop: '5rem',
		},

		Finish_title: {
			color: 'black',
			textShadow: '0 0 2px white',
		},

		Finish_moves: {
			color: 'black',
			textShadow: '0 0 2px white',
			margin: {
				top: '1rem',
			},
		},

		Finish_home: {
			margin: {
				top: '1rem',
			},
		},

	} )

}

Финишный экран

Финишный экран

Протестируйте приложение

Давайте напишем тест, чтобы убедиться, что наши экраны меняются правильно. Создать файл app.view.test.ts

namespace $.$$ {
	$mol_test({
		
		"Screan changing"() {
			const app = new $hype_ballsort_app

			// По умолчанию должен показываться стартовый экран
			$mol_assert_like(app.sub(), [app.Start_page()])

			// Кликаем по кнопке старта и проверяем что теперь отображается экран игры
			app.start()
			$mol_assert_like(app.sub(), [app.Game_page()])

			// Выиграем игру, просто установим всем шарам один цвет и проверим экран
			app.game().balls().forEach(obj => obj.color(0))
			$mol_assert_like(app.sub(), [app.Finish_page()])
		},
		
	})
}
Смотрим консоль на упавшие тесты

Смотрим консоль на упавшие тесты

Убедитесь, что тест работает, сломав его, заменив Finish_page на Game_page в последнем утверждении.

Пробные работы

Пробные работы

По любым вопросам вы можете обратиться здесь.

Настоящий оригинал на $hyoo_page

Source

От admin