Skip to content

Commit

Permalink
Update Blazor template post
Browse files Browse the repository at this point in the history
  • Loading branch information
mythz committed Nov 21, 2023
1 parent f2f5288 commit 6969c57
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 85 deletions.
4 changes: 2 additions & 2 deletions MyApp/_posts/2023-11-20_net8-best-blazor.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ and submitting forms to Logout users:

Effectively adding interactivity to Blazor static rendered pages with client-side JavaScript to avoid paying Blazor's Interactivity tax.

#### Avoiding Interactivity for Chrome elements
#### Avoid using Interactivity in LayoutsAvoiding Interactivity for Chrome elements

This is especially important for any features you want to add to the Websites Layout or Chrome UI which you'll always want to be
statically rendered so landing pages can load fast and render SEO-friendly server rendered content.
Expand Down Expand Up @@ -439,7 +439,7 @@ to use Blazor end-to-end for all App functionality, which uses Blazor Server and
<img src="https://raw.githubusercontent.com/ServiceStack/Assets/master/csharp-templates/blazor.png" alt=""></a>
</div>
Whilst Blazor Interactivity may remain the predominant solution amongst .NET developers we believe .NET 8 Blazor opens the doors,
Whilst Blazor Interactivity may remain the predominant solution amongst .NET developers we believe .NET 8 Blazor opens the doors
for progressively enhanced statically-rendered Blazor Apps which has now become our preferred solution for developing
most .NET Web Apps.
Expand Down
26 changes: 19 additions & 7 deletions MyApp/_posts/2023-11-20_net8-blazor-template.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,28 @@ Linux Host via SSH and Docker compose.
We’ll also discuss the project's structure, usage of **ASP.NET Core Identity** for Authorization and utilizing
**ServiceStack Blazor Components** for data handling, all integrated to maximize developer efficiency in building Web Applications.

<div class="flex justify-center">
<div class="not-prose mt-16 flex flex-col items-center">
<div class="flex">
<svg class="w-28 h-28 text-purple-500" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M23.834 8.101a13.912 13.912 0 0 1-13.643 11.72a10.105 10.105 0 0 1-1.994-.12a6.111 6.111 0 0 1-5.082-5.761a5.934 5.934 0 0 1 11.867-.084c.025.983-.401 1.846-1.277 1.871c-.936 0-1.374-.668-1.374-1.567v-2.5a1.531 1.531 0 0 0-1.52-1.533H8.715a3.648 3.648 0 1 0 2.695 6.08l.073-.11l.074.121a2.58 2.58 0 0 0 2.2 1.048a2.909 2.909 0 0 0 2.695-3.04a7.912 7.912 0 0 0-.217-1.933a7.404 7.404 0 0 0-14.64 1.603a7.497 7.497 0 0 0 7.308 7.405s.549.05 1.167.035a15.803 15.803 0 0 0 8.475-2.528c.036-.025.072.025.048.061a12.44 12.44 0 0 1-9.69 3.963a8.744 8.744 0 0 1-8.9-8.972a9.049 9.049 0 0 1 3.635-7.247a8.863 8.863 0 0 1 5.229-1.726h2.813a7.915 7.915 0 0 0 5.839-2.578a.11.11 0 0 1 .059-.034a.112.112 0 0 1 .12.053a.113.113 0 0 1 .015.067a7.934 7.934 0 0 1-1.227 3.549a.107.107 0 0 0-.014.06a.11.11 0 0 0 .073.095a.109.109 0 0 0 .062.004a8.505 8.505 0 0 0 5.913-4.876a.155.155 0 0 1 .055-.053a.15.15 0 0 1 .147 0a.153.153 0 0 1 .054.053A10.779 10.779 0 0 1 23.834 8.1zM8.895 11.628a2.188 2.188 0 1 0 2.188 2.188v-2.042a.158.158 0 0 0-.15-.15Z"></path></svg>
</div>
</div>
<div class="not-prose mt-4 px-4 sm:px-6">
<div class="text-center"><h3 id="blazor-template" class="text-4xl sm:text-5xl md:text-6xl tracking-tight font-extrabold text-gray-900">
Blazor Tailwind Template
</h3></div>
<div class="py-8 max-w-7xl mx-auto px-4 sm:px-6">
<lite-youtube class="w-full mx-4 my-4" width="560" height="315" videoid="hqyozHSL0Nk" style="background-image: url('https://img.youtube.com/vi/hqyozHSL0Nk/maxresdefault.jpg')"></lite-youtube>
</div>
</div>

