Skip to content

koplenov/habr-notes

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 

Repository files navigation

Простенькие заметки на $mol

картинка для привлечения внимания. чорт. надеюсь никто не читает альты..

Здравствуйте, меня не зовут Дмитрий Карловский и я.. решил написать простенькие заметки на $mol в несколько итераций:

  1. Настраиваемся
  2. Возводим скелет
  3. Сохраняемся
  4. Шаримся
  5. Пакуемся

парой команд - это делается один раз под все проекты:

git clone https://github.com/hyoo-ru/mam.git
cd mam
npm install

Запускаем дев сервер:

npm start

Он заиграет на 9080 порту http://127.0.0.1:9080, а нам можно начинать смолить..

Возводим скелет

Создаём наш проект: в склонированной папке mam создаем папки habr/notes В нём создём точку входа habr/notes/index.html:

<!doctype html>
<html mol_view_root>
	<head>
		<meta charset="utf-8" />
		<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1">
	</head>
	<body mol_view_root>
		<div mol_view_root="$habr_notes"></div>
		<script src="web.js" charset="utf-8"></script>
	</body>
</html>

Заметили $habr_notes? Тут везде fqn обращения (имя = путь), а в mol_view_root мы указываем наше приложение. Точнее, компонент - здесь это одно и то же по смыслу, только мы можем вкладывать компоненты друг в друга и делегировать/рекомпозировать/хакать их свойства между собой.

Что же, создадим сам компонент habr/notes/view.tree:

- это комментарий, ах да, следим за табами
$habr_notes $mol_page

Шпаргалка по синтаксису и страшная статья о view.tree

В браузере можем перейти по адресу http://127.0.0.1:9080/habr/notes и увидим зачаток нашего приложение:

гифка

Придадим форму, подправив файл view.tree:

- мы отнаследовали $habr_notes от $mol_page
$habr_notes $mol_page
	- в свойство body мы положили массив /
	body /
		- в этот массив мы вложили компонент $mol_textarea и назвали его Input
		<= Input $mol_textarea

О, теперь у нас появилось текстовое поле ввода:

гифка

Но наш введенный текст теряется при обновлении страницы, давайте это изменим.

Сохраняемся..

в localStorage

Подправим наш view.tree файл до такого содержания:

$habr_notes $mol_page
	body /
		<= Input $mol_textarea
			- переопределяем наше свойство value
			value?val <=> text?val \

подробнее про свойства компонента $mol_textarea туть

Собственно на этом момент можно уже начать задаваться вопросом какого черта тут происходит и зачем нужны эти view.tree файлы.

view.tree - это DSL, транслирующийся в ts.

Пример выше преобразится в такой код:

namespace $ {
	export class $habr_notes extends $mol_page {
		
		/**
		 * ```tree
		 * body / <= input
		 * ```
		 */
		body() {
			return [
				this.input()
			] as readonly any[]
		}
		
		/**
		 * ```tree
		 * text?val \
		 * ```
		 */
		@ $mol_mem
		text(val?: any) {
			if ( val !== undefined ) return val as never
			return ""
		}
		
		/**
		 * ```tree
		 * Input $mol_textarea value?val <=> text?val
		 * ```
		 */
		@ $mol_mem
		Input() {
			const obj = new this.$.$mol_textarea()
			
			obj.value = (val?: any) => this.text(val)
			
			return obj
		}
	}
	
}

Вы можете сами поиграться в песочнице.

Зачем он нужен? Для разделения мух и котлет.

С помощью view.tree мы декларативно описываем наш интерфейс. С помощью view.tree.ts мы императивно описываем работу самой логики.

Из view.tree сборщик сгенерировал шаблонный код в файл habr/notes/-view.tree/view.tree.ts При обновлении view.tree файла, файл выше обновляется сам.

Зачем он нужен? Для переопределения!

Можем заметить, что код выше сгенерировался в неймспейсе $. Свою логику мы будем описывать в неймспейсе $.$$ - то есть, "перекрывая" своей логикой.

Вернёмся же к нашему коду. Создаём файл habr/notes/view.tree.ts:

namespace $.$$ {
	export class $habr_notes extends $.$habr_notes {
		@ $mol_mem
		text(val?: any) {
			if ( val !== undefined ) return val as never
			return ""
		}
	}
}

Тут я перенёс text(val?: any) - функция-заглушка, сгенерированная из view.tree файла с навешенным декоратором @ $mol_mem (от memoization)

Это канал - он возвращает значение, при вызове его без параметра, а при вызове с параметром он указывается в качестве значения.

