<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>My Projects Archives : vedmant.com : coding blog</title>
	<atom:link href="https://vedmant.com/category/my-projects/feed/" rel="self" type="application/rss+xml" />
	<link>https://vedmant.com/category/my-projects/</link>
	<description>Sharing my personal experience in web development</description>
	<lastBuildDate>Sun, 06 Sep 2026 04:35:22 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.1</generator>
	<item>
		<title>GainBook – an offline-first strength training tracker built with Expo</title>
		<link>https://vedmant.com/gainbook-offline-first-strength-training-tracker-expo/</link>
					<comments>https://vedmant.com/gainbook-offline-first-strength-training-tracker-expo/#respond</comments>
		
		<dc:creator><![CDATA[vedmant]]></dc:creator>
		<pubDate>Sun, 06 Sep 2026 04:32:43 +0000</pubDate>
				<category><![CDATA[My Projects]]></category>
		<category><![CDATA[React Native]]></category>
		<category><![CDATA[Drizzle ORM]]></category>
		<category><![CDATA[Expo]]></category>
		<category><![CDATA[Fitness]]></category>
		<category><![CDATA[Mobile]]></category>
		<category><![CDATA[SQLite]]></category>
		<guid isPermaLink="false">https://vedmant.com/?p=295</guid>

					<description><![CDATA[<p>I built my own workout tracker after cycling through everything on the stores. GainBook runs entirely on your phone – no account, no cloud, no ads – on Expo SDK 57, SQLite and Drizzle. Here is what it does, and the volume model that took the longest to get right.</p>
<p>The post <a href="https://vedmant.com/gainbook-offline-first-strength-training-tracker-expo/">GainBook – an offline-first strength training tracker built with Expo</a> appeared first on <a href="https://vedmant.com">vedmant.com :: coding blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Install from <a href="https://play.google.com/store/apps/details?id=com.vedware.gainbook" target="_blank" rel="noreferrer noopener">Google Play</a>. The iOS build is currently in TestFlight, with the App Store release coming soon.</p>



<p class="wp-block-paragraph">I have been lifting for years, and over that time I went through most of the workout trackers available in the stores. Every one of them was missing something I needed: the set types I actually use, supersets that stay synchronized, training volume calculated correctly for dumbbells and single-leg exercises, or a rest timer that stays out of the way. Eventually I stopped searching and built my own.</p>



<p class="wp-block-paragraph"><strong>GainBook</strong> is a strength training tracker for iOS and Android. It runs entirely on your phone — no account, no cloud, no ads, and no internet connection required. This post is part announcement and part write-up of the parts that were actually interesting to build.</p>



<h2 class="wp-block-heading">The loop: plan, log, review</h2>



<figure class="wp-block-gallery has-nested-images columns-3 is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1183" height="2560" data-id="288" src="https://vedmant.com/wp-content/uploads/2026/09/gainbook-workout-plans-templates-scaled.jpg" alt="GainBook workout plans screen with Gym Back, Gym Legs and Gym Chest templates" class="wp-image-288" srcset="https://vedmant.com/wp-content/uploads/2026/09/gainbook-workout-plans-templates-scaled.jpg 1183w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-workout-plans-templates-139x300.jpg 139w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-workout-plans-templates-473x1024.jpg 473w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-workout-plans-templates-768x1662.jpg 768w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-workout-plans-templates-710x1536.jpg 710w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-workout-plans-templates-946x2048.jpg 946w" sizes="(max-width: 1183px) 100vw, 1183px" /></figure>



<figure class="wp-block-image size-large"><img decoding="async" width="1183" height="2560" data-id="289" src="https://vedmant.com/wp-content/uploads/2026/09/gainbook-active-workout-superset-rest-timer-scaled.jpg" alt="GainBook active workout screen showing a leg press superset and the rest timer" class="wp-image-289" srcset="https://vedmant.com/wp-content/uploads/2026/09/gainbook-active-workout-superset-rest-timer-scaled.jpg 1183w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-active-workout-superset-rest-timer-139x300.jpg 139w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-active-workout-superset-rest-timer-473x1024.jpg 473w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-active-workout-superset-rest-timer-768x1662.jpg 768w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-active-workout-superset-rest-timer-710x1536.jpg 710w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-active-workout-superset-rest-timer-946x2048.jpg 946w" sizes="(max-width: 1183px) 100vw, 1183px" /></figure>



<figure class="wp-block-image size-large"><img decoding="async" width="1183" height="2560" data-id="293" src="https://vedmant.com/wp-content/uploads/2026/09/gainbook-history-calendar-scaled.jpg" alt="GainBook history screen with a training calendar and session summaries" class="wp-image-293" srcset="https://vedmant.com/wp-content/uploads/2026/09/gainbook-history-calendar-scaled.jpg 1183w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-history-calendar-139x300.jpg 139w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-history-calendar-473x1024.jpg 473w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-history-calendar-768x1662.jpg 768w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-history-calendar-710x1536.jpg 710w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-history-calendar-946x2048.jpg 946w" sizes="(max-width: 1183px) 100vw, 1183px" /></figure>
</figure>



<p class="wp-block-paragraph">Templates are organised into plans and can be scheduled for specific weekdays. Each set has a target weight, reps, rest time and set type — warm-up, working, drop set or failure — while exercises can be grouped into supersets whose sets remain synchronised. Whether you are editing a template or standing in front of the rack, the app shows you what you did the last time you performed that exercise.</p>



<p class="wp-block-paragraph">During a workout, you log reps and weight, add or remove sets on the fly, and the rest timer starts automatically when you complete a set, with sound and a notification if you have left the app. If the equipment you need is taken, you can replace the exercise mid-session and the history records the substitution. A persistent bar on every other screen lets you jump back into an active workout.</p>



<h2 class="wp-block-heading">Volume is the part that took the longest</h2>



<p class="wp-block-paragraph">Most trackers calculate total volume as <code>sets × reps × weight</code> and leave it at that. That number is wrong in three ways that bothered me enough to fix them.</p>



<h3 class="wp-block-heading">1. Your body weight is load</h3>



<p class="wp-block-paragraph">A pull-up with no added weight is not a zero-volume set. But a plank or a glute kickback should not count the same proportion of body weight as a pull-up either. My first attempt derived the percentage from the exercise name, and the results were terrible: it assigned 60–90% to static stretches that move nothing, 70% to a single-leg kickback even though one leg is about 16% of body mass, and 70% to a hyperextension compared with 35% for a sit-up even though both rotate roughly the same mass around the same joint. The result was that three sets of hyperextensions could out-tonnage an entire bench session.</p>



<p class="wp-block-paragraph">So that heuristic is gone. Every exercise now has a reviewed body-weight load percentage, derived from <code>segment mass × lever factor</code> using Winter&#8217;s segment table (whole body 100, above the hip 68, above the knee 85, one leg 16, one arm 5), multiplied by a leverage/range-of-motion factor. The exercise name alone does not tell you how much mass a movement actually moves.</p>



<h3 class="wp-block-heading">2. A set does not train one muscle</h3>



<p class="wp-block-paragraph">A bent-over row is not simply a &#8220;back exercise&#8221; — it is roughly 42% middle back, 32% lats, with the remainder distributed across biceps, shoulders and forearms. GainBook models each exercise as a single distribution across every muscle it works, including the primary muscle, with no primary/secondary split and no cap on any individual share.</p>



<p class="wp-block-paragraph">The important part is that the set&#8217;s volume is <strong>divided</strong> across those muscles, never multiplied. The distribution always adds up to exactly 100, so the volume credited to the muscles equals the volume of the original set. All 892 exercises in the library were reviewed individually based on their own mechanics rather than inherited from a movement family, and each exercise has its own split displayed in the app.</p>



<figure class="wp-block-gallery has-nested-images columns-3 is-cropped wp-block-gallery-2 is-layout-flex wp-block-gallery-is-layout-flex">
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1183" height="2560" data-id="291" src="https://vedmant.com/wp-content/uploads/2026/09/gainbook-volume-calculation-muscle-split-scaled.jpg" alt="GainBook explaining set volume as body weight plus added weight times reps, with the pull-up muscle split" class="wp-image-291" srcset="https://vedmant.com/wp-content/uploads/2026/09/gainbook-volume-calculation-muscle-split-scaled.jpg 1183w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-volume-calculation-muscle-split-139x300.jpg 139w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-volume-calculation-muscle-split-473x1024.jpg 473w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-volume-calculation-muscle-split-768x1662.jpg 768w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-volume-calculation-muscle-split-710x1536.jpg 710w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-volume-calculation-muscle-split-946x2048.jpg 946w" sizes="auto, (max-width: 1183px) 100vw, 1183px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1183" height="2560" data-id="290" src="https://vedmant.com/wp-content/uploads/2026/09/gainbook-muscle-volume-heatmap-scaled.jpg" alt="GainBook muscle volume heatmap with quads, calves, hamstrings and glutes highlighted" class="wp-image-290" srcset="https://vedmant.com/wp-content/uploads/2026/09/gainbook-muscle-volume-heatmap-scaled.jpg 1183w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-muscle-volume-heatmap-139x300.jpg 139w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-muscle-volume-heatmap-473x1024.jpg 473w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-muscle-volume-heatmap-768x1662.jpg 768w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-muscle-volume-heatmap-710x1536.jpg 710w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-muscle-volume-heatmap-946x2048.jpg 946w" sizes="auto, (max-width: 1183px) 100vw, 1183px" /></figure>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1183" height="2560" data-id="292" src="https://vedmant.com/wp-content/uploads/2026/09/gainbook-muscle-volume-trend-scaled.jpg" alt="GainBook per-muscle analytics for Lats with volume, sets, sessions and a trend chart" class="wp-image-292" srcset="https://vedmant.com/wp-content/uploads/2026/09/gainbook-muscle-volume-trend-scaled.jpg 1183w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-muscle-volume-trend-139x300.jpg 139w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-muscle-volume-trend-473x1024.jpg 473w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-muscle-volume-trend-768x1662.jpg 768w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-muscle-volume-trend-710x1536.jpg 710w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-muscle-volume-trend-946x2048.jpg 946w" sizes="auto, (max-width: 1183px) 100vw, 1183px" /></figure>
</figure>



<h3 class="wp-block-heading">3. Muscle groups are not comparable at equal tonnage</h3>



<p class="wp-block-paragraph">A 98 kg bench press and a 230 kg leg press can represent roughly the same effort, so colouring a body map by raw kilograms means the legs are always on fire while the arms barely register. Each muscle group therefore has a strength capacity — how much load it can actually handle, based on intermediate 1RM standards and attributed through the app&#8217;s own distribution — and every heatmap and ranking metric is normalised against it.</p>



<p class="wp-block-paragraph">One thing I got wrong initially was normalising each muscle independently against a &#8220;hard session&#8221; reference. But a full-body workout distributes its volume across ten muscles, so no individual muscle can ever get close to that reference. A real four-exercise template peaked at 0.32, leaving the entire map inside just 27% of the colour range. The result was almost the same hazy map regardless of what you trained. The map was effectively answering &#8220;how does this compare to a maximal session?&#8221; when the useful question is &#8220;where did this workout&#8217;s work go?&#8221;. Now the whole map is resolved together: the shape is stretched so the hardest-worked muscle reaches the top of the range, then dimmed according to the overall magnitude of the session. That way, a warm-up still cannot look like a leg day.</p>



<p class="wp-block-paragraph">Warm-up sets, incidentally, do not count toward training volume at all. A 25-rep bar-only warm-up used to light up the heatmap just like a working set.</p>



<h2 class="wp-block-heading">Everything stays on the device</h2>



<p class="wp-block-paragraph">There is no backend. The entire app is a local SQLite database (<code>expo-sqlite</code>) accessed through <a href="https://orm.drizzle.team/" target="_blank" rel="noreferrer noopener">Drizzle ORM</a>, with schema migrations generated from the TypeScript schema. No account, no sync, no server bill, and nothing to leak.</p>



<p class="wp-block-paragraph">The trade-off is that backups are entirely my problem, so there are three options and they all produce <strong>the same file</strong>: the share-sheet export you can send to yourself, automatic iCloud Drive backup on iOS, and Android Auto Backup. A backup taken from the Files app is byte-identical to an export, so it can always be imported again. Creating a separate private backup format would have meant that the user&#8217;s own copy might no longer be restorable.</p>



<p class="wp-block-paragraph">That file is a zip containing a single <code>gainbook.db</code>. A workout log consists of short, repetitive rows spread across mostly-empty SQLite pages, so it compresses by roughly 8×: a synthetic three-year history of 450 sessions and 10,800 sets went from 672 KB down to 83 KB. Import detects the file from its <em>leading bytes</em> rather than relying on the extension or MIME type, because a file that has passed through a share sheet or two may arrive with whatever filename the last app decided to give it. It also still accepts the uncompressed databases exported before the zip change, since those files are already sitting in people&#8217;s Files apps and there is no migration mechanism that can reach them.</p>



<h2 class="wp-block-heading">The exercise library</h2>


<div class="wp-block-image">
<figure class="aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1183" height="2560" src="https://vedmant.com/wp-content/uploads/2026/09/gainbook-exercise-library-detail-scaled.jpg" alt="GainBook exercise detail for Dumbbell Bench Press with photo, muscle groups and equipment tags" class="wp-image-294" style="width:340px;height:auto" srcset="https://vedmant.com/wp-content/uploads/2026/09/gainbook-exercise-library-detail-scaled.jpg 1183w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-exercise-library-detail-139x300.jpg 139w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-exercise-library-detail-473x1024.jpg 473w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-exercise-library-detail-768x1662.jpg 768w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-exercise-library-detail-710x1536.jpg 710w, https://vedmant.com/wp-content/uploads/2026/09/gainbook-exercise-library-detail-946x2048.jpg 946w" sizes="auto, (max-width: 1183px) 100vw, 1183px" /><figcaption class="wp-element-caption">Exercise detail, including the 2× volume multiplier for dumbbell work.</figcaption></figure>
</div>


<p class="wp-block-paragraph">The bundled library is based on <a href="https://github.com/yuhonas/free-exercise-db" target="_blank" rel="noreferrer noopener">free-exercise-db</a> (public domain) — 892 exercises with instructions, photos, equipment and difficulty — combined with the muscle distribution and body-weight load data described above. You can search by name, muscle group or equipment, add your own exercises, and open any exercise to see its complete history and per-muscle trend. Custom exercises can only be deleted when nothing still references them.</p>



<h2 class="wp-block-heading">Stack</h2>



<ul class="wp-block-list">
<li><a href="https://docs.expo.dev/" target="_blank" rel="noreferrer noopener">Expo SDK 57</a> / React Native 0.86, New Architecture enabled</li>



<li><a href="https://docs.expo.dev/router/introduction/" target="_blank" rel="noreferrer noopener">Expo Router</a> for file-based navigation</li>



<li><code>expo-sqlite</code> + <a href="https://orm.drizzle.team/" target="_blank" rel="noreferrer noopener">Drizzle ORM</a> for local storage and migrations</li>



<li>Reanimated and FlashList for the set-logging screens</li>



<li>HealthKit on iOS — workouts written to Apple Health, live heart rate from Apple Watch or AirPods, per-set max heart rate and active energy</li>



<li>A vendored picker and three small native modules (iCloud backup, Live Activities)</li>



<li><a href="https://maestro.mobile.dev/" target="_blank" rel="noreferrer noopener">Maestro</a> for end-to-end tests on both simulators, plus Jest for the model code</li>



<li>English, Spanish and Russian</li>



<li>OTA updates through <code>expo-updates</code> on fingerprint runtime versions</li>
</ul>



<p class="wp-block-paragraph">That last one probably deserves its own post. With <code>runtimeVersion.policy</code> set to <code>fingerprint</code>, the hash <em>is</em> the runtime version, and anything that changes it can silently strand every binary already in the field. Nothing errors; the update simply never gets offered. In my case, an ESLint-only commit generated a new runtime version because <code>package.json</code> scripts were included in the hash. It is worth knowing about before you ship one.</p>



<h2 class="wp-block-heading">Try it</h2>



<p class="wp-block-paragraph">GainBook is free on <a href="https://play.google.com/store/apps/details?id=com.vedware.gainbook" target="_blank" rel="noreferrer noopener">Google Play</a>, with iOS following shortly. I train with it every week, which is the main reason it keeps evolving — whenever I find something missing, I build it. If you prefer owning your training data instead of storing it on someone else&#8217;s server, that is exactly what GainBook is built for.</p>



<p class="wp-block-paragraph"></p>
<p>The post <a href="https://vedmant.com/gainbook-offline-first-strength-training-tracker-expo/">GainBook – an offline-first strength training tracker built with Expo</a> appeared first on <a href="https://vedmant.com">vedmant.com :: coding blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vedmant.com/gainbook-offline-first-strength-training-tracker-expo/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Running Time &#8211; React Native Sample Application</title>
		<link>https://vedmant.com/running-time-react-native-sample-application/</link>
					<comments>https://vedmant.com/running-time-react-native-sample-application/#comments</comments>
		
		<dc:creator><![CDATA[vedmant]]></dc:creator>
		<pubDate>Sun, 24 Nov 2019 19:23:02 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[My Projects]]></category>
		<category><![CDATA[React Native]]></category>
		<category><![CDATA[Mobile App]]></category>
		<guid isPermaLink="false">https://vedmant.com/?p=276</guid>

					<description><![CDATA[<p>Open sources GitHub. Install App from Play Market. Not so long ago I created a simple running tracker &#8211; Running Time that was build on Laravel and Vue as a tutorial to build Single Page Applications. It turned out to be quite helpful learning app for many people. Now I decided to get to know &#8230; <a href="https://vedmant.com/running-time-react-native-sample-application/" class="more-link">Continue reading <span class="screen-reader-text">Running Time &#8211; React Native Sample Application</span></a></p>
<p>The post <a href="https://vedmant.com/running-time-react-native-sample-application/">Running Time &#8211; React Native Sample Application</a> appeared first on <a href="https://vedmant.com">vedmant.com :: coding blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Open sources <a href="https://github.com/vedmant/running-time-react" target="_blank" rel="noreferrer noopener" aria-label=" (opens in a new tab)">GitHub</a>. Install App from <a href="https://play.google.com/store/apps/details?id=com.vedmant.runningtime" target="_blank" rel="noreferrer noopener" aria-label=" (opens in a new tab)">Play Market</a>.</p>



<p class="wp-block-paragraph">Not so long ago I created a simple running tracker &#8211; <a href="https://github.com/vedmant/running-time">Running Time</a> that was build on Laravel and Vue as a tutorial to build Single Page Applications. It turned out to be quite helpful learning app for many people. Now I decided to get to know React Native a bit more and in the process I created an app that uses that same Laravel API backend.</p>



<p class="wp-block-paragraph">This mobile App is quite simple it has authentication flow with register and login pages. Main screen with three tabs, &#8220;Dashboard&#8221;, &#8220;Entries&#8221; and &#8220;Profile&#8221;. </p>



<p class="wp-block-paragraph">Here is more detailed list of features:</p>



<ul class="wp-block-list"><li>Simple and clean code</li><li>Redux with redux-thunk</li><li>Auth flow: login and registration</li><li>Dashboard tab with panels and charts</li><li>Entries list tab</li><li>Add / edit entry</li><li>Infinite scroll</li><li>Pull to refresh</li><li>Profile tab: update profile</li></ul>



<p class="wp-block-paragraph">The app is free to use and modify in any way and has MIT license.</p>



<p class="wp-block-paragraph">Open sources <a rel="noreferrer noopener" href="https://github.com/vedmant/running-time-react" target="_blank">GitHub</a>. Install App from <a rel="noreferrer noopener" href="https://play.google.com/store/apps/details?id=com.vedmant.runningtime" target="_blank">Play Market</a>.</p>
<p>The post <a href="https://vedmant.com/running-time-react-native-sample-application/">Running Time &#8211; React Native Sample Application</a> appeared first on <a href="https://vedmant.com">vedmant.com :: coding blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vedmant.com/running-time-react-native-sample-application/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Laravel Shortcodes</title>
		<link>https://vedmant.com/laravel-shortcodes/</link>
					<comments>https://vedmant.com/laravel-shortcodes/#comments</comments>
		
		<dc:creator><![CDATA[vedmant]]></dc:creator>
		<pubDate>Tue, 23 Apr 2019 13:41:41 +0000</pubDate>
				<category><![CDATA[Laravel]]></category>
		<category><![CDATA[My Projects]]></category>
		<category><![CDATA[Composer]]></category>
		<category><![CDATA[Package]]></category>
		<category><![CDATA[Shortcodes]]></category>
		<category><![CDATA[Wordpress]]></category>
		<guid isPermaLink="false">https://vedmant.com/?p=241</guid>

					<description><![CDATA[<p>WordPress based Shortcodes for Laravel 5.x with shared variables, debugbar integration, flexible configuration and other useful features. Github: https://github.com/vedmant/laravel-shortcodes﻿ Build powerful and simple layouts using shortcodes in the content or views like this: Installation Via Composer This package supports Laravel Auto-Discover and will be discovered automatically. For Laravel version before 5.5 please add the Vedmant\LaravelShortcodes\LaravelShortcodesServiceProvider::class &#8230; <a href="https://vedmant.com/laravel-shortcodes/" class="more-link">Continue reading <span class="screen-reader-text">Laravel Shortcodes</span></a></p>
<p>The post <a href="https://vedmant.com/laravel-shortcodes/">Laravel Shortcodes</a> appeared first on <a href="https://vedmant.com">vedmant.com :: coding blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">WordPress based Shortcodes for Laravel 5.x with shared variables, debugbar integration, flexible configuration and other useful features.</p>



<p class="wp-block-paragraph">Github: <a href="https://github.com/vedmant/laravel-shortcodes" target="_blank" rel="noreferrer noopener" aria-label=" (opens in a new tab)">https://github.com/vedmant/laravel-shortcodes﻿</a></p>



<p class="wp-block-paragraph">Build powerful and simple layouts using shortcodes in the content or views like this:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: xml; title: ; notranslate">
&#x5B;b]Bold text&#x5B;/b]
&#x5B;row]
  &#x5B;col md=8]
     &#x5B;posts_list types="post,gallery" show_tags="yes"]
  &#x5B;/col]
  &#x5B;col md=4]
     &#x5B;poll id="1"]
     &#x5B;user_info username="test_user" website="mywebsite.com" active="yes"]
     &#x5B;last_free_post title="Free Posts"]
  &#x5B;/col]
&#x5B;/row]
</pre></div>


<h2 class="wp-block-heading"><a href="https://github.com/vedmant/laravel-shortcodes#installation"></a>Installation</h2>



<p class="wp-block-paragraph">Via Composer</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
$ composer require vedmant/laravel-shortcodes
</pre></div>


<p class="wp-block-paragraph">This package supports Laravel Auto-Discover and will be discovered automatically.</p>



<p class="wp-block-paragraph">For Laravel version before 5.5 please add the Vedmant\LaravelShortcodes\LaravelShortcodesServiceProvider::class to the providers array in&nbsp;<code>config/app.php</code>. And optionally &#8216;Shortcodes&#8217; =&gt; Vedmant\LaravelShortcodes\Facades\Shortcodes::class, to aliases.</p>



<h2 class="wp-block-heading"><a href="https://github.com/vedmant/laravel-shortcodes#configuraton"></a>Configuraton</h2>



<p class="wp-block-paragraph">Publish configuration.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
php artisan vendor:publish --tag=shortcodes
</pre></div>


<h2 class="wp-block-heading"><a href="https://github.com/vedmant/laravel-shortcodes#usage"></a>Usage</h2>



<h3 class="wp-block-heading"><a href="https://github.com/vedmant/laravel-shortcodes#shortcode-class"></a>Shortcode class</h3>



<p class="wp-block-paragraph">Shortcode class should extend abstract \Vedmant\LaravelShortcodes\Shortcode class.</p>



<p class="wp-block-paragraph">This packages adds&nbsp;<code>make:shortcode</code>&nbsp;artisan command:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
php artisan make:shortcode PostsListShortcode
</pre></div>


<p class="wp-block-paragraph">It will generate a shortcode class in the&nbsp;<code>app/Shortcodes</code>&nbsp;folder by default.</p>



<h3 class="wp-block-heading"><a href="https://github.com/vedmant/laravel-shortcodes#register-shortcodes"></a>Register shortcodes</h3>



<p class="wp-block-paragraph">You can use AppServiceProvider boot method to register all needed shortcodes.</p>



<p class="wp-block-paragraph">Using shortcode class:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
Shortcodes::add('b', BShortcode::class);
</pre></div>


<p class="wp-block-paragraph">Using shortcode classes in array, preferable for lots of shortcodes:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
Shortcodes::add(&#x5B;
   &#039;a&#039; =&gt; AShortcode::class,
   &#039;b&#039; =&gt; BShortcode::class,
]);
</pre></div>


<p class="wp-block-paragraph">Using closure:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
Shortcodes::add(&#039;test&#039;, function ($atts, $content, $tag, $manager) {
   return new HtmlString(&#039;&lt;strong&gt;some test shortcode&lt;/strong&gt;&#039;);
});

</pre></div>


<h3 class="wp-block-heading"><a href="https://github.com/vedmant/laravel-shortcodes#rendering-shortcodes"></a>Rendering shortcodes</h3>



<p class="wp-block-paragraph">By default this packages extends View to parse all shortcodes during views rendering. This feature can be disabled in the config file.</p>



<p class="wp-block-paragraph">Also to enable / disable rendering shortcodes for specific view you can use:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
view(&#039;some-view&#039;)-&gt;withShortcodes(); // Or view(&#039;some-view&#039;)-&gt;withoutShortcodes();
</pre></div>


<p class="wp-block-paragraph">To render shortcodes manually use:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
{{ Shortcodes::render('&#x5B;b]bold&#x5B;/b]') }}
</pre></div>


<h3 class="wp-block-heading"><a href="https://github.com/vedmant/laravel-shortcodes#shared-attributes"></a>Shared attributes</h3>



<p class="wp-block-paragraph">YOccasionally, you may need to share a piece of data with all shortcodes that are rendered by your application. You may do so using the shortode facade&#8217;s&nbsp;<code>share</code>&nbsp;method. Typically, you should place calls to share in the controller, or within a service provider&#8217;s boot method.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
Shortcodes::share('post', $post);
</pre></div>


<p class="wp-block-paragraph">Then you can get share attributes in the shortcode class:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
$post = $this-&gt;shared(&#039;post&#039;); $allShared = $this-&gt;shared();
</pre></div>


<h3 class="wp-block-heading"><a href="https://github.com/vedmant/laravel-shortcodes#comma-separated-values-array-attributes"></a>Comma separated values (array attributes)</h3>



<p class="wp-block-paragraph">If you need to pass an array to a shortcode, you can pass values separated by comma:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&#x5B;posts_list ids="1,2,3"]
</pre></div>


<p class="wp-block-paragraph">Then in render function you can parse this attribute using build in method:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
$ids = $this-&gt;parseCommaSeparated($atts&#x5B;&#039;ids&#039;]);
</pre></div>


<p class="wp-block-paragraph">Edit configuration file as needed.</p>



<h3 class="wp-block-heading"><a href="https://github.com/vedmant/laravel-shortcodes#integration-with-laravel-debugbar"></a>Integration with Laravel Debugbar</h3>



<p class="wp-block-paragraph">This packages supports Laravel Debugbar. Integration can be disabled in the config file if needed.<br></p>



<p class="wp-block-paragraph">This project is fully free to use for any purpose and licensed under MIT License.</p>
<p>The post <a href="https://vedmant.com/laravel-shortcodes/">Laravel Shortcodes</a> appeared first on <a href="https://vedmant.com">vedmant.com :: coding blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vedmant.com/laravel-shortcodes/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>My Little Bitcoin &#8211; simple cryptocurrency implementation on JavaScript with GUI</title>
		<link>https://vedmant.com/little-bitcoin-simple-cryptocurrency-implementation-javascript-gui/</link>
					<comments>https://vedmant.com/little-bitcoin-simple-cryptocurrency-implementation-javascript-gui/#comments</comments>
		
		<dc:creator><![CDATA[vedmant]]></dc:creator>
		<pubDate>Sun, 01 Oct 2017 20:14:25 +0000</pubDate>
				<category><![CDATA[Cryptocurrency]]></category>
		<category><![CDATA[My Projects]]></category>
		<category><![CDATA[Node.js]]></category>
		<category><![CDATA[Vue.js]]></category>
		<category><![CDATA[vue-router]]></category>
		<category><![CDATA[Vuex]]></category>
		<category><![CDATA[Web Sockets]]></category>
		<guid isPermaLink="false">https://vedmant.com/?p=209</guid>

					<description><![CDATA[<p>I was interested in Bitcoin and Blockchain technologies for a while and in theory things look pretty simple yet so powerful. I really admire genius of Satoshi Nakamoto or whoever invented Blockchain based Crypto Currency and eventually I decided to implement my own simple cryptocurrency to study it better, as for me the best way &#8230; <a href="https://vedmant.com/little-bitcoin-simple-cryptocurrency-implementation-javascript-gui/" class="more-link">Continue reading <span class="screen-reader-text">My Little Bitcoin &#8211; simple cryptocurrency implementation on JavaScript with GUI</span></a></p>
<p>The post <a href="https://vedmant.com/little-bitcoin-simple-cryptocurrency-implementation-javascript-gui/">My Little Bitcoin &#8211; simple cryptocurrency implementation on JavaScript with GUI</a> appeared first on <a href="https://vedmant.com">vedmant.com :: coding blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I was interested in Bitcoin and Blockchain technologies for a while and in theory things look pretty simple yet so powerful. I really admire genius of Satoshi Nakamoto or whoever invented Blockchain based Crypto Currency and eventually I decided to implement my own simple cryptocurrency to study it better, as for me the best way to learn is to do it myself.</p>



<p class="wp-block-paragraph">And the result is <strong>My Little Bitcoin</strong> &#8211; a simple cryptocurrency implementation on JavaScript in just about 650 lines of code (without comments and client). It also includes WEB GUI written on Vue.js where you can send coins and explore blockchain.</p>



<h3 class="wp-block-heading">The structure</h3>



<p class="wp-block-paragraph">The project is based on Node.js and has following basic structure:</p>



<ol class="wp-block-list"><li>Library &#8211; consist of functions to help handle crypto currency in a simplest way</li><li>Store &#8211; this in-memory storage for blockchain, wallets, mempool and few other things</li><li>Miner &#8211; this a worker that adds new blocks to the chain</li><li>Peers &#8211; simple peer-to-peer blockchain synchronization implementation</li><li>Server &#8211; web server that serves data for our front end GUI, includes API and web sockets</li></ol>



<h3 class="wp-block-heading">The chain</h3>



<p class="wp-block-paragraph">The structure of the chain is the simplest possible.</p>



<p class="wp-block-paragraph">Block structure is following:</p>


<pre class="brush: jscript; title: ; notranslate">
{
  index, // Block index
  prevHash, // Hash of the previous block
  time, // Current block timestamp
  transactions, // List of transactions, included into the block
  nonce, // Nonce, required for proof of work protocol
  hash, // Current block hash
}
</pre>



<p class="wp-block-paragraph">Transaction structure is following:</p>


<pre class="brush: jscript; title: ; notranslate">
{
  id, // Transaction unique id
  time, // Transaction timestamp
  hash, // Transaction hash
  reward, // Boolean to mark mining reward transaction
  inputs, // List of inputs in the transaction
  outputs, // List of outputs in transaction
  address, // Transaction is limited to only one input address for simplicity
  hash, // Transaction hash
  signature, // Transaction hash signature
}
</pre>



<p class="wp-block-paragraph">And following inputs and outputs structure:</p>


<pre class="brush: jscript; title: ; notranslate">
// Input
{
  tx, // Points to transaction of referenced output
  index, // Index of the output in the referenced transaction
  amount, // Amount of the referenced output
  address, // Address of the referenced output and also public key
  signature, // Signature, signed by private key and can be verified by included public key
}
// Output
{
  index, // Output index in current transaction
  amount, // Amount of the output
  address, // Address of the wallet (public key)
}
</pre>



<p class="wp-block-paragraph">For demo purpose I created special mode that disables peer-to-peer module, reduces proof of work difficulty and adds one minute block timeout.</p>


<div class="carousel-slider-outer carousel-slider-outer-image-carousel carousel-slider-outer-217" style="--carousel-slider-nav-color:#f1f1f1;--carousel-slider-active-nav-color:#4caf50;--carousel-slider-arrow-size:48px;--carousel-slider-bullet-size:10px">
<div id="&#039;id-217" class="carousel-slider carousel-slider-217 arrows-visibility-always dots-visibility-never arrows-outside dots-center dots-circle owl-carousel" data-slide-type="image-carousel" data-owl-settings='{"nav":true,"dots":false,"slideBy":1,"stagePadding":0,"margin":10,"loop":true,"lazyLoad":true,"autoplay":true,"autoplayTimeout":5000,"autoplaySpeed":500,"autoplayHoverPause":false,"autoWidth":false,"responsive":{"300":{"items":1},"576":{"items":1},"768":{"items":1},"1024":{"items":1},"1280":{"items":1},"1536":{"items":1}}}'>
<div class="carousel-slider__item">
	<img class="owl-lazy" data-src="https://vedmant.com/wp-content/uploads/2017/10/1.jpg" alt=""></a></div>

<div class="carousel-slider__item">
	<img class="owl-lazy" data-src="https://vedmant.com/wp-content/uploads/2017/10/2.jpg" alt=""></a></div>

<div class="carousel-slider__item">
	<img class="owl-lazy" data-src="https://vedmant.com/wp-content/uploads/2017/10/3.jpg" alt=""></a></div>

</div><!-- .carousel-slider-217 -->
</div><!-- .carousel-slider-outer-217 -->




<p class="wp-block-paragraph"><a href="https://my-little-bitcoin.vedmant.com/" target="_blank" rel="noopener">Demo</a></p>



<p class="wp-block-paragraph">Check sources here: <a href="https://github.com/vedmant/my-little-bitcoin" target="_blank" rel="noopener">GitHub Link</a></p>



<p class="wp-block-paragraph">This implementation is pretty naive and suitable only for studying purpose.</p>



<p class="wp-block-paragraph">This project is fully free to use for any purpose and licensed under MIT License.</p>
<p>The post <a href="https://vedmant.com/little-bitcoin-simple-cryptocurrency-implementation-javascript-gui/">My Little Bitcoin &#8211; simple cryptocurrency implementation on JavaScript with GUI</a> appeared first on <a href="https://vedmant.com">vedmant.com :: coding blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vedmant.com/little-bitcoin-simple-cryptocurrency-implementation-javascript-gui/feed/</wfw:commentRss>
			<slash:comments>5</slash:comments>
		
		
			</item>
		<item>
		<title>Sample Single Page Application (SPA) using Laravel 5 &#038; Vue2 + Vuex + Vue-Router</title>
		<link>https://vedmant.com/sample-single-page-application-spa-using-laravel-5-vue2-vuex-vue-router/</link>
					<comments>https://vedmant.com/sample-single-page-application-spa-using-laravel-5-vue2-vuex-vue-router/#comments</comments>
		
		<dc:creator><![CDATA[vedmant]]></dc:creator>
		<pubDate>Sat, 19 Aug 2017 18:04:16 +0000</pubDate>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[My Projects]]></category>
		<category><![CDATA[Vue.js]]></category>
		<category><![CDATA[E2E tests]]></category>
		<category><![CDATA[phpunit]]></category>
		<category><![CDATA[REST API]]></category>
		<category><![CDATA[SPA]]></category>
		<category><![CDATA[vue-router]]></category>
		<category><![CDATA[Vuex]]></category>
		<guid isPermaLink="false">https://vedmant.com/?p=180</guid>

					<description><![CDATA[<p>Not to long ago I implemented a sample Single Page Application using Laravel 5 and Vue2 + Vuex + Vue-Router. Today I decided to make it public and share my experience with others. The project is basically a simple Running Tracker, where you can add your running entries and see your performance during some period &#8230; <a href="https://vedmant.com/sample-single-page-application-spa-using-laravel-5-vue2-vuex-vue-router/" class="more-link">Continue reading <span class="screen-reader-text">Sample Single Page Application (SPA) using Laravel 5 &#038; Vue2 + Vuex + Vue-Router</span></a></p>
<p>The post <a href="https://vedmant.com/sample-single-page-application-spa-using-laravel-5-vue2-vuex-vue-router/">Sample Single Page Application (SPA) using Laravel 5 &#038; Vue2 + Vuex + Vue-Router</a> appeared first on <a href="https://vedmant.com">vedmant.com :: coding blog</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Not to long ago I implemented a sample Single Page Application using Laravel 5 and Vue2 + Vuex + Vue-Router.</p>
<p>Today I decided to make it public and share my experience with others.</p>
<p>The project is basically a simple Running Tracker, where you can add your running entries and see your performance during some period of time.</p>
<h3>Main features</h3>
<ul>
<li>Fully separate Backend and Frontend</li>
<li>Authentication based on Laravel Passport</li>
<li>List pages with filters and CRUD editing</li>
<li>Admin panel</li>
<li>Simple widgets</li>
<li>Simple reports</li>
<li>Full Phpunit test coverage</li>
<li>Sample E2E tests using Nightwatch and Cypress</li>
</ul>
<h3>Includes</h3>
<ul>
<li><a href="https://laravel.com/docs/5.4/passport">Laravel Passport</a> API Authentication</li>
<li><a href="https://github.com/mpociot/laravel-apidoc-generator">API Docs Gerator</a> Laravel API Documentation Generator</li>
<li><a href="https://github.com/barryvdh/laravel-debugbar">Laravel DebugBar</a> Debug bar for Laravel</li>
<li><a href="https://vuejs.org/">Vue.js</a> The Progressive JavaScript Framework</li>
<li><a href="https://vuex.vuejs.org/en/intro.html">Vuex</a> State management pattern + library for Vue.js</li>
<li><a href="https://router.vuejs.org/en/">Vue-Router</a> Router library for Vue.js</li>
</ul>
<h3>Other Features</h3>
<ul>
<li>Front page</li>
<li>Authentication (registration, login, logout, throttle)</li>
<li>Users roles: administrator (all access), manager (manage records)</li>
<li>User dashborad with widgets and charts</li>
<li>Entries list with filter by date (list, show, edit, delete, create)</li>
<li>Report page with chart</li>
<li>User profile page</li>
<li>Admin dashboard with widgets</li>
<li>Users admin (list, show, edit, delete, create)</li>
<li>Entries admin (list, show, edit, delete, create)</li>
<li>Global loader for all requests with small delay</li>
</ul>
<p><div class="carousel-slider-outer carousel-slider-outer-image-carousel carousel-slider-outer-191" style="--carousel-slider-nav-color:#f1f1f1;--carousel-slider-active-nav-color:#4caf50;--carousel-slider-arrow-size:48px;--carousel-slider-bullet-size:10px">
<div id="&#039;id-191" class="carousel-slider carousel-slider-191 arrows-visibility-always dots-visibility-never arrows-outside dots-center dots-circle owl-carousel" data-slide-type="image-carousel" data-owl-settings='{"nav":true,"dots":false,"slideBy":1,"stagePadding":0,"margin":10,"loop":true,"lazyLoad":true,"autoplay":true,"autoplayTimeout":10000,"autoplaySpeed":500,"autoplayHoverPause":true,"autoWidth":false,"responsive":{"300":{"items":1},"576":{"items":1},"768":{"items":1},"1024":{"items":1},"1280":{"items":1},"1536":{"items":1}}}'>
<div class="carousel-slider__item">
	<img class="owl-lazy" data-src="https://vedmant.com/wp-content/uploads/2017/08/2017-08-19_1712.jpg" alt=""></a></div>

<div class="carousel-slider__item">
	<img class="owl-lazy" data-src="https://vedmant.com/wp-content/uploads/2017/08/2017-08-19_1713.jpg" alt=""></a></div>

<div class="carousel-slider__item">
	<img class="owl-lazy" data-src="https://vedmant.com/wp-content/uploads/2017/08/2017-08-19_1713.png" alt=""></a></div>

<div class="carousel-slider__item">
	<img class="owl-lazy" data-src="https://vedmant.com/wp-content/uploads/2017/08/2017-08-19_1714.jpg" alt=""></a></div>

</div><!-- .carousel-slider-191 -->
</div><!-- .carousel-slider-outer-191 -->
</p>
<p></p>
<p><a href="https://github.com/vedmant/running-time">GitHub Link</a></p>
<p><a href="https://running-time.vedmant.com/">Demo</a></p>
<p>Use login: <code>user@gmail.com</code> and password: <code>123456</code></p>
<p>This project is fully free to use for any purpose and licenced under MIT License.</p>
<p>The post <a href="https://vedmant.com/sample-single-page-application-spa-using-laravel-5-vue2-vuex-vue-router/">Sample Single Page Application (SPA) using Laravel 5 &#038; Vue2 + Vuex + Vue-Router</a> appeared first on <a href="https://vedmant.com">vedmant.com :: coding blog</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vedmant.com/sample-single-page-application-spa-using-laravel-5-vue2-vuex-vue-router/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
	</channel>
</rss>