:::{.text-center}
## Create a new ServiceStack Blazor App
:::

<div class="not-prose flex justify-center">
<project-template template="blazor"></project-template>
<div class="not-prose relative bg-white dark:bg-black py-4">
<div class="mx-auto max-w-md px-4 text-center sm:max-w-3xl sm:px-6 lg:max-w-7xl lg:px-8">
<p class="mt-2 text-3xl font-extrabold tracking-tight text-gray-900 dark:text-gray-50 sm:text-4xl">Create a new Blazor Tailwind App</p>
<p class="mx-auto mt-5 max-w-prose text-xl text-gray-500">
Create a new Blazor Tailwind project with your preferred project name:
</p>
</div>
<blazor-template repo="NetCoreTemplates/blazor" name="Blazor"></blazor-template>
</div>

## ASP.NET Core Identity Integration
Expand Down
6 changes: 6 additions & 0 deletions MyApp/wwwroot/posts/components/Icons.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
ServiceStack: '<svg class="w-12 h-12 text-indigo-600" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path fill="currentColor" d="M10 6c1.544 1.76 2.276 4.15 2.217 6.61c3.968 1.67 9.924 6.12 11.181 12.39H28C26.051 14.31 14.918 6.77 10 6zm-2 7c4.67 4.913.81 11.582-4 12h18.97C21.5 18.289 11.95 13.533 8 13z"></path></svg>',
Blazor: '<svg class="w-12 h-12 text-purple-500" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M23.834 8.101a13.912 13.912 0 0 1-13.643 11.72a10.105 10.105 0 0 1-1.994-.12a6.111 6.111 0 0 1-5.082-5.761a5.934 5.934 0 0 1 11.867-.084c.025.983-.401 1.846-1.277 1.871c-.936 0-1.374-.668-1.374-1.567v-2.5a1.531 1.531 0 0 0-1.52-1.533H8.715a3.648 3.648 0 1 0 2.695 6.08l.073-.11l.074.121a2.58 2.58 0 0 0 2.2 1.048a2.909 2.909 0 0 0 2.695-3.04a7.912 7.912 0 0 0-.217-1.933a7.404 7.404 0 0 0-14.64 1.603a7.497 7.497 0 0 0 7.308 7.405s.549.05 1.167.035a15.803 15.803 0 0 0 8.475-2.528c.036-.025.072.025.048.061a12.44 12.44 0 0 1-9.69 3.963a8.744 8.744 0 0 1-8.9-8.972a9.049 9.049 0 0 1 3.635-7.247a8.863 8.863 0 0 1 5.229-1.726h2.813a7.915 7.915 0 0 0 5.839-2.578a.11.11 0 0 1 .059-.034a.112.112 0 0 1 .12.053a.113.113 0 0 1 .015.067a7.934 7.934 0 0 1-1.227 3.549a.107.107 0 0 0-.014.06a.11.11 0 0 0 .073.095a.109.109 0 0 0 .062.004a8.505 8.505 0 0 0 5.913-4.876a.155.155 0 0 1 .055-.053a.15.15 0 0 1 .147 0a.153.153 0 0 1 .054.053A10.779 10.779 0 0 1 23.834 8.1zM8.895 11.628a2.188 2.188 0 1 0 2.188 2.188v-2.042a.158.158 0 0 0-.15-.15Z"/></svg>',
Razor: '<svg class="w-12 h-12 text-indigo-600" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 32 32"><path fill="currentColor" d="M23.844 27.692a16.332 16.332 0 0 1-6.645 1.3q-6.364 0-10.013-3.243a11.3 11.3 0 0 1-3.649-8.9a13.716 13.716 0 0 1 3.785-9.898A12.716 12.716 0 0 1 16.9 3.008a11.676 11.676 0 0 1 8.425 3.006a9.994 9.994 0 0 1 3.142 7.533a10.187 10.187 0 0 1-2.318 7.114a7.532 7.532 0 0 1-5.817 2.547a2.613 2.613 0 0 1-1.845-.642a2.323 2.323 0 0 1-.764-1.6a4.9 4.9 0 0 1-4.148 2.243a4.6 4.6 0 0 1-3.507-1.479a5.706 5.706 0 0 1-1.384-4.063a9.913 9.913 0 0 1 2.2-6.357q2.2-2.763 4.8-2.763a5.063 5.063 0 0 1 4.256 1.716l.311-1.338h2.405l-2.081 9.08a10.716 10.716 0 0 0-.352 2.243q0 .972.744.972a4.819 4.819 0 0 0 3.877-2.047a8.93 8.93 0 0 0 1.621-5.681a7.98 7.98 0 0 0-2.675-6.175a9.887 9.887 0 0 0-6.919-2.432a10.6 10.6 0 0 0-8.158 3.467a12.066 12.066 0 0 0-3.2 8.495a9.561 9.561 0 0 0 3.06 7.573q3.06 2.7 8.586 2.7a13.757 13.757 0 0 0 5.675-1.054ZM19.466 12.25a3.977 3.977 0 0 0-3.6-1.716q-1.824 0-3.263 2.23a8.726 8.726 0 0 0-1.439 4.824q0 3.635 2.905 3.635a3.771 3.771 0 0 0 2.651-1.183a6.309 6.309 0 0 0 1.7-3.2Z"></path></svg>',
Windows: '<svg class="w-12 h-12 text-indigo-600" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M11.5 3v8.5H3V3h8.5zm0 18H3v-8.5h8.5V21zm1-18H21v8.5h-8.5V3zm8.5 9.5V21h-8.5v-8.5H21z"></path></svg>',
}
79 changes: 79 additions & 0 deletions MyApp/wwwroot/posts/components/Templates.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { ref, computed } from 'vue'
import Icons from './Icons.mjs'