Почему оно работает? Мы открыли наше приложение, поле ввода запросило значение из функции text, функция text вернуло пустую строку. Мы ввели первый символ, в функцию text передалась нажатая клавиша, функция text сохранила её. Мы вводим последующие символы, они запоминаются и результат функции text возвращается в поле ввода.

Ага, значит сюда и можно подвязать сохранение данных в localStorage.

В $mol есть модуль $mol_state_local - реактивная обертка над localStorage - ей и воспользуемся:

namespace $.$$ {
	export class $habr_notes extends $.$habr_notes {
		@ $mol_mem
		text(val?: any) {
			return $mol_state_local.value('note', val) || ""
		}
	}
}

Проверяем.. работает! После перезагрузки страницы наш введённый текст сохраняется.

гифка

Я создал репозиторий с веткой stage-1, действия выше воспроизведены в нём - можно сравниться.

Что же, осталось научиться шариться данными!

собственно,

Шаримся

заметками, используя децентрализованную криптографическую систему, ну а почему нет ¯\(ツ)

Поправим view.tree файл:

$habr_notes $mol_page
	- через синк клиент мы обмениваемся данными в сети
	yard $hyoo_sync_client
		peer <= Peer null
	tools /
		- через модуль онлайна мы подключаемся к пирам и синхронизируемся
		<= Online $hyoo_sync_online
			yard <= yard
	body /
		<= Input $mol_textarea
			value?val <=> text?val \
			enabled <= i_have_can_mod false

Опишем логику view.tree.ts:

namespace $.$$ {
	export class $habr_notes extends $.$habr_notes {
		@$mol_mem
		text( val?: any ) {
			return this.store().str( val ) || ""
		}

		@$mol_mem
		store() {
			// через модуль клиента мы обращаемся к хранилищу (миру),
			// используем тип $hyoo_crowd_reg - он позволяет атомарно хранить значения (строки, числа, булы)
			// запрашиваем участок с указанным id
			return this.yard().world().Fund( $hyoo_crowd_reg ).Item( this.current_note_id() )
		}

		@$mol_mem
		current_note_id() {
			// мы считываем id заметки из урла, или, если пустой, указываем новый свой
			const id = this.$.$mol_state_arg.value( '' ) || this.yard().land_grab().id()
			// задаём в урл текущий id - чтобы мы могли его сразу же скопировать
			this.$.$mol_state_arg.value( '', id )
			return id as $mol_int62_string
		}

		@$mol_mem
		i_have_can_mod() {
			// проверка наличия прав на редактирование
			return this.yard().land( this.current_note_id() ).allowed_mod()
		}
	}
}

Вот как это выглядит: ля, работает

Для сверки, ветка stage-2

А может вам рюшечки?

Добавим поддержку тем тройкой строк кода:

$habr_notes $mol_page
	plugins /
		- включаем поддержку смены тем
		<= Theme $mol_theme_auto
	yard $hyoo_sync_client
	tools /
		<= Online $hyoo_sync_online
			yard <= yard
		- добавляем кнопку-переключалку
		<= Lighter $mol_lights_toggle
	body /
		<= Input $mol_textarea
			value?val <=> text?val \
			enabled <= i_have_can_mod false

Вот так это выглядит:

Или ехать?

А может сделаем наше pwa offline-first? Пфф: создаем в той же директории файл view.meta.tree:

include \/mol/offline/install

Одной строчкой мы подключили Service Worker, который закеширует наше приложение и позволит работать ему при отсутствии интернетов. Зачем? CROWD, который мы используем, автоматически синхронизируется с внешним миром при потери и появлении интернета.

Для сверки, ветка stage-3

Пакуемся

мы командой:

npm start habr/notes

Наш статический бандл расположится в папке habr/notes/-/ - его и можно хостить.

В ходе всех вышеописанных шагов можно заметить появившиеся папки:

  • -/ - наш бандл
  • -view.tree/ - наш переопределяемый код

Тут продуманно, что весь генерируемый код с которым мы не взаимодействуем лежит в минусах, это сделано для упрощения работы с тем же гитом. Например, файл .gitignore будет таков:

-*

Отвлеклись, задеплоимся на какой-нибдь фапхаб с возможностью хостить статические странички - тот же Github Pages.

Выгрузим содержимое папки - в ветку gh-pages и можем лицезреть результаты наших работ по ссылке: https://koplenov.github.io/habr-notes/#!=sxktck_j3e02v

Схожее по теме:

Ссылка на доку туть, а мы обитаем туть..