export function template(repo, name, icon, tags, demo) {
return { repo, name, icon, tags: tags ?? [], demo: demo ?? `${repo}.web-templates.io` }
}

export const Index = [
template('blazor', 'Blazor', 'Blazor', ['tailwind']),
template('blazor-vue', 'Blazor Vue', 'Blazor',['tailwind']),
template('mvc', 'MVC', 'Windows',['tailwind']),
template('razor', 'Razor Pages', 'Razor',['tailwind']),
template('mvc-bootstrap', 'MVC', 'Windows',['bootstrap']),
template('razor-bootstrap', 'Razor Pages', 'Razor',['bootstrap']),
template('razor-pages', 'Razor Pages', 'Razor',['bootstrap']),
].reduce((acc, template) => { acc[template.repo] = template; return acc}, {})

console.log('Index', Index)

export default {
template:`<div>
<section class="w-full flex flex-col justify-center text-center">
<div id="empty" class="mt-4 mb-2">
<div class="flex justify-center mb-8">
<div class="w-70">
<input v-model="project" type="text" placeholder="Project Name" autocorrect="off" spellcheck="false" @keypress="isAlphaNumeric"
class="mt-1 text-lg block w-full px-3 py-2 bg-white dark:bg-black border border-slate-300 dark:border-slate-700 rounded-md text-sm shadow-sm placeholder-slate-400
focus:outline-none focus:border-sky-500 focus:ring-1 focus:ring-sky-500">
</div>
</div>
</div>
</section>
<section :class="['w-full flex grid gap-4 text-center', templates.length === 1 ? 'grid-cols-1' : templates.length === 2 ? 'grid-cols-2' : 'grid-cols-3']">
<div v-for="template in templates" class="mb-2">
<div class="flex justify-center text-center">
<a class="archive-url hover:no-underline" :href="zipUrl('NetCoreTemplates/' + template.repo)">
<div class="bg-white dark:bg-gray-800 px-4 py-4 mr-4 mb-4 rounded-lg shadow-lg text-center items-center justify-center hover:shadow-2xl dark:border-2 dark:border-pink-600 dark:hover:border-blue-600 dark:border-2 dark:border-pink-600 dark:hover:border-blue-600" style="min-width:150px">
<div class="text-center font-extrabold flex items-center justify-center mb-2">
<div class="text-4xl text-blue-400 my-3" v-html="svgIcon(template.icon)">
</div>
</div>
<div class="text-xl font-medium text-gray-700">{{ template.name }}</div>
<div class="flex justify-center h-8">
<div v-for="tag in template.tags" class="mr-1">
<span class="px-2 h-8 rounded-lg bg-blue-50 dark:bg-blue-900 text-blue-500 dark:text-blue-400 text-sm">{{tag}}</span>
</div>
</div>
<span class="archive-name px-4 pb-2 text-blue-600 dark:text-indigo-400">{{ projectZip }}</span>
<div class="count mt-1 text-gray-400 text-sm"></div>
</div>
</a>
</div>
<a v-if="template.demo && hide !== 'demo'" :href="'https://' + template.demo">{{template.demo}}</a>
</div>
</section>
</div>`,
props: { templates: Array, hide:String },
setup(props) {

const project = ref('MyApp')
const projectZip = computed(() => (project.value || 'MyApp') + '.zip')

/** @param {string} template */
const zipUrl = (template) =>
`https://account.servicestack.net/archive/${template}?Name=${project.value || 'MyApp'}`

/** @param {KeyboardEvent} e */
const isAlphaNumeric = (e) => {
const c = e.charCode;
if (c >= 65 && c <= 90 || c >= 97 && c <= 122 || c >= 48 && c <= 57 || c === 95) //A-Za-z0-9_
return;
e.preventDefault()
}

const svgIcon = (icon) => Icons[icon] ?? Icons.ServiceStack

return { project, projectZip, zipUrl, isAlphaNumeric, svgIcon, }
}
}
106 changes: 30 additions & 76 deletions MyApp/wwwroot/posts/net8-blazor-template.mjs
Original file line number Diff line number Diff line change
@@ -1,84 +1,38 @@
import { ref, computed } from "vue"
import ShellCommand from "../mjs/components/ShellCommand.mjs"
import Templates, { Index } from "./components/Templates.mjs"

export const ProjectTemplate = {
components: {
ShellCommand,
},
template:/*html*/`
<div class="flex flex-col w-96">
<input type="text" v-model="project" autocomplete="off" spellcheck="false" @keydown="validateSafeName"
class="mb-8 sm:text-lg rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 border-gray-300 dark:bg-gray-800"/>
<section class="w-full flex justify-center text-center">
<div class="mb-2">
<div class="flex justify-center text-center">
<a class="archive-url hover:no-underline netcoretemplates_empty" :href="zipUrl('NetCoreTemplates/blazor')">
<div class="bg-white dark:bg-gray-800 px-4 py-4 mr-4 mb-4 rounded-lg shadow-lg text-center items-center justify-center hover:shadow-2xl dark:border-2 dark:border-pink-600 dark:hover:border-blue-600 dark:border-2 dark:border-pink-600 dark:hover:border-blue-600" style="min-width:150px">
<div class="text-center font-extrabold flex items-center justify-center mb-2">
<div class="text-4xl text-blue-400 my-3">
<svg class="w-14 h-14 text-purple-500" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="currentColor" d="M23.834 8.101a13.912 13.912 0 0 1-13.643 11.72a10.105 10.105 0 0 1-1.994-.12a6.111 6.111 0 0 1-5.082-5.761a5.934 5.934 0 0 1 11.867-.084c.025.983-.401 1.846-1.277 1.871c-.936 0-1.374-.668-1.374-1.567v-2.5a1.531 1.531 0 0 0-1.52-1.533H8.715a3.648 3.648 0 1 0 2.695 6.08l.073-.11l.074.121a2.58 2.58 0 0 0 2.2 1.048a2.909 2.909 0 0 0 2.695-3.04a7.912 7.912 0 0 0-.217-1.933a7.404 7.404 0 0 0-14.64 1.603a7.497 7.497 0 0 0 7.308 7.405s.549.05 1.167.035a15.803 15.803 0 0 0 8.475-2.528c.036-.025.072.025.048.061a12.44 12.44 0 0 1-9.69 3.963a8.744 8.744 0 0 1-8.9-8.972a9.049 9.049 0 0 1 3.635-7.247a8.863 8.863 0 0 1 5.229-1.726h2.813a7.915 7.915 0 0 0 5.839-2.578a.11.11 0 0 1 .059-.034a.112.112 0 0 1 .12.053a.113.113 0 0 1 .015.067a7.934 7.934 0 0 1-1.227 3.549a.107.107 0 0 0-.014.06a.11.11 0 0 0 .073.095a.109.109 0 0 0 .062.004a8.505 8.505 0 0 0 5.913-4.876a.155.155 0 0 1 .055-.053a.15.15 0 0 1 .147 0a.153.153 0 0 1 .054.053A10.779 10.779 0 0 1 23.834 8.1zM8.895 11.628a2.188 2.188 0 1 0 2.188 2.188v-2.042a.158.158 0 0 0-.15-.15Z"/></svg>
</div>
</div>
<div class="text-xl font-medium text-gray-700">Blazor</div>
<div class="flex justify-center h-8"></div>
<span class="archive-name px-4 pb-2 text-blue-600 dark:text-indigo-400">{{ projectZip }}</span>
<div class="count mt-1 text-gray-400 text-sm"></div>
</div>
</a>
</div>
</div>
</section>
<h4 class="py-6 text-center text-xl">or create from command-line:</h4>
<ShellCommand class="mb-2">dotnet tool install -g x</ShellCommand>
<ShellCommand class="mb-2">x new {{template}} {{project}}</ShellCommand>
<h4 class="pt-6 text-center text-xl font-medium">Run Tailwind and .NET for Development</h4>
<h4 class="py-6 text-center text-xl">In <span class="font-semibold text-indigo-700">/MyApp</span>, Run Tailwind</h4>
<ShellCommand class="mb-2">npm run ui:dev</ShellCommand>
<h4 class="py-6 text-center text-xl">Run .NET Project (New Terminal)</h4>
<ShellCommand class="mb-2">dotnet watch</ShellCommand>
</div>`,
props: { template:String },
setup(props) {
const project = ref('ProjectName')

const projectZip = computed(() => (project.value || 'MyApp') + '.zip')

/** @param {string} template */
const zipUrl = (template) =>
`https://account.servicestack.net/archive/${template}?Name=${project.value || 'MyApp'}`

/** @param {KeyboardEvent} e */
const isAlphaNumeric = (e) => {
const c = e.charCode;
if (c >= 65 && c <= 90 || c >= 97 && c <= 122 || c >= 48 && c <= 57 || c === 95) //A-Za-z0-9_
return;
e.preventDefault()
}
const BlazorTemplate = {
components: { Templates },
template:`<Templates :templates="[Index['blazor']]" />`,
setup() {
return { Index }
}
}

/** @param path {string}
* @returns {string} */
const resolvePath = (path) => navigator.userAgent.indexOf("Win") >= 0 ? path.replace(/\//g,'\\') : path
const uiPath = () => resolvePath(`ui`)
const apiPath = () => resolvePath(`api/${project.value}`)
const BlazorVueTemplate = {
components: { Templates },
template:`<Templates :templates="[Index['blazor-vue']]" />`,
setup() {
return { Index }
}
}

/** @param e {KeyboardEvent} */
function validateSafeName(e) {
if (e.key.match(/[\W]+/g)) {
e.preventDefault()
return false
}
}
return { project, projectZip, zipUrl, isAlphaNumeric, uiPath, apiPath, validateSafeName }
const IdentityAuthTemplates = {
components: { Templates },
template:`<Templates :templates="[Index['blazor'], Index['blazor-vue'], Index['razor'], Index['mvc'], Index['razor-bootstrap'], Index['mvc-bootstrap']]" hide="demo" />`,
setup() {
return { Index }
}
}

export default {
components: { ProjectTemplate }
install(app) {
},
components: {
BlazorTemplate,
BlazorVueTemplate,
IdentityAuthTemplates,
},
setup() {
return { }
}
}

0 comments on commit 6969c57

Please sign in to comment.