Create Nuxt version
This commit is contained in:
parent
9e80e528c9
commit
128c554ce5
@ -1,12 +0,0 @@
|
||||
# This file is used by the build system to adjust CSS and JS output to support the specified browsers below.
|
||||
# For additional information regarding the format and rule options, please see:
|
||||
# https://github.com/browserslist/browserslist#queries
|
||||
|
||||
# You can see what browsers were selected by your queries by running:
|
||||
# npx browserslist
|
||||
|
||||
> 0.5%
|
||||
last 2 versions
|
||||
Firefox ESR
|
||||
not dead
|
||||
not IE 9-11 # For IE 9-11 support, remove 'not'.
|
@ -1,13 +1,13 @@
|
||||
# Editor configuration, see https://editorconfig.org
|
||||
# editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
max_line_length = off
|
||||
trim_trailing_whitespace = false
|
||||
|
15
bit-badger-solutions/.eslintrc.js
Normal file
15
bit-badger-solutions/.eslintrc.js
Normal file
@ -0,0 +1,15 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
browser: true,
|
||||
node: true
|
||||
},
|
||||
extends: [
|
||||
'@nuxtjs/eslint-config-typescript',
|
||||
'plugin:nuxt/recommended'
|
||||
],
|
||||
plugins: [
|
||||
],
|
||||
// add your custom rules here
|
||||
rules: {}
|
||||
}
|
120
bit-badger-solutions/.gitignore
vendored
120
bit-badger-solutions/.gitignore
vendored
@ -1,46 +1,90 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
||||
### Node template
|
||||
# Logs
|
||||
/logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# compiled output
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
# Only exists if Bazel was run
|
||||
/bazel-out
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# profiling files
|
||||
chrome-profiler-events*.json
|
||||
speed-measure-plugin*.json
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# IDEs and editors
|
||||
/.idea
|
||||
.project
|
||||
.classpath
|
||||
.c9/
|
||||
*.launch
|
||||
.settings/
|
||||
*.sublime-workspace
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# IDE - VSCode
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
.history/*
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# misc
|
||||
/.sass-cache
|
||||
/connect.lock
|
||||
/coverage
|
||||
/libpeerconnection.log
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
testem.log
|
||||
/typings
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# System Files
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# Nuxt generate
|
||||
dist
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless
|
||||
|
||||
# IDE / Editor
|
||||
.idea
|
||||
|
||||
# Service worker
|
||||
sw.*
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Vim swap files
|
||||
*.swp
|
||||
|
20
bit-badger-solutions/README.md
Normal file
20
bit-badger-solutions/README.md
Normal file
@ -0,0 +1,20 @@
|
||||
# bit-badger-solutions
|
||||
|
||||
## Build Setup
|
||||
|
||||
```bash
|
||||
# install dependencies
|
||||
$ npm install
|
||||
|
||||
# serve with hot reload at localhost:3000
|
||||
$ npm run dev
|
||||
|
||||
# build for production and launch server
|
||||
$ npm run build
|
||||
$ npm run start
|
||||
|
||||
# generate static project
|
||||
$ npm run generate
|
||||
```
|
||||
|
||||
For detailed explanation on how things work, check out [Nuxt.js docs](https://nuxtjs.org).
|
@ -1,132 +0,0 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"newProjectRoot": "projects",
|
||||
"projects": {
|
||||
"bit-badger-solutions": {
|
||||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "sass"
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
"sourceRoot": "src",
|
||||
"prefix": "app",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:browser",
|
||||
"options": {
|
||||
"outputPath": "dist/bit-badger-solutions",
|
||||
"index": "src/index.html",
|
||||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"aot": true,
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.sass"
|
||||
],
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"fileReplacements": [
|
||||
{
|
||||
"replace": "src/environments/environment.ts",
|
||||
"with": "src/environments/environment.prod.ts"
|
||||
}
|
||||
],
|
||||
"optimization": true,
|
||||
"outputHashing": "all",
|
||||
"sourceMap": false,
|
||||
"extractCss": true,
|
||||
"namedChunks": false,
|
||||
"extractLicenses": true,
|
||||
"vendorChunk": false,
|
||||
"buildOptimizer": true,
|
||||
"budgets": [
|
||||
{
|
||||
"type": "initial",
|
||||
"maximumWarning": "2mb",
|
||||
"maximumError": "5mb"
|
||||
},
|
||||
{
|
||||
"type": "anyComponentStyle",
|
||||
"maximumWarning": "6kb",
|
||||
"maximumError": "10kb"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"builder": "@angular-devkit/build-angular:dev-server",
|
||||
"options": {
|
||||
"browserTarget": "bit-badger-solutions:build"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"browserTarget": "bit-badger-solutions:build:production"
|
||||
}
|
||||
}
|
||||
},
|
||||
"extract-i18n": {
|
||||
"builder": "@angular-devkit/build-angular:extract-i18n",
|
||||
"options": {
|
||||
"browserTarget": "bit-badger-solutions:build"
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "src/test.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"src/styles.sass"
|
||||
],
|
||||
"scripts": []
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"tsconfig.app.json",
|
||||
"tsconfig.spec.json",
|
||||
"e2e/tsconfig.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
},
|
||||
"e2e": {
|
||||
"builder": "@angular-devkit/build-angular:protractor",
|
||||
"options": {
|
||||
"protractorConfig": "e2e/protractor.conf.js",
|
||||
"devServerTarget": "bit-badger-solutions:serve"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"devServerTarget": "bit-badger-solutions:serve:production"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "bit-badger-solutions",
|
||||
"cli": {
|
||||
"analytics": "bfe12c8e-b3a2-47cb-abee-7380fe1d1fed"
|
||||
}
|
||||
}
|
29
bit-badger-solutions/components/Logo.vue
Normal file
29
bit-badger-solutions/components/Logo.vue
Normal file
@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<svg class="NuxtLogo" width="245" height="180" viewBox="0 0 452 342" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="M139 330l-1-2c-2-4-2-8-1-13H29L189 31l67 121 22-16-67-121c-1-2-9-14-22-14-6 0-15 2-22 15L5 303c-1 3-8 16-2 27 4 6 10 12 24 12h136c-14 0-21-6-24-12z"
|
||||
fill="#00C58E"
|
||||
/>
|
||||
<path
|
||||
d="M447 304L317 70c-2-2-9-15-22-15-6 0-15 3-22 15l-17 28v54l39-67 129 230h-49a23 23 0 0 1-2 14l-1 1c-6 11-21 12-23 12h76c3 0 17-1 24-12 3-5 5-14-2-26z"
|
||||
fill="#108775"
|
||||
/>
|
||||
<path
|
||||
d="M376 330v-1l1-2c1-4 2-8 1-12l-4-12-102-178-15-27h-1l-15 27-102 178-4 12a24 24 0 0 0 2 15c4 6 10 12 24 12h190c3 0 18-1 25-12zM256 152l93 163H163l93-163z"
|
||||
fill="#2F495E"
|
||||
/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.NuxtLogo {
|
||||
animation: 1s appear;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
@keyframes appear {
|
||||
0% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
19
bit-badger-solutions/components/PageFooter.vue
Normal file
19
bit-badger-solutions/components/PageFooter.vue
Normal file
@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<footer>
|
||||
A <strong><nuxt-link to="/">Bit Badger Solutions</nuxt-link></strong> original design
|
||||
</footer>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
footer {
|
||||
padding: 20px 15px 10px 15px;
|
||||
text-align: right;
|
||||
font-size: 1rem;
|
||||
color: black;
|
||||
clear: both;
|
||||
background-image: linear-gradient(to bottom, #FFFAFA, lightgray);
|
||||
}
|
||||
footer a:link, footer a:visited {
|
||||
color: black;
|
||||
}
|
||||
</style>
|
70
bit-badger-solutions/components/PageHeader.vue
Normal file
70
bit-badger-solutions/components/PageHeader.vue
Normal file
@ -0,0 +1,70 @@
|
||||
<template>
|
||||
<header class="site-header">
|
||||
<div class="header-logo">
|
||||
<nuxt-link to="/">
|
||||
<img
|
||||
src="/bitbadger.png"
|
||||
alt="A cartoon badger looking at a computer screen, with his paw on a mouse"
|
||||
title="Bit Badger Solutions">
|
||||
</nuxt-link>
|
||||
</div>
|
||||
<div class="header-title">
|
||||
<nuxt-link to="/">Bit Badger Solutions</nuxt-link>
|
||||
</div>
|
||||
<div class="header-spacer">
|
||||
|
||||
</div>
|
||||
<div class="header-social">
|
||||
<a href="https://twitter.com/Bit_Badger" title="Bit_Badger on Twitter" target="_blank">
|
||||
<img src="/twitter.png" alt="Twitter">
|
||||
</a> <a href="https://www.facebook.com/bitbadger.solutions" title="Bit Badger Solutions on Facebook" _target="_blank">
|
||||
<img src="/facebook.png" alt="Facebook">
|
||||
</a>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.site-header {
|
||||
height: 100px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
background-image: linear-gradient(to bottom, lightgray, #FFFAFA);
|
||||
}
|
||||
.site-header a, .site-header a:visited {
|
||||
color: black;
|
||||
}
|
||||
.site-header a:hover {
|
||||
border-bottom: none;
|
||||
}
|
||||
.header-title {
|
||||
font-size: 3rem;
|
||||
font-weight: bold;
|
||||
line-height: 100px;
|
||||
text-align: center;
|
||||
}
|
||||
.header-spacer {
|
||||
flex-grow: 3;
|
||||
}
|
||||
.header-social {
|
||||
padding: 25px .8rem 0 0;
|
||||
}
|
||||
.header-social img {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
@media all and (max-width:40rem) {
|
||||
.site-header {
|
||||
height: auto;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.header-title {
|
||||
line-height: 3rem;
|
||||
}
|
||||
.header-spacer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
41
bit-badger-solutions/components/global/HiddenSection.vue
Normal file
41
bit-badger-solutions/components/global/HiddenSection.vue
Normal file
@ -0,0 +1,41 @@
|
||||
<template>
|
||||
<section>
|
||||
<h3 @click="toggle()">
|
||||
{{ heading }}<span class="arrow" v-html="label"></span>
|
||||
</h3>
|
||||
<slot v-if="isVisible"></slot>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
export default Vue.extend({
|
||||
name: 'hidden-section',
|
||||
props: [
|
||||
'heading'
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
isVisible: false,
|
||||
label: '▼'
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggle () {
|
||||
this.isVisible = !this.isVisible
|
||||
this.label = this.isVisible ? '▲' : '▼'
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
h3:hover {
|
||||
cursor: hand;
|
||||
cursor: pointer;
|
||||
}
|
||||
.arrow {
|
||||
font-size: .75rem;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
</style>
|
108
bit-badger-solutions/components/global/HomeSidebar.vue
Normal file
108
bit-badger-solutions/components/global/HomeSidebar.vue
Normal file
@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<aside class="app-sidebar">
|
||||
<div v-for="cat in sortedCats" :key="cat">
|
||||
<div class="app-sidebar-head" v-text="cat" />
|
||||
<div v-for="sln in displayForCategegory(cat)" :key="sln.title">
|
||||
<p class="app-sidebar-name">
|
||||
<strong>{{ sln.title }}</strong><br>
|
||||
<span v-if="!sln.noAboutLink">
|
||||
<nuxt-link :to="`/solutions/${sln.slug}`" :title="aboutTitle(sln.title)">About</nuxt-link> •
|
||||
</span>
|
||||
<a :href="sln.url" :title="sln.title" target="_blank">Visit</a>
|
||||
</p>
|
||||
<p class="app-sidebar-description" v-html="sln.frontPage.text" />
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
|
||||
/**
|
||||
* Sort the categories in a specific order; any not addressed will appear at the bottom.
|
||||
*/
|
||||
const categoryOrder = (x: string, y: string) => {
|
||||
if (x === 'Web Sites and Applications') { return -1 }
|
||||
if (x === 'WordPress' && y !== 'Web Sites and Applications') { return -1 }
|
||||
if (x === 'Static Sites' && y !== 'Web Sites and Applications' && y !== 'WordPress') { return -1 }
|
||||
return 1
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'home-sidebar',
|
||||
props: ['catNames', 'solutions'],
|
||||
computed: {
|
||||
sortedCats (): string[] {
|
||||
return [...this.catNames].sort(categoryOrder)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
displayForCategegory (category: string): any[] {
|
||||
return this.solutions
|
||||
.filter((x: any) => x.category === category)
|
||||
.sort((x: any, y: any) => x.frontPage.order - y.frontPage.order)
|
||||
},
|
||||
aboutTitle (name: string): string {
|
||||
return `About ${name} | Bit Badger Solutions`
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-sidebar {
|
||||
text-align: center;
|
||||
border-top: dotted 1px lightgray;
|
||||
padding-top: 1rem;
|
||||
font-size: .9rem;
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: space-around;
|
||||
}
|
||||
.app-sidebar > div {
|
||||
width: 20rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
@media all and (min-width: 68rem) {
|
||||
.app-sidebar {
|
||||
width: 66rem;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
@media all and (min-width: 80rem) {
|
||||
.app-sidebar {
|
||||
width: 12rem;
|
||||
border-top: none;
|
||||
border-left: dotted 1px lightgray;
|
||||
padding-top: 0;
|
||||
padding-left: 2rem;
|
||||
flex-direction: column;
|
||||
}
|
||||
.app-sidebar > div {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
.app-sidebar a {
|
||||
font-size: 10pt;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
.app-sidebar-head {
|
||||
font-family: "Oswald", "Segoe UI", Ubuntu, "DejaVu Sans", "Liberation Sans", Arial, sans-serif;
|
||||
font-weight: bold;
|
||||
color: maroon;
|
||||
margin-bottom: .8rem;
|
||||
padding: 3px 12px;
|
||||
border-bottom: solid 2px lightgray;
|
||||
font-size: 1rem;
|
||||
}
|
||||
.app-sidebar-name, .app-sidebar-description {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.app-sidebar-description {
|
||||
font-style: italic;
|
||||
color: #555555;
|
||||
padding-bottom: .6rem;
|
||||
}
|
||||
</style>
|
29
bit-badger-solutions/components/global/SolutionItem.vue
Normal file
29
bit-badger-solutions/components/global/SolutionItem.vue
Normal file
@ -0,0 +1,29 @@
|
||||
<template>
|
||||
<p>
|
||||
<span class="app-name" v-html="solution.title"></span>
|
||||
~ <nuxt-link :to="'/solutions/' + solution.slug">About</nuxt-link>
|
||||
<span v-if="!solution.isInactive">~ <a :href="solution.url" target="_blank">Visit</a></span>
|
||||
<span v-if="solution.isInactive && solution.archiveUrl">
|
||||
~ <a :href="solution.archiveUrl" target="_blank">Visit</a><em> (archive)</em>
|
||||
</span>
|
||||
<br>
|
||||
<span v-html="solution.summary"></span>
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
export default Vue.extend({
|
||||
name: 'solution-item',
|
||||
props: ['solution']
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.app-name {
|
||||
font-family: "Oswald", "Segoe UI", Ubuntu, "DejaVu Sans", "Liberation Sans", Arial, sans-serif;
|
||||
font-size: 1.3rem;
|
||||
font-weight: bold;
|
||||
color: maroon;
|
||||
}
|
||||
</style>
|
58
bit-badger-solutions/components/global/TechnologyItem.vue
Normal file
58
bit-badger-solutions/components/global/TechnologyItem.vue
Normal file
@ -0,0 +1,58 @@
|
||||
<template>
|
||||
<li>
|
||||
<a v-if="hasLink(tech[0])" :href="techLinks[tech[0]]" target="_blank">{{ tech[0] }}</a>
|
||||
<template v-else>{{ tech[0] }}</template>
|
||||
for {{ tech[1] }}
|
||||
</li>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
|
||||
/** Links to various technologies */
|
||||
const techLinks: any = {
|
||||
'ASP.NET MVC': 'https://dotnet.microsoft.com/apps/aspnet/mvc',
|
||||
Azure: 'https://azure.microsoft.com/',
|
||||
'BlogEngine.NET': 'http://www.dotnetblogengine.net/',
|
||||
'Database Abstraction': 'https://github.com/danieljsummers/DatabaseAbstraction',
|
||||
'Digital Ocean': 'https://www.digitalocean.com/',
|
||||
Giraffe: 'https://github.com/giraffe-fsharp/Giraffe',
|
||||
GitHub: 'https://github.com/',
|
||||
'GitHub Pages': 'https://pages.github.com/',
|
||||
Hexo: 'https://hexo.io/',
|
||||
Hugo: 'https://gohugo.io/',
|
||||
Jekyll: 'https://jekyllrb.com/',
|
||||
MongoDB: 'https://www.mongodb.com/',
|
||||
MySQL: 'https://www.mysql.com/',
|
||||
myWebLog: 'https://github.com/bit-badger/myWebLog',
|
||||
nginx: 'http://nginx.org/',
|
||||
Orchard: 'https://orchardproject.net/',
|
||||
PHP: 'https://www.php.net/',
|
||||
PostgreSQL: 'https://www.postgresql.org/',
|
||||
'Rackspace Cloud': 'https://www.rackspace.com/cloud',
|
||||
RavenDB: 'https://ravendb.net/',
|
||||
RethinkDB: 'https://rethinkdb.com/',
|
||||
'SQL Server': 'https://www.microsoft.com/en-us/sql-server/',
|
||||
'Vue.js': 'https://vuejs.org/',
|
||||
WordPress: 'https://wordpress.org'
|
||||
}
|
||||
|
||||
export default Vue.extend({
|
||||
name: 'technology-item',
|
||||
props: [ 'tech' ],
|
||||
data () {
|
||||
return { techLinks }
|
||||
},
|
||||
methods: {
|
||||
/**
|
||||
* Does the given technology have a known link?
|
||||
*
|
||||
* @param tech The technology to be checked
|
||||
* @returns True if there is a link, false if not
|
||||
*/
|
||||
hasLink (tech: string): boolean {
|
||||
return techLinks[tech] !== undefined
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
@ -0,0 +1,21 @@
|
||||
---
|
||||
title: Information Publicizing and Blogging
|
||||
---
|
||||
In the early days of the World Wide Web, it was known as the “information superhighway.” From its inception, the web’s primary goal is information. The open nature of the Internet allows anyone, anywhere to say anything, provided they can connect a machine to the network. In fact, there are software products to handle everything except creating the content; all you have to bring is the ability to form a coherent thought, and type that thought into a box. [WordPress](https://wordpress.org "WordPress") is one of the most popular <abbr title="Web Log">blog</abbr>ging platforms in use today; it allows authors to concentrate on the content of their websites, rather than forcing authors to turn into programmers.
|
||||
|
||||
## Custom-Built Sites
|
||||
|
||||
- We developed and maintained the site for [Emerald Mountain Christian School](http://www.emeraldmountainchristianschool.org)<small> (<nuxt-link to="/solutions/emerald-mountain-christian-school" title="Emerald Mountain Christian School • Bit Badger Solutions">about</nuxt-link>)</small> for 9 years, where they had information about the type of curriculum they teach, the school’s 40+-year history, a calendar of events, and how to get more information.
|
||||
- We built and maintained the site for [Photography by Michelle](https://www.summershome.org)<small> (<nuxt-link to="/solutions/photography-by-michelle" title="Photography by Michelle • Bit Badger Solutions">about</nuxt-link>)</small>, which had information, prices, and samples of the photographer’s work, as well as the ability for customers to view proofs and make photo selections online.
|
||||
- The site for [Bay Vista Baptist Church](https://bayvista.org "Bay Vista Baptist Church")<small> (<nuxt-link to="/solutions/bay-vista" title="Bay Vista Baptist Church • Bit Badger Solutions">about</nuxt-link>)</small> utilizes a “static site generator,” where the entire site is generated from source files, then served. It requires no back-end database, which means that the server can send pages as fast as its clients can take them. This site even has a generated podcast feed! Adding content to these types of sites requires a bit more technical knowledge beyond “typing text in a box,” but it is a great way to build ultra-fast, scalable web sites.
|
||||
- This site is also a statically-generated site, utilizing the [Nuxt](https://nuxtjs.org) project for the [Vue.js](https://vuejs.org) JavaScript framework. Using Nuxt’s content plugin, the majority of pages are written in Markdown (a very writing-friendly format). We can include data at the top of each file that controls how it is displayed; this gives us both the flexibility of a database and the speed of not actually having one! (It’s [open source](https://github.com/bit-badger/bitbadger.solutions) if you want to see how we did it.)
|
||||
|
||||
## WordPress Design, Customization, and Support
|
||||
|
||||
- For [Futility Closet](https://www.futilitycloset.com "Futility Closet")<small> (<nuxt-link to="/solutions/futility-closet" title="Futility Closet • Bit Badger Solutions">about</nuxt-link>)</small>, we moved their site from a shared hosting platform to its own <abbr title="Virtual Private Server">VPS</abbr>, securing it from intrusion attempts and enabling it to handle its ever-increasing traffic.
|
||||
- We took over [Mindy Mackenzie](https://mindymackenzie.com "Mindy Mackenzie")<small> (<nuxt-link to="/solutions/mindy-mackenzie" title="Mindy Mackenzie • Bit Badger Solutions">about</nuxt-link>)</small> in advance of the release of her eventual _<abbr title="Wall Street Journal">WSJ</abbr>_ best-selling book _The Courage Solution_, and continue to support her as she hosts the annual _You First Integrative Leadership Summit_.
|
||||
- We helped <nuxt-link to="/solutions/cassy-fiano" title="Cassy Fiano • Bit Badger Solutions">Cassy Fiano</nuxt-link> and <nuxt-link to="/solutions/dr-melissa-clouthier" title="Dr. Melissa Clouthier • Bit Badger Solutions">Dr. Melissa Clouthier</nuxt-link> both move their blogs from Blogspot to their own domains.
|
||||
- We migrated <nuxt-link to="/solutions/liberty-pundits" title="Liberty Pundits • Bit Badger Solutions">Liberty Pundits</nuxt-link> from a custom blog platform to WordPress, and set up and maintained their server, which routinely cleared 100,000 hits per day in its prime.
|
||||
- <nuxt-link to="/solutions/tcms" title="The Clearinghouse Management System (TCMS) • Bit Badger Solutions">TCMS</nuxt-link> and <nuxt-link to="/solutions/nsx" title="NSXapp • Bit Badger Solutions">NSXapp</nuxt-link> both used WordPress as their front end, which also provided a public web presence that the customers could update themselves.
|
||||
|
||||
On _[The Bit Badger Blog](https://blog.bitbadger.solutions "The Bit Badger Blog")_ you can browse the [WordPress](https://blog.bitbadger.solutions/category/wordpress "WordPress • The Bit Badger Blog") category for information on plug-ins, and we have supported theme customizations for nearly all of the WordPress sites linked on the sidebar/footer of the home page.
|
4
bit-badger-solutions/content/about/legacy-data.md
Normal file
4
bit-badger-solutions/content/about/legacy-data.md
Normal file
@ -0,0 +1,4 @@
|
||||
---
|
||||
title: Legacy Data Solutions
|
||||
---
|
||||
Our background in mainframe applications gives us a knowledgeable perspective on retrieving information from older, “legacy” systems. This data can be migrated to a more modern relational or document database, where a web application can retrieve the information; in some cases, the data can even be exposed as a web service in place. These types of systems are often a great way for companies to expose their data to their customers, without having to move their day-to-day system from its current environment. While we currently have no active projects along these lines, we have done them in the past for other organizations; sadly, none can be linked publicly.
|
@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Process Automation and User Engagement
|
||||
---
|
||||
Computers can be used to augment or automate nearly any process; could you think of generating bank statements, processing mailing lists, or tracking orders without some form of automation? We develop web-based solutions to automate _your_ processes, ensuring that your business constraints are satisfied; these systems can run on the Internet or your private network. For Internet-facing solutions, we engineer solutions that allow them to interact with you securely, presented in an engaging manner. And, by “engagement,” we are not describing intrusive page pop-ups and other <span class="strike">marketing gimmicks</span> web annoyances; we determine an optimal user experience for _your_ customers, and tailor the solution to work for both of you.
|
||||
|
||||
Several of our solutions fit this description.
|
||||
|
||||
- <nuxt-link to="/solutions/virtual-prayer-room" title="Virtual Prayer Room • Bit Badger Solutions">Virtual Prayer Room</nuxt-link> helped the prayer ministry of [Hoffmantown Church](https://www.hoffmantownchurch.org "Hoffmantown Church • Albuquerque, New Mexico") enable their prayer warriors to have access to requests wherever they are, even in their inbox once a day!
|
||||
- <nuxt-link to="/solutions/tcms" title="The Clearinghouse Management System (TCMS) • Bit Badger Solutions">TCMS</nuxt-link> was an application that helped organizations such as [Love INC of South Albuquerque](http://www.loveincabq.org) connect people with needs to people who can help fulfill those needs. TCMS sprung from the [Not So Extreme Makeover: Community Edition](https://nsx.archive.bitbadger.solutions "Not So Extreme Makeover: Community Edition (Archive)") in Albuquerque, New Mexico during spring break 2008; we not only developed the public presence, but a private system called <nuxt-link to="/solutions/nsx" title="NSXapp • Bit Badger Solutions">NSXapp</nuxt-link> that enabled the management of the volunteers, families, and things for this massive effort.
|
||||
- We continue to offer [PrayerTracker](https://prayer.bitbadger.solutions "PrayerTracker")<small> (<nuxt-link to="/solutions/prayer-tracker" title="PrayerTracker • Bit Badger Solutions">about</nuxt-link>)</small>, a free-to-use web application that helps Sunday School classes (or other small groups) generate a prayer request list; it provides a central place for list management and continuity.
|
10
bit-badger-solutions/content/about/web-services-solutions.md
Normal file
10
bit-badger-solutions/content/about/web-services-solutions.md
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Web Services Solutions
|
||||
---
|
||||
A web service is a way of using the Internet to provide or accept information that makes sense to computers; this allows other sites or applications to consume information from, or provide information to, your service. This enables communication between applications, without having to establish any communication channels other than the ones that web browsers already use. It isn’t the best fit for every application, but when it is useful, it is _very_ useful.
|
||||
|
||||
An <abbr title="Application Programming Interface">API</abbr> can be a synonym for a web service, but it can also be a generally accessible way of providing data. For example, Twitter has a public API, which other applications can use to display tweets on their site.
|
||||
|
||||
- [myPrayerJournal](https://prayerjournal.me)<small> (<nuxt-link to="/solutions/my-prayer-journal" title="myPrayerJournal • Bit Badger Solutions">about</nuxt-link>)</small> is a <abbr title="Single Page Application">SPA</abbr> which only downloads the structure of the site the first time you go there, then utilizes a stateless API to access data from the browser.
|
||||
- <nuxt-link to="/solutions/photography-by-michelle" title="Photography by Michelle • Bit Badger Solutions">Photography by Michelle</nuxt-link> had a private web API that a desktop application utilized to create the online proof sets right from the computer where the images resided.
|
||||
- We [wrote a service](https://blog.bitbadger.solutions/2010/4040-web-service.html "40/40 Web Service • The Bit Badger Blog") for the 2010 [40/40 Prayer Vigil](http://erlc.com/4040/ "40/40 Prayer Vigil • Ethics and Religious Liberty Commission of the Southern Baptist Convention"), which was utilized by several sites to display the current day’s (or hour’s) prayer focus, and [wrote one for 2012](https://blog.bitbadger.solutions/2012/4040-web-service-for-2012.html "40/40 Web Service for 2012 • The Bit Badger Blog") as well. _(As the ERLC does not host these any more, this service is no longer active.)_
|
8
bit-badger-solutions/content/about/why-bit-badger.md
Normal file
8
bit-badger-solutions/content/about/why-bit-badger.md
Normal file
@ -0,0 +1,8 @@
|
||||
---
|
||||
title: Why “Bit Badger”?
|
||||
---
|
||||
A while back, our primary developer Daniel learned through genetic testing that he had one gene that was not right (technically known as a genetic mutation). He is currently fine _(thank you for asking)_, but his co-workers thought of another group of genetic mutants – the X-Men. They wanted to develop the mutant identity for him in that style; since Wolverine is already taken, they wanted something similar, but based on a member of the weasel family (for its normal private life and fierce tenacity, not its morals). They went through several different options, but when “Bit Badger” was mentioned, it was the winner. The Bit Badger's mutant superpower is the ability to shoot 1s and 0s out its nostrils!
|
||||
|
||||
Daniel liked this moniker, and decided to run with it. He had been growing dissatisfied with the name “DJS Consulting,” as he felt that name was passive. He enjoys taking problems and finding creative solutions for them, making our computers work for us instead of the other way around. While he can't actually breathe out 1s and 0s, they do flow from his fingers (in groups of 8, of course).
|
||||
|
||||
Do you have a problem that needs a solution? [Sic the Bit Badger on it](mailto:daniel@bitbadger.solutions)!
|
45
bit-badger-solutions/content/home.md
Normal file
45
bit-badger-solutions/content/home.md
Normal file
@ -0,0 +1,45 @@
|
||||
<p class="home-lead">Bit Badger Solutions develops the site you need to enable your success!</p>
|
||||
|
||||
These solutions can take several different forms.
|
||||
|
||||
## Process Automation and User Engagement
|
||||
|
||||
Do you have a process that requires recording the same thing multiple times? Do you have information in different places, but you need it all together? This solution is for you. [Learn more about how our solutions automate processes and engage users][automation].
|
||||
|
||||
## Information Publicizing and Blogging
|
||||
|
||||
From its inception, the Web has been about information. Do you need to get information out about an upcoming event? Are you wanting to start blogging, or breathe some fresh life into an existing blog? Those are but a few of the problems that this solution solves. [Find out more about our information publicizing and blogging solutions][information] (including WordPress and statically-generated sites).
|
||||
|
||||
## Web Services and APIs
|
||||
|
||||
Do you have a need for multiple computers to talk to each other? Do you have an interesting data set that you want to make available to the public? A web service or API may be just the solution for you. [Learn about web services, along with examples of current solutions][services].
|
||||
|
||||
## Legacy Data Sharing
|
||||
|
||||
Do you have data that's old — and by “old,” we aren’t talking “iPhone 6” old, we’re talking “this data [could run for President][old]” old? Just because the information is in an older “legacy” system doesn’t mean it has to stay there. [Learn how our solutions can help get this data where you and your customers can access it more easily][legacy].
|
||||
|
||||
## Why Web-Based?
|
||||
|
||||
Web-based solutions have many advantages:
|
||||
|
||||
- They can be used just on a local, private network (an intranet) or on the public Internet.
|
||||
- They are available to any device connected to the network.
|
||||
- They require no special software; every device has a browser - which you're using to read this!)
|
||||
- They can get your most critical needs met first, then evolved and improved over time.
|
||||
|
||||
## What Is a “Bit Badger”?
|
||||
|
||||
[Read the Bit Badger’s origin story][origin].
|
||||
|
||||
## Solutions to Your Problems
|
||||
|
||||
We’d be happy to discuss your information technology needs, and which of our solutions are right for you. Just [e-mail us](mailto:daniel@bitbadger.solutions) and let us know what we can do for you! You can also [browse a complete list of our current and previous solutions][solutions].
|
||||
|
||||
|
||||
[automation]: /about/process-automation-solutions "Process Automation Solutions"
|
||||
[information]: /about/information-publicizing-solutions "Information Publicizing Solutions"
|
||||
[services]: /about/web-services-solutions "Web Services and API Solutions"
|
||||
[old]: https://en.wikipedia.org/wiki/Age_of_candidacy#United_States "Age of Candidacy (United States) | Wikipedia"
|
||||
[legacy]: /about/legacy-data "Legacy Data Sharing Solutions"
|
||||
[origin]: /about/why-bit-badger "Why Bit Badger?"
|
||||
[solutions]: /solutions "All Solutions"
|
@ -0,0 +1,10 @@
|
||||
---
|
||||
title: A Word from the Word
|
||||
url: https://devotions.summershome.org
|
||||
category: Personal
|
||||
noAboutLink: true
|
||||
frontPage:
|
||||
display: true
|
||||
order: 2
|
||||
text: Devotions by Daniel
|
||||
---
|
49
bit-badger-solutions/content/solutions/bay-vista.md
Normal file
49
bit-badger-solutions/content/solutions/bay-vista.md
Normal file
@ -0,0 +1,49 @@
|
||||
---
|
||||
title: Bay Vista Baptist Church
|
||||
url: https://bayvista.org
|
||||
summary: Southern Baptist church in Biloxi, Mississippi
|
||||
category: Static Sites
|
||||
frontPage:
|
||||
display: true
|
||||
order: 1
|
||||
text: Biloxi, Mississippi
|
||||
technologies:
|
||||
- Hugo:
|
||||
for: static site generation
|
||||
isCurrent: true
|
||||
- Azure:
|
||||
for: podcast file storage, automated builds, and static site hosting
|
||||
isCurrent: true
|
||||
- GitHub:
|
||||
for: source code control
|
||||
isCurrent: true
|
||||
- Hexo:
|
||||
for: static site generation
|
||||
- Jekyll:
|
||||
for: static site generation
|
||||
- WordPress:
|
||||
for: content management
|
||||
- MySQL:
|
||||
for: data storage
|
||||
---
|
||||
### The Client
|
||||
|
||||
Bay Vista Baptist Church has served the spiritual needs of Mississippi’s Gulf Coast for decades. They emphasize serving their community as well; they were a hub for <abbr title="Federal Emergency Management Agency">FEMA</abbr> during Hurricane Katrina relief and recovery efforts, and they are a relay point for each year’s [Operation Christmas Child](https://www.samaritanspurse.org/what-we-do/operation-christmas-child/) campaign.
|
||||
|
||||
### The Problem
|
||||
|
||||
In late 2013, the authors of their current website were no longer around, and no one could get to the site to update it.
|
||||
|
||||
### The Solution
|
||||
|
||||
We developed and continue to maintain a fast, static website that can be updated by multiple trained church members. The site also has a repository for their sermons dating back to January 2014, and a podcast feed that gives their ministry a global reach.
|
||||
|
||||
<hidden-section heading="The Process">
|
||||
|
||||
Initially, we set up a WordPress-based site, where multiple people could have the ability to maintain the site. We manually downloaded all the publically-accessible parts of their old site, and used that content to form the basis for the new side, updating outdated information along the way. We maintained the same look-and-feel, but soon moved to a more mobile-friendly layout.
|
||||
|
||||
In 2016, we determined that we were the only ones updating the site, so we transformed the site to use a static site generator; this resulted in fast page loads, with automation providing scheduled updates. We also wrote a custom template for the podcast feed, which is also generated as a static file.
|
||||
|
||||
In 2019, we [open sourced](https://github.com/bayvistabc/www.bayvista.org) the site’s source code. We also set up Azure Pipelines to automatically build and deploy the site both on demand and on a schedule. Finally, we trained other church members on updating the site’s contents and the podcast feed. Although we continue to host the site, the church is now maintaining it themselves.
|
||||
|
||||
</hidden-section>
|
42
bit-badger-solutions/content/solutions/cassy-fiano.md
Normal file
42
bit-badger-solutions/content/solutions/cassy-fiano.md
Normal file
@ -0,0 +1,42 @@
|
||||
---
|
||||
title: Cassy Fiano
|
||||
url: http://www.cassyfiano.com
|
||||
summary: A “rising star” conservative blogger
|
||||
category: WordPress
|
||||
isInactive: true
|
||||
noLink: true
|
||||
frontPage:
|
||||
display: false
|
||||
technologies:
|
||||
- WordPress:
|
||||
for: blogging (with a custom theme)
|
||||
- MySQL:
|
||||
for: data storage
|
||||
- Rackspace Cloud:
|
||||
for: backup and recovery
|
||||
- Azure:
|
||||
for: backup and recovery
|
||||
---
|
||||
### The Client
|
||||
|
||||
Cassy Fiano (now Cassy Chesser) began blogging back in 2007 on Blogger. She worked hard to network with other bloggers, wrote prolifically, and gained a large audience with her coverage of life issues and of Sarah Palin as the first female Republican vice-presidential nominee.
|
||||
|
||||
### The Problem
|
||||
|
||||
With her success, Cassy was quickly outgrowing Blogger. She was interested in moving to a different platform; specifically, Movable Type, as she had some authoring experience with that platform.
|
||||
|
||||
### The Solution
|
||||
|
||||
We migrated her content to a WordPress site, and customized a theme to look very similar to her Blogger theme (which she liked). We maintained the site, and began hosting it a few years later.
|
||||
|
||||
### The Epilogue
|
||||
|
||||
Cassy formally decommissioned this site in early 2014.
|
||||
|
||||
<hidden-section heading="The Process">
|
||||
|
||||
Initially, we assisted her with finding a theme, and customized it. We also modified her old Blogger template to send redirect users to her new blog after displaying a note that the blog had moved. A few years later, we developed an advertising banner to generate income from her writing.
|
||||
|
||||
In July 2012, we began hosting the site, as we were already hosting her military wife blog <nuxt-link to="/solutions/hard-corps-wife" title="Hard Corps Wife • Bit Badger Solutions">Hard Corps Wife</nuxt-link>. When the time came to decommission the site, we backed up the data and ensured she had it.
|
||||
|
||||
</hidden-section>
|
10
bit-badger-solutions/content/solutions/daniel-j-summers.md
Normal file
10
bit-badger-solutions/content/solutions/daniel-j-summers.md
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Daniel J. Summers
|
||||
url: https://daniel.summershome.org
|
||||
category: Personal
|
||||
noAboutLink: true
|
||||
frontPage:
|
||||
display: true
|
||||
order: 1
|
||||
text: Daniel’s personal blog
|
||||
---
|
@ -0,0 +1,42 @@
|
||||
---
|
||||
title: Dr. Melissa Clouthier
|
||||
url: http://melissablogs.com
|
||||
summary: Politics, health, podcasts and more
|
||||
category: WordPress
|
||||
isInactive: true
|
||||
noLink: true
|
||||
frontPage:
|
||||
display: false
|
||||
technologies:
|
||||
- WordPress:
|
||||
for: blogging (with a custom theme)
|
||||
- MySQL:
|
||||
for: data storage
|
||||
- Rackspace Cloud:
|
||||
for: backup and recovery
|
||||
- Azure:
|
||||
for: backup and recovery
|
||||
---
|
||||
### The Client
|
||||
|
||||
Dr. Melissa Clouthier (now Mackenzie) blogged from the political right; she also covered health issues and social media techniques and utilization.
|
||||
|
||||
### The Problem
|
||||
|
||||
She had seen our work with <nuxt-link to="/solutions/cassy-fiano" title="Cassy Fiano • Bit Badger Solutions">Cassy</nuxt-link>’s site, also wanted to move off Blogger; however, she did not want to lose her years of posts up to that point.
|
||||
|
||||
### The Solution
|
||||
|
||||
We created a custom theme for her site, imported the content into a WordPress site, and created a specialized front-page template. She obtained hosting elsewhere; Bit Badger Solutions maintained it there.
|
||||
|
||||
<small>_(NOTE: The thumbnail of the site represents a new skin on the original theme; while the theme is the same, Bit Badger Solutions did not create the graphics.)_</small>
|
||||
|
||||
### The Epilogue
|
||||
|
||||
Melissa decommissioned this site in 2018; we took final snapshots of the data before shutting it down.
|
||||
|
||||
<hidden-section heading="The Process">
|
||||
|
||||
Initially, we created the theme based off another well-known blogger’s site, which had been developed by one of WordPress’s core contributors. We also advised on the type of hosting she would need for her site, and moved several domains there. We also took care of regular backups of her data.
|
||||
|
||||
</hidden-section>
|
@ -0,0 +1,43 @@
|
||||
---
|
||||
title: Emerald Mountain Christian School
|
||||
url: http://www.emeraldmountainchristianschool.org
|
||||
summary: Classical, Christ-centered education near Wetumpka, Alabama
|
||||
category: Web Sites and Applications
|
||||
isInactive: true
|
||||
frontPage:
|
||||
display: false
|
||||
technologies:
|
||||
- PHP:
|
||||
for: page generation and interactivity
|
||||
- ASP.NET MVC:
|
||||
for: page generation and interactivity
|
||||
- PostgreSQL:
|
||||
for: data storage
|
||||
- Rackspace Cloud:
|
||||
for: hosting
|
||||
- Azure:
|
||||
for: hosting
|
||||
---
|
||||
### The Client
|
||||
|
||||
Emerald Mountain Christian School is a private Christian school founded over 50 years ago. They use the Principle Approach®, which emphasizes research, reasoning, relating, and recording to help students synthesize the information they learn, rather than just requiring rote memorization. More information about the school’s rich history can be found on their site.
|
||||
|
||||
### The Problem
|
||||
|
||||
They had a website with very basic information and very little styling; they also had no way of updating it.
|
||||
|
||||
### The Solution
|
||||
|
||||
In 2004, we developed a theme that brought it in line with the design of their printed materials, adding the school calendar of events and the entirety of their Parent Information Packet, giving prospective families the information the needed to determine if the school was a good fit for their students.
|
||||
|
||||
### The Epilogue
|
||||
|
||||
In 2013, we passed off the content and hosting of the site to a new maintainer. They have since redesigned it; it is accessible via the URL above, and at [EMCSpatriots.org](http://emcspatriots.org "EMCS Patriots").
|
||||
|
||||
<hidden-section heading="The Process">
|
||||
|
||||
Initially, we downloaded the content from their old site, and put it into a custom PHP-based framework. We then added a database of events, and a calendar page that read that database, enabling us to display multiple years, as well as future and past years. The design of the online information packet looked like a tabbed notebook, with each page highlighting a different tab.
|
||||
|
||||
In 2011, we switched the site to use ASP.NET MVC instead of the custom PHP solution, and migrated the data from MySQL to PostgreSQL; these efforts increased the performance of the site.
|
||||
|
||||
</app-hide-section>
|
53
bit-badger-solutions/content/solutions/futility-closet.md
Normal file
53
bit-badger-solutions/content/solutions/futility-closet.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
title: Futility Closet
|
||||
url: https://www.futilitycloset.com
|
||||
summary: An idler’s miscellany of compendious amusements
|
||||
category: WordPress
|
||||
frontPage:
|
||||
display: true
|
||||
order: 1
|
||||
text: An idler’s miscellany of compendious amusements
|
||||
technologies:
|
||||
- WordPress:
|
||||
for: blogging
|
||||
isCurrent: true
|
||||
- nginx:
|
||||
for: the web server
|
||||
isCurrent: true
|
||||
- MySQL:
|
||||
for: data storage
|
||||
isCurrent: true
|
||||
- Digital Ocean:
|
||||
for: web site hosting
|
||||
isCurrent: true
|
||||
- Azure:
|
||||
for: backup and recovery
|
||||
isCurrent: true
|
||||
- Rackspace Cloud:
|
||||
for: web site hosting
|
||||
---
|
||||
### The Client
|
||||
|
||||
Futility Closet exists as a place to give people a break from the dullness of work, by providing puzzles, anecdotes, and more. They also publish a weekly podcast highlighting “forgotten stories from the pages of history,” along with story updates and lateral thinking puzzles.
|
||||
|
||||
### The Problem
|
||||
|
||||
The site was running on a shared host, but was growing too large for that platform. The site had also suffered regular security breaches.
|
||||
|
||||
### The Solution
|
||||
|
||||
We architected an environment that would support a Reddit or Slashdot deluge of requests, and moved the site to an implementation of that environment. We continue to maintain that environment and back up data and files for the over 10,000 posts.
|
||||
|
||||
### The Business Impact
|
||||
|
||||
> <p class="quote">Bit Badger Solutions has been an absolute godsend for Futility Closet. We have been with them since 2010, initially setting up and maintaining the site on a Rackspace VPS, and then hosting it completely. Daniel’s never failed in being friendly, knowledgeable, thoughtful, and farsighted. I’ve literally lost count of the number of times he’s saved us from one emergency or another, always with diligence and good humor, or recommended an improvement or a protection that saved us later. We would be out of business many times over if it weren’t for his reliability, expertise, and good judgment. And he’s a joy to work with.</p>
|
||||
>
|
||||
> <p class="source"> — <strong>Greg Ross</strong>, Futility Closet</p>
|
||||
|
||||
<hidden-section heading="The Process">
|
||||
|
||||
In mid-2010, we obtained a backup of the previous site, and looked through it to ensure that none of the breaches had made any permanent changes to the site’s structure and data. We also locked down the new server (hosted on Rackspace Cloud) to only required protocols, training the client on SSH so that they could have access. We also stood up nginx as the front-end server, boosting performance significantly while requiring a much smaller server.
|
||||
|
||||
In 2015, we began hosting Futility Closet (using Digital Ocean).
|
||||
|
||||
</app-hide-section>
|
32
bit-badger-solutions/content/solutions/hard-corps-wife.md
Normal file
32
bit-badger-solutions/content/solutions/hard-corps-wife.md
Normal file
@ -0,0 +1,32 @@
|
||||
---
|
||||
title: Hard Corps Wife
|
||||
url: http://www.hardcorpswife.com
|
||||
summary: Cassy’s life as a Marine wife
|
||||
category: WordPress
|
||||
isInactive: true
|
||||
noLink: true
|
||||
frontPage:
|
||||
display: false
|
||||
technologies:
|
||||
- WordPress:
|
||||
for: blogging
|
||||
- MySQL:
|
||||
for: data storage
|
||||
- Rackspace Cloud:
|
||||
for: web site hosting
|
||||
---
|
||||
### The Client
|
||||
|
||||
Our existing client <nuxt-link to="/solutions/cassy-fiano" title="Cassy Fiano • Bit Badger Solutions">Cassy Fiano</nuxt-link>
|
||||
|
||||
### The Problem
|
||||
|
||||
Cassy (now Chesser) wanted a separate place from which to chronicle her experience as a military spouse.
|
||||
|
||||
### The Solution
|
||||
|
||||
In mid-2010, we set up her domain name, created a WordPress site, and customized the header and sidebar for her selected theme. We also hosted and maintained the site for the duration of its run.
|
||||
|
||||
### The Epilogue
|
||||
|
||||
In 2013, Cassy shifted priorities and closed this site down.
|
40
bit-badger-solutions/content/solutions/liberty-pundits.md
Normal file
40
bit-badger-solutions/content/solutions/liberty-pundits.md
Normal file
@ -0,0 +1,40 @@
|
||||
---
|
||||
title: Liberty Pundits
|
||||
url: http://libertypundits.net
|
||||
summary: The home for conservatives
|
||||
category: WordPress
|
||||
isInactive: true
|
||||
noLink: true
|
||||
frontPage:
|
||||
display: false
|
||||
technologies:
|
||||
- WordPress:
|
||||
for: blogging
|
||||
- PHP:
|
||||
for: custom data migration software
|
||||
- MySQL:
|
||||
for: data storage
|
||||
---
|
||||
### The Client
|
||||
|
||||
<nuxt-link to="/solutions/dr-melissa-clouthier" title="Dr. Melissa Clouthier • Bit Badger Solutions">Melissa Clouthier</nuxt-link>, Bill Dupray, and Clyde Middleton, all established conservative bloggers, started a joint venture called _Liberty Pundits_.
|
||||
|
||||
### The Problem
|
||||
|
||||
Bill and Clyde had a significant amount of content on a prior site. As they were starting this with established authors, they needed a site that would handle their expected traffic spikes on popular posts.
|
||||
|
||||
### The Solution
|
||||
|
||||
In early 2010, we migrated their content from a custom solution into WordPress’s database; we then set them up on the same host where their podcast was being distributed. However, the combination of theme complexity and traffic overwhelmed that server, so we configured a standalone server with more memory and more efficient software; this allowed them to routinely eclipse 100,000 views per day, most of those coming on posts within the first few hours.
|
||||
|
||||
### The Epilogue
|
||||
|
||||
The site closed in late 2011, as its authors closed their joint venture and moved on to other sites and topics.
|
||||
|
||||
<hidden-section heading="The Process">
|
||||
|
||||
Before we could migrate the data from _Patriot Room_, Bill and Clyde’s prior home, we had to get into the server and determine how data was stored in the custom solution. Once we identified where all the data was, we wrote a custom migration script to shape the data the way WordPress needed it.
|
||||
|
||||
Bit Badger Solutions maintained the server, keeping it current with performance and security upgrades. We also provided support to the primary 3 bloggers, when they had questions about WordPress or how the site was performing.
|
||||
|
||||
</hidden-section>
|
10
bit-badger-solutions/content/solutions/linux-resources.md
Normal file
10
bit-badger-solutions/content/solutions/linux-resources.md
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
title: Linux Resources
|
||||
url: https://blog.bitbadger.solutions/linux/
|
||||
category: Web Sites and Applications
|
||||
noAboutLink: true
|
||||
frontPage:
|
||||
display: true
|
||||
order: 3
|
||||
text: Handy information for Linux folks
|
||||
---
|
53
bit-badger-solutions/content/solutions/mindy-mackenzie.md
Normal file
53
bit-badger-solutions/content/solutions/mindy-mackenzie.md
Normal file
@ -0,0 +1,53 @@
|
||||
---
|
||||
title: Mindy Mackenzie
|
||||
url: https://mindymackenzie.com
|
||||
summary: <em>Wall Street Journal</em> best-selling author and C-suite advisor
|
||||
category: WordPress
|
||||
frontPage:
|
||||
display: true
|
||||
order: 2
|
||||
text: WSJ-best-selling author of The Courage Solution
|
||||
technologies:
|
||||
- WordPress:
|
||||
for: blogging and content management
|
||||
isCurrent: true
|
||||
- nginx:
|
||||
for: the web server
|
||||
isCurrent: true
|
||||
- MySQL:
|
||||
for: data storage
|
||||
isCurrent: true
|
||||
- Digital Ocean:
|
||||
for: web site hosting
|
||||
isCurrent: true
|
||||
- Azure:
|
||||
for: backup and recovery
|
||||
isCurrent: true
|
||||
---
|
||||
### The Client
|
||||
|
||||
Mindy Mackenzie, the prior Chief Performance Officer of Beam, Inc., is known as the “Velvet Hammer” for her tough-yet-caring style of leadership. She is a _Wall Street Journal_ best-selling author of the book _The Courage Solution: The Power of Truth-Telling with Your Boss, Peers, and Team_, and the creator and host of the annual _You First Integrative Leadership Summit_, equipping women of influence to reach even greater heights.
|
||||
|
||||
### The Problem
|
||||
|
||||
Mindy was dissatisfied with the value she was receiving with her current web designer and host; in advance of her book launch, she needed a more responsive site that could easily be updated.
|
||||
|
||||
### The Solution
|
||||
|
||||
We took over hosting her site, updating it regularly for the book launch, and highlighting her media appearances in conjunction with that launch. We also created and continue to maintain the pages for her _You First Integrative Leadership Summit_, including online registration.
|
||||
|
||||
### The Business Impact
|
||||
|
||||
> <p class="quote">Daniel is the best partner you could hope for in a web designer and for handling web maintenance! He is smart, creative, resourceful and fast. Daniel is able to produce high quality work on short time frames and with minimal creative direction and hit the mark over and over. The best part, is Daniel is a joy to work with. He is smart, customer-centric and trustworthy. If he says he will get it done, he does. After having a poor experience with another firm, I can highly recommend Daniel for all your website design and support needs – he’s terrific!</p>
|
||||
>
|
||||
> <p class="source"> — <strong>Mindy Mackenzie</strong></p>
|
||||
|
||||
<hidden-section heading="The Process">
|
||||
|
||||
In late 2015, We assumed maintenance of her site several months in advance of the book launch. We created a custom WordPress type to highlight her Media Appearances, automatically ordered from most recent to older. She had a lot of short video content, and we implemented code that displays a different video each week on the front page.
|
||||
|
||||
In early 2018, we developed the pages for her _You First Integrative Leadership Summit_, with speaker bios, conference schedule, and an application form. We have continued to maintain these pages across the 2019 and 2020 summits.
|
||||
|
||||
We continue to provide backups, WordPress support, and content updates for Mindy’s site.
|
||||
|
||||
</app-hide-section>
|
43
bit-badger-solutions/content/solutions/my-prayer-journal.md
Normal file
43
bit-badger-solutions/content/solutions/my-prayer-journal.md
Normal file
@ -0,0 +1,43 @@
|
||||
---
|
||||
title: myPrayerJournal
|
||||
url: https://prayerjournal.me
|
||||
summary: Minimalist personal prayer journal
|
||||
category: Web Sites and Applications
|
||||
frontPage:
|
||||
display: true
|
||||
order: 2
|
||||
text: Minimalist personal prayer journal
|
||||
technologies:
|
||||
- Vue.js:
|
||||
for: the front-end
|
||||
isCurrent: true
|
||||
- Giraffe:
|
||||
for: the back-end data API
|
||||
isCurrent: true
|
||||
- RavenDB:
|
||||
for: data storage
|
||||
isCurrent: true
|
||||
- GitHub:
|
||||
for: source code control
|
||||
isCurrent: true
|
||||
- GitHub Pages:
|
||||
for: documentation
|
||||
isCurrent: true
|
||||
- PostgreSQL:
|
||||
for: data storage
|
||||
---
|
||||
### The Problem
|
||||
|
||||
Daniel wanted to maintain a prayer journal, where he could record the prayer requests for which he had prayed, and the answer that eventually came to that request. He didn’t want to do that on paper for several reasons – it's easy to lose, a long-running request can run out of space to make notes, etc.
|
||||
|
||||
### The Solution
|
||||
|
||||
We created a site where users can enter requests, pray through lists of these requests, make notes on them, and follow them through until they are answered. The site stores no identifying information, and works well on both desktop and mobile. Bit Badger Solutions hosts and maintains the instance of the site linked above.
|
||||
|
||||
<hidden-section heading="The Process">
|
||||
|
||||
Development of myPrayerJournal began in earnest in early 2017. As we were using this to learn new techniques, we ended up trying a host of different front and back end technologies before settling on Vue.js for the front end and Giraffe for the back end. This combination works well, and we wrote up an 8-post series entitled ["A Tour of myPrayerJournal"](https://blog.bitbadger.solutions/2018/a-tour-of-myprayerjournal/introduction.html "A Tour of myPrayerJournal: Introduction | The Bit Badger Blog") over on the _Bit Badger Blog_ that steps through all aspects of version 1 of this application.
|
||||
|
||||
Version 2 changed to a Material Design interface, and we changed the data store from PostgreSQL to RavenDB, an excellent document database. As this is an open-source project, anyone can review the source code on [GitHub](https://github.com/bit-badger/myPrayerJournal); we also track open issues there.
|
||||
|
||||
</app-hide-section>
|
36
bit-badger-solutions/content/solutions/nsx.md
Normal file
36
bit-badger-solutions/content/solutions/nsx.md
Normal file
@ -0,0 +1,36 @@
|
||||
---
|
||||
title: "Not So Extreme Makeover: Community Edition"
|
||||
url: http://notsoextreme.org
|
||||
summary: Public site for the makeover; provides event-driven management of volunteers, donations, and families needing help
|
||||
category: Web Sites and Applications
|
||||
isInactive: true
|
||||
noLink: true
|
||||
linkToArchive: true
|
||||
archiveUrl: https://nsx.archive.bitbadger.solutions
|
||||
frontPage:
|
||||
display: false
|
||||
technologies:
|
||||
- WordPress:
|
||||
for: content management
|
||||
- PHP:
|
||||
for: NSXapp
|
||||
- MySQL:
|
||||
for: WordPress data storage
|
||||
- PostgreSQL:
|
||||
for: NSXapp data storage
|
||||
---
|
||||
### The Client
|
||||
|
||||
In January 2008, a few members of [Hoffmantown Church](https://www.hoffmantownchurch.org "Hoffmantown Church • Albuquerque, New Mexico") in Albuquerque, New Mexico had an idea. The ABC show _[Extreme Makeover: Home Edition](http://abc.go.com/shows/extreme-makeover-home-edition)_ had just done [a build for a pastor in the “war zone” area of town](http://abc.go.com/shows/extreme-makeover-home-edition/episode-detail/martinez-family/224884 "Martinez Family • Extreme Makeover: Home Edition"), and this brought attention to Gerald Martinez and the work he had done to help clean up this area of town. Through [Love INC of South Albuquerque](http://www.loveincabq.org/ "Love INC of South Albuquerque"), they learned that there were many other homes in that area that could use the “Ty Pennington touch.” While the goal was not to knock down homes and build new ones, the goal was no less extreme. The goal of the “Not So Extreme Makeover: Community Edition” was to help 50 families in 5 days during spring break week in 2008.
|
||||
|
||||
### The Problem
|
||||
|
||||
An effort of this magnitude, happening this quickly, would be unmanageable without software support. It would also require a lot of paperwork, and a lot of people processing that paperwork.
|
||||
|
||||
### The Solution
|
||||
|
||||
We obtained the domain name and stood up the public website quickly using WordPress, which also allowed the coordinators to put content up. We then developed an application (NSXapp) where volunteers could sign up for “X Week”, with over 80 different skill, talent, and ability categories. We then created a way to identify families and their needs, and a place for people with donations to let us know what they would be. From there, we created the ability to begin matching needs with goods (stuff) and abilities (people), organizing the stuff into donated trailers and people into teams. During X Week, NSXapp generated schedules and reports that were used to help guide the teams as they executed their projects.
|
||||
|
||||
### The Epilogue
|
||||
|
||||
From an idea in January, “Not So Extreme Makeover: Community Edition” was able to help 57 families by the end of X Week on March 29th. When Love INC saw how NSXapp worked, they expressed an interest in a version that would allow them to handle these same areas on an ongoing basis; this became <nuxt-link to="/solutions/tcms" title="The Clearinghouse Management System (TCMS) • Bit Badger Solutions">TCMS</nuxt-link>. Finally, there is a [snapshot of the NSX public site](https://nsx.archive.bitbadger.solutions) that serves as a record of those three months in 2008.
|
46
bit-badger-solutions/content/solutions/olivet-baptist.md
Normal file
46
bit-badger-solutions/content/solutions/olivet-baptist.md
Normal file
@ -0,0 +1,46 @@
|
||||
---
|
||||
title: Olivet Baptist Church
|
||||
url: https://olivet-baptist.org
|
||||
summary: Southern Baptist church in Gulfport, Mississippi
|
||||
category: Static Sites
|
||||
isInactive: true
|
||||
noLink: true
|
||||
linkToArchive: true
|
||||
archiveUrl: https://olivet.archive.bitbadger.solutions
|
||||
frontPage:
|
||||
display: false
|
||||
technologies:
|
||||
- Vue.js:
|
||||
for: the user interface for the PWA
|
||||
- Hexo:
|
||||
for: generating the site's pages
|
||||
- Azure:
|
||||
for: podcast file storage and archive site hosting
|
||||
- WordPress:
|
||||
for: content management
|
||||
- MySQL:
|
||||
for: data storage
|
||||
---
|
||||
### The Client
|
||||
|
||||
Olivet Baptist Church was a Southern Baptist church in Gulfport, Mississippi, who had seen our work with <nuxt-link to="/solutions/bay-vista" title="Bay Vista Baptist Church • Bit Badger Solutions">Bay Vista</nuxt-link> and wanted something similar.
|
||||
|
||||
### The Problem
|
||||
|
||||
Olivet had no online presence.
|
||||
|
||||
### The Solution
|
||||
|
||||
Initially, we set up a WordPress site, configured it, and established a podcast feed; we also advised them on how to register that feed in iTunes. A few years later, we converted the site to behave like an app, where it could be installed as an icon, allowing quick access.
|
||||
|
||||
### The Epilogue
|
||||
|
||||
When the church closed its doors on February 24th, 2019, we converted the app-behaving site back to a static web site, set up an archive site, and worked with their personnel to ensure that the podcast links are all still available. We continue to host that archive site and podcast content.
|
||||
|
||||
<hidden-section heading="The Process">
|
||||
|
||||
In 2014, we registered the domain name for the church. They had expressed a desire to do as much of the content of the site themselves, so we supported them as they worked through its initial setup. After the site was originally set up, though, updates were rare (apart from the weekly podcast episodes), so we converted it to be a statically-generated site.
|
||||
|
||||
In 2018, we modified the site to be a Progressive Web Application (PWA), which allows users to “install” the site, like an app, to their phone’s home screen. The site was also still accessible from the web via a browser. We converted the static content to generate page fragments that the PWA would load, providing the same navigation experience as before.
|
||||
|
||||
</hidden-section>
|
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: Photography by Michelle
|
||||
url: https://www.summershome.org
|
||||
summary: Photography services in Albuquerque, New Mexico
|
||||
category: Web Sites and Applications
|
||||
isInactive: true
|
||||
frontPage:
|
||||
display: false
|
||||
technologies:
|
||||
- ASP.NET MVC:
|
||||
for: content management / gallery creation API
|
||||
- PostgreSQL:
|
||||
for: data storage
|
||||
- C# / Windows Forms:
|
||||
for: desktop gallery application
|
||||
- WordPress:
|
||||
for: content management
|
||||
- MySQL:
|
||||
for: data storage
|
||||
---
|
||||
### The Client
|
||||
|
||||
Michelle Summers had been photographing her children for years. When her sons were on sports teams, she was disappointed with the cost of team photography, and felt that she could do a better job at a lower cost. She specialized in outdoor photography of families, children, and sports teams, as well as maternity photography and holiday cards.
|
||||
|
||||
### The Problem
|
||||
|
||||
Michelle needed a site to showcase her previous work, as well as a place to allow her customers to view their proofs before selecting prints.
|
||||
|
||||
### The Solution
|
||||
|
||||
We created a WordPress site with image galleries for her existing work, and utilized a custom plug-in to support online proofs. This site was eventually replaced with one that had a matching Windows application; this application took a set of photos, resized them, applied a watermark, and created the proof gallery without having to even go to the site.
|
||||
|
||||
### The Epilogue
|
||||
|
||||
As Michelle is no longer doing professional photography, the current version of this site is a simple thank-you to her customers from 2007-2014.
|
50
bit-badger-solutions/content/solutions/prayer-tracker.md
Normal file
50
bit-badger-solutions/content/solutions/prayer-tracker.md
Normal file
@ -0,0 +1,50 @@
|
||||
---
|
||||
title: PrayerTracker
|
||||
url: https://prayer.bitbadger.solutions
|
||||
summary: Provides an ongoing, centralized prayer list for Sunday School classes and other groups
|
||||
category: Web Sites and Applications
|
||||
frontPage:
|
||||
display: true
|
||||
order: 1
|
||||
text: A prayer request tracking website (Free for any church or Sunday School class!)
|
||||
technologies:
|
||||
- Giraffe:
|
||||
for: server-side logic and dynamic page generation
|
||||
isCurrent: true
|
||||
- PostgreSQL:
|
||||
for: data storage
|
||||
isCurrent: true
|
||||
- GitHub:
|
||||
for: source code control
|
||||
isCurrent: true
|
||||
- GitHub Pages:
|
||||
for: documentation hosting
|
||||
isCurrent: true
|
||||
- MongoDB:
|
||||
for: data storage
|
||||
- ASP.NET MVC:
|
||||
for: dynamic content generation
|
||||
- Database Abstraction:
|
||||
for: data access
|
||||
- MySQL:
|
||||
for: data storage
|
||||
- PHP:
|
||||
for: dynamic content generation
|
||||
---
|
||||
### The Problem
|
||||
|
||||
Back in 2005, Daniel was responsible for keeping up with prayer requests for his Sunday School class. However, simply sending out a mass e-mail has some significant drawbacks - everyone’s e-mail address is visible to everyone else; mass e-mails are more likely to be flagged as suspicious; and it is difficult to have a single “latest and greatest” list of members.
|
||||
|
||||
### The Solution
|
||||
|
||||
We wrote a site so we could enter prayer requests and class members; this site would then send individual e-mails to each member. When requests were 15 days old, they would drop off the list. From there, PrayerTracker has grown to support multiple churches and groups within those churches, and the user interface is available in both English _y Español_. Bit Badger Solutions offers use of this site for free to any church, Sunday School class, or small group that desires a tool to help them establish a continuous list of prayer requests.
|
||||
|
||||
<hidden-section heading="The Process">
|
||||
|
||||
The first reimagining of PrayerTracker occurred in 2011; this was when we moved to a more modern (at the time) framework (ASP MVC 3), building in the multi-church/multi-group security additions, and posturing it for an interface with <nuxt-link to="/solutions/virtual-prayer-room" title="Virtual Prayer Room • Bit Badger Solutions">Virtual Prayer Room</nuxt-link>. A year later, a visiting missionary saw the site and liked it, but needed the site (including the online help) in Spanish; we released version 4 a few months later which brought this support.
|
||||
|
||||
In late 2014, version 5 moved to a MongoDB data store, as we had some problems with columns not being large enough for some requests. In early 2017, we released version 6, which took PrayerTracker into the .NET Core environment; we also moved the data back to PostgreSQL, as it now supported the sizes we needed.
|
||||
|
||||
Version 7 was released in mid-2018, bringing full mobile accessibility and an upgrade to a modern, ultra-fast web framework (Giraffe). In early 2019, version 7.1 was the first release for PrayerTracker as an [open source project](https://github.com/bit-badger/PrayerTracker). Right on its heels, version 7.2 moved the embedded help files to GitHub Pages; this made the web application more streamlined.
|
||||
|
||||
</hidden-section>
|
30
bit-badger-solutions/content/solutions/riehl-world-news.md
Normal file
30
bit-badger-solutions/content/solutions/riehl-world-news.md
Normal file
@ -0,0 +1,30 @@
|
||||
---
|
||||
title: Riehl World News
|
||||
url: http://riehlworldview.com
|
||||
summary: Riehl news for real people
|
||||
category: WordPress
|
||||
frontPage:
|
||||
display: true
|
||||
order: 3
|
||||
text: Riehl news for real people
|
||||
technologies:
|
||||
- WordPress:
|
||||
for: blogging
|
||||
isCurrent: true
|
||||
- MySQL:
|
||||
for: data storage
|
||||
isCurrent: true
|
||||
- F#:
|
||||
for: custom archive static page generation
|
||||
---
|
||||
### The Client
|
||||
|
||||
Dan Riehl began blogging as _The Carnivorous Conservative_ back in 2004, specializing in the areas of crime and politics. He changed to _Riehl World View_ a short time later, and writes both news and opinion pieces. He was a prolific blogger, publishing over 15 posts a day on most days.
|
||||
|
||||
### The Problem
|
||||
|
||||
He wanted to take his blog in a different direction, and was having trouble getting his Movable Type blog to move with him.
|
||||
|
||||
### The Solution
|
||||
|
||||
We stood up a WordPress site on a server he procured. We then assisted him in selecting a theme and customized it to his liking. Finally, we wrote custom migration code to get his past body of work into the new site. In 2018, we generated static files for most of his prior posts, to give him a clean slate for a new direction. We continue to maintain and support _Riehl World News_.
|
34
bit-badger-solutions/content/solutions/tcms.md
Normal file
34
bit-badger-solutions/content/solutions/tcms.md
Normal file
@ -0,0 +1,34 @@
|
||||
---
|
||||
title: The Clearinghouse Management System
|
||||
url: http://tcms.us
|
||||
summary: Assists a needs clearinghouse in connecting people with needs to people that can help meet those needs
|
||||
category: Web Sites and Applications
|
||||
isInactive: true
|
||||
noLink: true
|
||||
frontPage:
|
||||
display: false
|
||||
technologies:
|
||||
- PHP:
|
||||
for: the TCMS application logic
|
||||
- WordPress:
|
||||
for: publicly-facing pages and authentication
|
||||
- PostgreSQL:
|
||||
for: application data storage
|
||||
- MySQL:
|
||||
for: WordPress data storage
|
||||
---
|
||||
### The Client
|
||||
|
||||
Love INC of South Albuquerque runs a “needs clearinghouse”; they have volunteers who accept donations, and people contact them with their needs. They are then able to match the person who needs something with that thing, or with someone who can assist them.
|
||||
|
||||
### The Problem
|
||||
|
||||
The files in their offices were multiplying; ensuring people’s needs are not missed, while ensuring that their clients were not taking advantage of their services, required a lot of paper. They were tracking volunteers on a spreadsheet, but their contact info was in yet another file. Having worked with us on the <nuxt-link to="/solutions/nsx" title="Not So Extreme Makeover: Community Edition • Bit Badger Solutions">“Not So Extreme Makeover: Community Edition”</nuxt-link>, and thought that the solution we developed for that project would help them.
|
||||
|
||||
### The Solution
|
||||
|
||||
We adapted NSXapp to handle an ongoing stream of people, volunteers, and donations. This enabled them to spend more time with the people who needed help. The WordPress front end also served as their public website, and allowed them to manage the volunteers who were using the system.
|
||||
|
||||
### The Epilogue
|
||||
|
||||
Love INC of South Albuquerque found a SalesForce system that would do things very similar to TCMS, and was able to get in on a program that let them use it at no cost; TCMS was decommissioned in 2014.
|
55
bit-badger-solutions/content/solutions/tech-blog.md
Normal file
55
bit-badger-solutions/content/solutions/tech-blog.md
Normal file
@ -0,0 +1,55 @@
|
||||
---
|
||||
title: The Bit Badger Blog
|
||||
url: https://blog.bitbadger.solutions
|
||||
summary: Geek stuff from Bit Badger Solutions
|
||||
category: Static Sites
|
||||
frontPage:
|
||||
display: true
|
||||
order: 3
|
||||
text: Technical information (“geek stuff”) from Bit Badger Solutions
|
||||
technologies:
|
||||
- Hexo:
|
||||
for: static site generation
|
||||
isCurrent: true
|
||||
- Azure:
|
||||
for: static site hosting
|
||||
isCurrent: true
|
||||
- GitHub:
|
||||
for: source code control
|
||||
isCurrent: true
|
||||
- Custom software:
|
||||
for: content management
|
||||
- WordPress:
|
||||
for: content management
|
||||
- BlogEngine.NET:
|
||||
for: content management
|
||||
- Orchard:
|
||||
for: content management
|
||||
- myWebLog:
|
||||
for: content management
|
||||
- Jekyll:
|
||||
for: static site generation
|
||||
- MySQL:
|
||||
for: data storage
|
||||
- SQL Server:
|
||||
for: data storage
|
||||
- RethinkDB:
|
||||
for: data storage
|
||||
---
|
||||
### The Problem
|
||||
|
||||
Daniel needed a place to journal his learning journey with the Linux operating system, and thought that allowing others read this journal would help them learn as well.
|
||||
|
||||
### The Solution
|
||||
|
||||
_The Bit Badger Blog_ contains that journal, plus tech tips and information for many different aspects of technology. It is written, maintained, and hosted by Bit Badger Solutions.
|
||||
|
||||
<hidden-section heading="The Process">
|
||||
|
||||
The initial posts were titled “My Linux Adventure,” and existed as static files that were edited to add each post. Daniel then wrote a rudimentary system that stored the posts in a database, which meant that the entire site did not need manual changes – what a breakthrough! :)
|
||||
|
||||
Over time, the _Bit Badger Blog_ (and the _DJS Consulting Tech Blog_ before it) has served as a place to support _(now inactive)_ WordPress plug-ins, and go in depth on servers, databases, programming languages, and open-source software. It has also served as a useful live website for learning and experimentation with different content management systems and blogging tools. It has existed in at least 8 different tools, with links preserved as systems change.
|
||||
|
||||
It is currently a statically-generated site, utilizing [Hexo](https://hexo.io), and its code is [open source](https://github.com/bit-badger/blog.bitbadger.solutions). New posts are infrequent, but the information it has is good. It may have more behind-the-scenes posts about future open-source efforts. Stay tuned!
|
||||
|
||||
</hidden-section>
|
28
bit-badger-solutions/content/solutions/the-shark-tank.md
Normal file
28
bit-badger-solutions/content/solutions/the-shark-tank.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
title: The Shark Tank
|
||||
url: http://shark-tank.net
|
||||
summary: Florida’s political feeding frenzy
|
||||
category: WordPress
|
||||
isInactive: true
|
||||
noLink: true
|
||||
frontPage:
|
||||
display: false
|
||||
technologies:
|
||||
- WordPress:
|
||||
for: blogging
|
||||
---
|
||||
### The Client
|
||||
|
||||
_The Shark Tank_ is a news and opinion site centered on south Florida politics (and the state at large). They provided extensive coverage of Rep. Allen West’s winning campaign in 2010, and continue their focused news and opinion on current political races.
|
||||
|
||||
### The Problem
|
||||
|
||||
They were displeased with their current theme; it was struggling with the amount of content they were producing.
|
||||
|
||||
### The Solution
|
||||
|
||||
They had identified a theme that would better suit their needs. We set it up, ensuring that their content would fit in the new theme’s requirements, and helped them turn off parts that they didn’t need. We also converted the social media connections from their old site to a style that would work nicely in the new theme.
|
||||
|
||||
### The Epilogue
|
||||
|
||||
This was all they needed; they returned their focus to their writing.
|
@ -0,0 +1,30 @@
|
||||
---
|
||||
title: Virtual Prayer Room
|
||||
url: https://virtualprayerroom.us
|
||||
summary: Gives prayer warriors access to requests from wherever they may be, and sends them daily updates
|
||||
category: Web Sites and Applications
|
||||
isInactive: true
|
||||
noLink: true
|
||||
frontPage:
|
||||
display: false
|
||||
technologies:
|
||||
- PHP:
|
||||
for: the application logic
|
||||
- PostgreSQL:
|
||||
for: data storage
|
||||
---
|
||||
### The Client
|
||||
|
||||
Our existing client [Hoffmantown Church](http://hoffmantown.org "Hoffmantown Church • Albuquerque, New Mexico") in Albuquerque, New Mexico, with whom we had worked on the <nuxt-link to="/solutions/nsx/" title="Not So Extreme Makeover: Community Edition • Bit Badger Solutions">Not So Extreme Makeover: Community Edition</nuxt-link>
|
||||
|
||||
### The Problem
|
||||
|
||||
Hoffmantown had seen the use of this physical prayer room dwindling over the years. People had become less willing to drive to the church, especially at night, and security became an issue as well; either prayer warriors had to know how to disable the security system, or the church would have to remain unlocked.
|
||||
|
||||
### The Solution
|
||||
|
||||
The development of Virtual Prayer Room extended the prayer room to anywhere a prayer warrior can get an Internet connection! Prayer warriors could enlist right from the site, and had to be approved. Requests and updates were tracked by date/time, and warriors could record when they’ve prayed for a request from the site, or from clicking a link in the daily e-mail they received with requests from their interest areas. As many prayer needs are confidential, security and confidentiality were very important. Virtual Prayer Room ensured these by providing varying security levels for prayer warriors and the ability to mark each request as confidential.
|
||||
|
||||
### The Epilogue
|
||||
|
||||
In 2016, Hoffmantown Church elected to begin using another package for their prayer requests. While a few other churches had expressed interest in it, none ultimately decided to use it; so, in 2017, Virtual Prayer Room was officially decommissioned.
|
@ -1,32 +0,0 @@
|
||||
// @ts-check
|
||||
// Protractor configuration file, see link for more information
|
||||
// https://github.com/angular/protractor/blob/master/lib/config.ts
|
||||
|
||||
const { SpecReporter } = require('jasmine-spec-reporter');
|
||||
|
||||
/**
|
||||
* @type { import("protractor").Config }
|
||||
*/
|
||||
exports.config = {
|
||||
allScriptsTimeout: 11000,
|
||||
specs: [
|
||||
'./src/**/*.e2e-spec.ts'
|
||||
],
|
||||
capabilities: {
|
||||
browserName: 'chrome'
|
||||
},
|
||||
directConnect: true,
|
||||
baseUrl: 'http://localhost:4200/',
|
||||
framework: 'jasmine',
|
||||
jasmineNodeOpts: {
|
||||
showColors: true,
|
||||
defaultTimeoutInterval: 30000,
|
||||
print: function() {}
|
||||
},
|
||||
onPrepare() {
|
||||
require('ts-node').register({
|
||||
project: require('path').join(__dirname, './tsconfig.json')
|
||||
});
|
||||
jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } }));
|
||||
}
|
||||
};
|
@ -1,23 +0,0 @@
|
||||
import { AppPage } from './app.po';
|
||||
import { browser, logging } from 'protractor';
|
||||
|
||||
describe('workspace-project App', () => {
|
||||
let page: AppPage;
|
||||
|
||||
beforeEach(() => {
|
||||
page = new AppPage();
|
||||
});
|
||||
|
||||
it('should display welcome message', () => {
|
||||
page.navigateTo();
|
||||
expect(page.getTitleText()).toEqual('bit-badger-solutions app is running!');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
// Assert that there are no errors emitted from the browser
|
||||
const logs = await browser.manage().logs().get(logging.Type.BROWSER);
|
||||
expect(logs).not.toContain(jasmine.objectContaining({
|
||||
level: logging.Level.SEVERE,
|
||||
} as logging.Entry));
|
||||
});
|
||||
});
|
@ -1,11 +0,0 @@
|
||||
import { browser, by, element } from 'protractor';
|
||||
|
||||
export class AppPage {
|
||||
navigateTo() {
|
||||
return browser.get(browser.baseUrl) as Promise<any>;
|
||||
}
|
||||
|
||||
getTitleText() {
|
||||
return element(by.css('app-root .content span')).getText() as Promise<string>;
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/e2e",
|
||||
"module": "commonjs",
|
||||
"target": "es2018",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"jasminewd2",
|
||||
"node"
|
||||
]
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma')
|
||||
],
|
||||
client: {
|
||||
clearContext: false // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, './coverage/bit-badger-solutions'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true
|
||||
});
|
||||
};
|
111
bit-badger-solutions/layouts/default.vue
Normal file
111
bit-badger-solutions/layouts/default.vue
Normal file
@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div>
|
||||
<PageHeader />
|
||||
<Nuxt />
|
||||
<PageFooter />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
export default Vue.extend({
|
||||
head () {
|
||||
return {
|
||||
link: [
|
||||
{ rel: 'stylesheet',
|
||||
href: 'https://fonts.googleapis.com/css?family=Oswald|Raleway'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
html {
|
||||
background-color: lightgray;
|
||||
}
|
||||
body {
|
||||
margin: 0px;
|
||||
font-family: "Raleway", "Segoe UI", Ubuntu, Tahoma, "DejaVu Sans", "Liberation Sans", Arial, sans-serif;
|
||||
background-color: #FFFAFA;
|
||||
}
|
||||
a {
|
||||
color: navy;
|
||||
text-decoration: none;
|
||||
}
|
||||
a:hover {
|
||||
border-bottom: dotted 1px navy;
|
||||
}
|
||||
a img {
|
||||
border: 0;
|
||||
}
|
||||
acronym {
|
||||
border-bottom: dotted 1px black;
|
||||
}
|
||||
header, h1, h2, h3, footer a {
|
||||
font-family: "Oswald", "Segoe UI", Ubuntu, "DejaVu Sans", "Liberation Sans", Arial, sans-serif;
|
||||
}
|
||||
h1 {
|
||||
text-align: center;
|
||||
margin: 1.4rem 0;
|
||||
font-size: 2rem;
|
||||
}
|
||||
h2 {
|
||||
margin: 1.2rem 0;
|
||||
}
|
||||
h3 {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
h2, h3 {
|
||||
border-bottom: solid 2px navy;
|
||||
}
|
||||
@media all and (min-width:40rem) {
|
||||
h2, h3 {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
p {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
#content {
|
||||
margin: 0 1rem;
|
||||
}
|
||||
.content {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
.auto {
|
||||
margin: 0 auto;
|
||||
}
|
||||
@media all and (min-width: 68rem) {
|
||||
.content {
|
||||
width: 66rem;
|
||||
}
|
||||
}
|
||||
.hdr {
|
||||
font-size: 14pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
.strike {
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.alignleft {
|
||||
float: left;
|
||||
padding-right: 5px;
|
||||
}
|
||||
ul {
|
||||
padding-left: 40px;
|
||||
}
|
||||
li {
|
||||
list-style-type: disc;
|
||||
}
|
||||
.app-info {
|
||||
display: flex;
|
||||
flex-flow: row-reverse wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
abbr[title] {
|
||||
text-decoration: none;
|
||||
border-bottom: dotted 1px rgba(0, 0, 0, .5)
|
||||
}
|
||||
</style>
|
71
bit-badger-solutions/nuxt.config.js
Normal file
71
bit-badger-solutions/nuxt.config.js
Normal file
@ -0,0 +1,71 @@
|
||||
|
||||
export default {
|
||||
/*
|
||||
** Nuxt rendering mode
|
||||
** See https://nuxtjs.org/api/configuration-mode
|
||||
*/
|
||||
mode: 'universal',
|
||||
/*
|
||||
** Nuxt target
|
||||
** See https://nuxtjs.org/api/configuration-target
|
||||
*/
|
||||
target: 'static',
|
||||
/*
|
||||
** Headers of the page
|
||||
** See https://nuxtjs.org/api/configuration-head
|
||||
*/
|
||||
head: {
|
||||
title: process.env.npm_package_name || '',
|
||||
meta: [
|
||||
{ charset: 'utf-8' },
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
{ hid: 'description', name: 'description', content: process.env.npm_package_description || '' }
|
||||
],
|
||||
link: [
|
||||
{ rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
|
||||
]
|
||||
},
|
||||
/*
|
||||
** Global CSS
|
||||
*/
|
||||
css: [
|
||||
],
|
||||
/*
|
||||
** Plugins to load before mounting the App
|
||||
** https://nuxtjs.org/guide/plugins
|
||||
*/
|
||||
plugins: [
|
||||
],
|
||||
/*
|
||||
** Auto import components
|
||||
** See https://nuxtjs.org/api/configuration-components
|
||||
*/
|
||||
components: true,
|
||||
/*
|
||||
** Nuxt.js dev-modules
|
||||
*/
|
||||
buildModules: [
|
||||
'@nuxt/typescript-build'
|
||||
],
|
||||
/*
|
||||
** Nuxt.js modules
|
||||
*/
|
||||
modules: [
|
||||
// Doc: https://github.com/nuxt/content
|
||||
'@nuxt/content'
|
||||
],
|
||||
/*
|
||||
** Content module configuration
|
||||
** See https://content.nuxtjs.org/configuration
|
||||
*/
|
||||
content: {
|
||||
liveEdit: false,
|
||||
nestedProperties: ['frontPage.display']
|
||||
},
|
||||
/*
|
||||
** Build configuration
|
||||
** See https://nuxtjs.org/api/configuration-build/
|
||||
*/
|
||||
build: {
|
||||
}
|
||||
}
|
13323
bit-badger-solutions/package-lock.json
generated
Normal file
13323
bit-badger-solutions/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,48 +1,28 @@
|
||||
{
|
||||
"name": "bit-badger-solutions",
|
||||
"version": "3.0.0",
|
||||
"scripts": {
|
||||
"ng": "ng",
|
||||
"start": "ng serve",
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
},
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "nuxt-ts",
|
||||
"build": "nuxt-ts build",
|
||||
"start": "nuxt-ts start",
|
||||
"generate": "nuxt-ts generate",
|
||||
"lint:js": "eslint --ext .js,.vue --ignore-path .gitignore .",
|
||||
"lint": "npm run lint:js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "~10.0.5",
|
||||
"@angular/common": "~10.0.5",
|
||||
"@angular/compiler": "~10.0.5",
|
||||
"@angular/core": "~10.0.5",
|
||||
"@angular/forms": "~10.0.5",
|
||||
"@angular/platform-browser": "~10.0.5",
|
||||
"@angular/platform-browser-dynamic": "~10.0.5",
|
||||
"@angular/router": "~10.0.5",
|
||||
"rxjs": "~6.5.5",
|
||||
"tslib": "^2.0.0",
|
||||
"zone.js": "~0.10.2"
|
||||
"@nuxt/content": "^1.5.0",
|
||||
"@nuxt/typescript-runtime": "^1.0.0",
|
||||
"nuxt": "^2.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-devkit/build-angular": "~0.1000.4",
|
||||
"@angular-devkit/schematics": "^10.0.4",
|
||||
"@angular/cli": "~10.0.4",
|
||||
"@angular/compiler-cli": "~10.0.5",
|
||||
"@angular/language-service": "~10.0.5",
|
||||
"@types/jasmine": "~3.3.8",
|
||||
"@types/jasminewd2": "~2.0.3",
|
||||
"@types/node": "^12.11.1",
|
||||
"codelyzer": "^6.0.0",
|
||||
"jasmine-core": "~3.5.0",
|
||||
"jasmine-spec-reporter": "~5.0.0",
|
||||
"karma": "~5.0.0",
|
||||
"karma-chrome-launcher": "~3.1.0",
|
||||
"karma-coverage-istanbul-reporter": "~3.0.2",
|
||||
"karma-jasmine": "~3.3.0",
|
||||
"karma-jasmine-html-reporter": "^1.5.0",
|
||||
"protractor": "~7.0.0",
|
||||
"ts-node": "~7.0.0",
|
||||
"tslint": "~6.1.0",
|
||||
"typescript": "~3.9.7"
|
||||
"@nuxt/types": "^2.14.0",
|
||||
"@nuxt/typescript-build": "^2.0.2",
|
||||
"@nuxtjs/eslint-config": "^3.1.0",
|
||||
"@nuxtjs/eslint-config-typescript": "^3.0.0",
|
||||
"@nuxtjs/eslint-module": "^2.0.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^7.5.0",
|
||||
"eslint-plugin-nuxt": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
28
bit-badger-solutions/pages/about/_slug.vue
Normal file
28
bit-badger-solutions/pages/about/_slug.vue
Normal file
@ -0,0 +1,28 @@
|
||||
<template>
|
||||
<article class="content auto">
|
||||
<h1 v-html="page.title" />
|
||||
<nuxt-content :document="page" />
|
||||
<p><br><nuxt-link to="/" title="Home">« Home</nuxt-link></p>
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import { siteTitle } from '../index.vue'
|
||||
|
||||
export default Vue.extend({
|
||||
async asyncData ({ $content, params }) {
|
||||
const page = await $content(`about/${params.slug}`).fetch()
|
||||
return { page }
|
||||
},
|
||||
head () {
|
||||
return { title: siteTitle((this as any).page.title) }
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
li {
|
||||
margin-bottom: .8rem;
|
||||
}
|
||||
</style>
|
53
bit-badger-solutions/pages/index.vue
Normal file
53
bit-badger-solutions/pages/index.vue
Normal file
@ -0,0 +1,53 @@
|
||||
<template>
|
||||
<div class="home">
|
||||
<article class="content auto">
|
||||
<nuxt-content :document="home" />
|
||||
</article>
|
||||
<home-sidebar :cat-names="catNames" :solutions="slns" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
|
||||
export default Vue.extend({
|
||||
async asyncData ({ $content }) {
|
||||
const home = await $content('home').fetch()
|
||||
|
||||
const cats: {category: string}[] = await $content('solutions').only(['category']).fetch()
|
||||
const catNames = [...new Set(cats.map(x => x.category))]
|
||||
|
||||
const slns = await $content('solutions').where({ 'frontPage.display': true }).fetch()
|
||||
|
||||
return { home, catNames, slns }
|
||||
},
|
||||
head () {
|
||||
return { title: siteTitle('Welcome!') }
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Construct a title for the site
|
||||
*
|
||||
* @param pageTitle The title of the page
|
||||
* @returns The page title, with the site title appended
|
||||
*/
|
||||
export function siteTitle (pageTitle: string) {
|
||||
return `${pageTitle} « Bit Badger Solutions`
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@media all and (min-width: 80rem) {
|
||||
.home {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
align-items: flex-start;
|
||||
justify-content: space-around;
|
||||
}
|
||||
}
|
||||
.home-lead {
|
||||
font-size: 1.3rem;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
139
bit-badger-solutions/pages/solutions/_id/index.vue
Normal file
139
bit-badger-solutions/pages/solutions/_id/index.vue
Normal file
@ -0,0 +1,139 @@
|
||||
<template>
|
||||
<section>
|
||||
<h1>
|
||||
{{ solution.title }}<br>
|
||||
<small><small>
|
||||
<a v-if="!solution.noLink" :href="solution.url" target="_blank">{{ solution.url }}</a>
|
||||
<span v-else>{{ solution.url }}</span>
|
||||
<span v-if="solution.linkToArchive">
|
||||
<a :href="solution.archiveUrl"><small>(Archive)</small></a>
|
||||
</span>
|
||||
</small></small>
|
||||
</h1>
|
||||
<div class="app-info">
|
||||
<article class="content">
|
||||
<aside>
|
||||
<span> </span>
|
||||
<img :src="`/screenshots/${solution.slug}.png`" :alt="`Screen shot of ${solution.title}`">
|
||||
</aside>
|
||||
<nuxt-content :document="solution" />
|
||||
<hidden-section v-if="hasTechStack" heading="The Technology Stack" class="tech-stack">
|
||||
<template v-if="hasCurrent">
|
||||
<p v-if="hasCurrent && hasPrevious">
|
||||
<small><strong>Current:</strong></small>
|
||||
</p>
|
||||
<ul>
|
||||
<technology-item v-for="tech in currentTech" :key="tech[0]" :tech="tech" />
|
||||
</ul>
|
||||
</template>
|
||||
<template v-if="hasPrevious">
|
||||
<p v-if="hasCurrent && hasPrevious">
|
||||
<small><strong>Previously:</strong></small>
|
||||
</p>
|
||||
<ul>
|
||||
<technology-item v-for="tech in previousTech" :key="tech[0]" :tech="tech" />
|
||||
</ul>
|
||||
</template>
|
||||
</hidden-section>
|
||||
<p><br><nuxt-link to="/solutions">« Back to All Solutions</nuxt-link></p>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import { siteTitle } from '../../index.vue'
|
||||
|
||||
export default Vue.extend({
|
||||
async asyncData ({ $content, params }) {
|
||||
const solution = await $content(`solutions/${params.id}`).fetch()
|
||||
return { solution }
|
||||
},
|
||||
head () {
|
||||
return { title: siteTitle((this as any).solution.title + ' « Solution') }
|
||||
},
|
||||
computed: {
|
||||
/**
|
||||
* Does this solution have a technology stack defined?
|
||||
*
|
||||
* @returns True if there are technologies defined, false if not
|
||||
*/
|
||||
hasTechStack (): boolean {
|
||||
return ((this as any).solution.technologies || []).length > 0
|
||||
},
|
||||
/**
|
||||
* Does this solution have any technology marked as current?
|
||||
*
|
||||
* @returns True if there are technologies marked as current, false if not
|
||||
*/
|
||||
hasCurrent (): boolean {
|
||||
return (this as any).solution.technologies.filter((x: any) => x[Object.keys(x)[0]].isCurrent).length > 0
|
||||
},
|
||||
/**
|
||||
* Retrieve the current technologies for this solution.
|
||||
*
|
||||
* @returns The current technologies for this solution
|
||||
*/
|
||||
currentTech (): [] {
|
||||
return (this as any).solution.technologies
|
||||
.filter((x: any) => x[Object.keys(x)[0]].isCurrent)
|
||||
.map((x: any) => [ Object.keys(x)[0], x[Object.keys(x)[0]].for ])
|
||||
},
|
||||
/**
|
||||
* Does this solutio have any technology not marked as current?
|
||||
*
|
||||
* @returns True if there are technologies not marked as current, false if not
|
||||
*/
|
||||
hasPrevious (): boolean {
|
||||
return (this as any).solution.technologies.filter((x: any) => !x[Object.keys(x)[0]].isCurrent).length > 0
|
||||
},
|
||||
/**
|
||||
* Retrieve the non-current technologies for this solution.
|
||||
*
|
||||
* @returns The non-current technologies for this solution.
|
||||
*/
|
||||
previousTech (): [] {
|
||||
return (this as any).solution.technologies
|
||||
.filter((x: any) => !x[Object.keys(x)[0]].isCurrent)
|
||||
.map((x: any) => [ Object.keys(x)[0], x[Object.keys(x)[0]].for ])
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
h1 {
|
||||
line-height: 1.6rem;
|
||||
}
|
||||
aside {
|
||||
float: right;
|
||||
background-color: #FFFAFA;
|
||||
}
|
||||
aside > span {
|
||||
padding-left: .75rem;
|
||||
}
|
||||
aside > img {
|
||||
overflow: hidden;
|
||||
border: dotted 1px darkgray;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.tech-stack p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.tech-stack ul {
|
||||
margin-top: 0;
|
||||
}
|
||||
blockquote {
|
||||
border-left: solid 1px darkgray;
|
||||
margin-left: 25px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
.quote {
|
||||
font-style: italic;
|
||||
}
|
||||
.source {
|
||||
text-align: right;
|
||||
padding-right: 60px;
|
||||
}
|
||||
</style>
|
32
bit-badger-solutions/pages/solutions/index.vue
Normal file
32
bit-badger-solutions/pages/solutions/index.vue
Normal file
@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<article class="content auto">
|
||||
<h1>All Solutions</h1>
|
||||
<h2>Active Solutions</h2>
|
||||
<solution-item v-for="sln in active" :key="sln.slug" :solution="sln" />
|
||||
<h2>Past Solutions</h2>
|
||||
<solution-item v-for="sln in inactive" :key="sln.slug" :solution="sln" />
|
||||
</article>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue'
|
||||
import { siteTitle } from '../index.vue'
|
||||
|
||||
const sortByName = (x: any, y: any): number =>
|
||||
x.title.toLowerCase() < y.title.toLowerCase() ? -1 : x.title.toLowerCase() > y.title.toLowerCase() ? 1 : 0
|
||||
|
||||
export default Vue.extend({
|
||||
async asyncData ({ $content }) {
|
||||
const activeSlns = await $content('solutions')
|
||||
.where({ isInactive: { $ne: true }, noAboutLink: { $ne: true } }).fetch()
|
||||
const inactiveSlns = await $content('solutions')
|
||||
.where({ isInactive: true, noAboutLink: { $ne: true } }).fetch()
|
||||
const active = activeSlns.sort(sortByName)
|
||||
const inactive = inactiveSlns.sort(sortByName)
|
||||
return { active, inactive }
|
||||
},
|
||||
head () {
|
||||
return { title: siteTitle('All Solutions') }
|
||||
}
|
||||
})
|
||||
</script>
|
@ -1,28 +0,0 @@
|
||||
import { NgModule } from '@angular/core'
|
||||
import { Routes, RouterModule } from '@angular/router'
|
||||
|
||||
import { ApplicationComponent } from './applications/application.component'
|
||||
import { ApplicationListComponent } from './applications/application-list/application-list.component'
|
||||
import { HomeComponent } from './pages/home/home.component'
|
||||
import { InformationPublicizingComponent } from './pages/about/information-publicizing.component'
|
||||
import { LegacyDataComponent } from './pages/about/legacy-data.component'
|
||||
import { ProcessAutomationComponent } from './pages/about/process-automation.component'
|
||||
import { WebServicesComponent } from './pages/about/web-services.component'
|
||||
import { WhyBitBadgerComponent } from './pages/about/why-bit-badger.component'
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', component: HomeComponent },
|
||||
{ path: 'about/information-publicizing-solutions', component: InformationPublicizingComponent },
|
||||
{ path: 'about/legacy-data', component: LegacyDataComponent },
|
||||
{ path: 'about/process-automation-solutions', component: ProcessAutomationComponent },
|
||||
{ path: 'about/web-services-solutions', component: WebServicesComponent },
|
||||
{ path: 'about/why-bit-badger', component: WhyBitBadgerComponent },
|
||||
{ path: 'solutions', component: ApplicationListComponent },
|
||||
{ path: 'solutions/:appId', component: ApplicationComponent }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes, { scrollPositionRestoration: 'enabled' })],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AppRoutingModule { }
|
@ -1,5 +0,0 @@
|
||||
<app-header></app-header>
|
||||
<div id="content">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
<app-footer></app-footer>
|
@ -1,35 +0,0 @@
|
||||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [
|
||||
RouterTestingModule
|
||||
],
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
it(`should have as title 'bit-badger-solutions'`, () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app.title).toEqual('bit-badger-solutions');
|
||||
});
|
||||
|
||||
it('should render title', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
expect(compiled.querySelector('.content span').textContent).toContain('bit-badger-solutions app is running!');
|
||||
});
|
||||
});
|
@ -1,10 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.sass']
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'bit-badger-solutions';
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
import { NgModule } from '@angular/core'
|
||||
import { BrowserModule } from '@angular/platform-browser'
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module'
|
||||
import { ApplicationsModule } from './applications/applications.module'
|
||||
import { SharedModule } from './shared/shared.module'
|
||||
import { SidebarModule } from './sidebar/sidebar.module'
|
||||
|
||||
import { AppComponent } from './app.component'
|
||||
import { HomeComponent } from './pages/home/home.component'
|
||||
import { WhyBitBadgerComponent } from './pages/about/why-bit-badger.component'
|
||||
import { InformationPublicizingComponent } from './pages/about/information-publicizing.component'
|
||||
import { LegacyDataComponent } from './pages/about/legacy-data.component'
|
||||
import { ProcessAutomationComponent } from './pages/about/process-automation.component'
|
||||
import { WebServicesComponent } from './pages/about/web-services.component'
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
HomeComponent,
|
||||
WhyBitBadgerComponent,
|
||||
InformationPublicizingComponent,
|
||||
LegacyDataComponent,
|
||||
ProcessAutomationComponent,
|
||||
WebServicesComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
BrowserAnimationsModule,
|
||||
AppRoutingModule,
|
||||
ApplicationsModule,
|
||||
SharedModule,
|
||||
SidebarModule
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
@ -1,13 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
|
||||
@Component({
|
||||
selector: 'app-all-solutions-link',
|
||||
template: `<p><br><a routerLink="/solutions">« Back to All Solutions</a></p>`
|
||||
})
|
||||
export class AllSolutionsLinkComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() { }
|
||||
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
import { Type } from '@angular/core'
|
||||
|
||||
/** An item representing an app */
|
||||
export class AppItem {
|
||||
constructor(public name: string, public component: Type<any>) { }
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import { Directive, ViewContainerRef } from '@angular/core'
|
||||
|
||||
@Directive({
|
||||
selector: '[app-application-detail]'
|
||||
})
|
||||
export class ApplicationDetailDirective {
|
||||
|
||||
constructor(public viewContainerRef: ViewContainerRef) { }
|
||||
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<h1>
|
||||
{{ app.name }}<br>
|
||||
<small><small>
|
||||
<a *ngIf="linkToApp" [href]="app.url">{{ app.url }}</a>
|
||||
<span *ngIf="!linkToApp">{{ app.url }}</span>
|
||||
<span *ngIf="linkToArchive">
|
||||
<a [href]="app.archiveUrl"><small>(Archive)</small></a>
|
||||
</span>
|
||||
</small></small>
|
||||
</h1>
|
@ -1,2 +0,0 @@
|
||||
h1
|
||||
line-height: 1.6rem
|
@ -1,28 +0,0 @@
|
||||
import { Component, OnInit, Input } from '@angular/core'
|
||||
|
||||
import { App } from '../application.types'
|
||||
|
||||
@Component({
|
||||
selector: 'app-application-header',
|
||||
templateUrl: './application-header.component.html',
|
||||
styleUrls: ['./application-header.component.sass']
|
||||
})
|
||||
export class ApplicationHeaderComponent implements OnInit {
|
||||
|
||||
@Input() app: App
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() { }
|
||||
|
||||
/** Whether to link to the app's URL */
|
||||
get linkToApp () {
|
||||
return this.app.isActive || this.app.linkInactive
|
||||
}
|
||||
|
||||
/** Whether to link to an archive URL */
|
||||
get linkToArchive () {
|
||||
return !this.app.isActive && !this.app.linkInactive && (this.app.archiveUrl > '')
|
||||
}
|
||||
|
||||
}
|
@ -1 +0,0 @@
|
||||
<aside><span> </span><img [src]="imageLink" [alt]="imageAlt"></aside>
|
@ -1,9 +0,0 @@
|
||||
aside
|
||||
float: right
|
||||
background-color: #FFFAFA
|
||||
aside > span
|
||||
padding-left: .75rem
|
||||
aside > img
|
||||
overflow: hidden
|
||||
border: dotted 1px darkgray
|
||||
border-radius: 10px
|
@ -1,29 +0,0 @@
|
||||
import { Component, OnInit, Input } from '@angular/core'
|
||||
|
||||
import { App } from '../application.types'
|
||||
|
||||
@Component({
|
||||
selector: 'app-application-image',
|
||||
templateUrl: './application-image.component.html',
|
||||
styleUrls: ['./application-image.component.sass']
|
||||
})
|
||||
export class ApplicationImageComponent implements OnInit {
|
||||
|
||||
@Input() app: App
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
/** The link to the screenshot image */
|
||||
get imageLink () {
|
||||
return `/assets/screenshots/${this.app.id}.png`
|
||||
}
|
||||
|
||||
/** The alt text for the screenshot image */
|
||||
get imageAlt () {
|
||||
return `Screen shot for ${this.app.name}`
|
||||
}
|
||||
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
<p>
|
||||
<span class="app-name" [innerHtml]="app.name"></span> ~ <a routerLink="/solutions/{{ app.id }}">About</a>
|
||||
<span *ngIf="app.isActive"> ~ <a [href]="app.url">Visit</a></span>
|
||||
<span *ngIf="!app.isActive && app.archiveUrl">
|
||||
~ <a [href]="app.archiveUrl">Visit</a><em> (archive)</em>
|
||||
</span>
|
||||
<br>
|
||||
<span [innerHtml]="app.indexText"></span>
|
||||
</p>
|
@ -1,5 +0,0 @@
|
||||
.app-name
|
||||
font-family: "Oswald", "Segoe UI", Ubuntu, "DejaVu Sans", "Liberation Sans", Arial, sans-serif
|
||||
font-size: 1.3rem
|
||||
font-weight: bold
|
||||
color: maroon
|
@ -1,18 +0,0 @@
|
||||
import { Component, OnInit, Input } from '@angular/core'
|
||||
|
||||
import { App } from '../application.types'
|
||||
|
||||
@Component({
|
||||
selector: 'app-application-list-item',
|
||||
templateUrl: './application-list-item.component.html',
|
||||
styleUrls: ['./application-list-item.component.sass']
|
||||
})
|
||||
export class ApplicationListItemComponent implements OnInit {
|
||||
|
||||
@Input() app: App
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() { }
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
<app-page-title title="All Solutions"></app-page-title>
|
||||
<article class="content auto">
|
||||
<h1>All Solutions</h1>
|
||||
<h2>Active Solutions</h2>
|
||||
<app-application-list-item *ngFor="let app of current" [app]="app"></app-application-list-item>
|
||||
<h2>Past Solutions</h2>
|
||||
<app-application-list-item *ngFor="let app of past" [app]="app"></app-application-list-item>
|
||||
</article>
|
@ -1,25 +0,0 @@
|
||||
import { Component, OnInit } from '@angular/core'
|
||||
|
||||
import { ApplicationService } from '../application.service'
|
||||
import { App } from '../application.types'
|
||||
|
||||
@Component({
|
||||
selector: 'app-application-list',
|
||||
templateUrl: './application-list.component.html'
|
||||
})
|
||||
export class ApplicationListComponent implements OnInit {
|
||||
|
||||
current: App[]
|
||||
|
||||
past: App[]
|
||||
|
||||
constructor(private appService: ApplicationService) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.appService.getApps().subscribe(apps => {
|
||||
this.current = apps.filter(app => app.isActive && !app.noAboutLink)
|
||||
this.past = apps.filter(app => !app.isActive && !app.noAboutLink)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
@ -1,87 +0,0 @@
|
||||
import { Component, OnInit, ViewChild, ComponentFactoryResolver } from '@angular/core'
|
||||
import { ActivatedRoute } from '@angular/router'
|
||||
|
||||
import { ApplicationService } from './application.service'
|
||||
import { App } from './application.types'
|
||||
import { AppItem } from './app-item'
|
||||
import { ApplicationDetailDirective } from './application-detail.directive'
|
||||
import { AppDetailComponent } from './solutions/app-detail.component'
|
||||
|
||||
import { BayVistaComponent } from './solutions/bay-vista.component'
|
||||
import { BitBadgerBlogComponent } from './solutions/bit-badger-blog.component'
|
||||
import { CassyFianoComponent } from './solutions/cassy-fiano.component'
|
||||
import { DrMelissaClouthierComponent } from './solutions/dr-melissa-clouthier.component'
|
||||
import { EmeraldMountainChristianSchoolComponent } from './solutions/emerald-mountain-christian-school.component'
|
||||
import { FutilityClosetComponent } from './solutions/futility-closet.component'
|
||||
import { HardCorpsWifeComponent } from './solutions/hard-corps-wife.component'
|
||||
import { LibertyPunditsComponent } from './solutions/liberty-pundits.component'
|
||||
import { MindyMackenzieComponent } from './solutions/mindy-mackenzie.component'
|
||||
import { MyPrayerJournalComponent } from './solutions/my-prayer-journal.component'
|
||||
import { NsxComponent } from './solutions/nsx.component'
|
||||
import { OlivetBaptistComponent } from './solutions/olivet-baptist.component'
|
||||
import { PhotographyByMichelleComponent } from './solutions/photography-by-michelle.component'
|
||||
import { PrayerTrackerComponent } from './solutions/prayer-tracker.component'
|
||||
import { RiehlWorldNewsComponent } from './solutions/riehl-world-news.component'
|
||||
import { SharkTankComponent } from './solutions/shark-tank.component'
|
||||
import { TcmsComponent } from './solutions/tcms.component'
|
||||
import { VirtualPrayerRoomComponent } from './solutions/virtual-prayer-room.component'
|
||||
|
||||
@Component({
|
||||
selector: 'app-application',
|
||||
template: '<ng-template app-application-detail></ng-template>'
|
||||
})
|
||||
export class ApplicationComponent implements OnInit {
|
||||
|
||||
private apps = [
|
||||
new AppItem('bay-vista', BayVistaComponent),
|
||||
new AppItem('cassy-fiano', CassyFianoComponent),
|
||||
new AppItem('dr-melissa-clouthier', DrMelissaClouthierComponent),
|
||||
new AppItem('emerald-mountain-christian-school', EmeraldMountainChristianSchoolComponent),
|
||||
new AppItem('futility-closet', FutilityClosetComponent),
|
||||
new AppItem('hard-corps-wife', HardCorpsWifeComponent),
|
||||
new AppItem('liberty-pundits', LibertyPunditsComponent),
|
||||
new AppItem('mindy-mackenzie', MindyMackenzieComponent),
|
||||
new AppItem('my-prayer-journal', MyPrayerJournalComponent),
|
||||
new AppItem('nsx', NsxComponent),
|
||||
new AppItem('olivet-baptist', OlivetBaptistComponent),
|
||||
new AppItem('photography-by-michelle', PhotographyByMichelleComponent),
|
||||
new AppItem('prayer-tracker', PrayerTrackerComponent),
|
||||
new AppItem('riehl-world-news', RiehlWorldNewsComponent),
|
||||
new AppItem('the-shark-tank', SharkTankComponent),
|
||||
new AppItem('tcms', TcmsComponent),
|
||||
new AppItem('tech-blog', BitBadgerBlogComponent),
|
||||
new AppItem('virtual-prayer-room', VirtualPrayerRoomComponent)
|
||||
]
|
||||
|
||||
@ViewChild(ApplicationDetailDirective, { static: true }) appDetail: ApplicationDetailDirective
|
||||
|
||||
/** The app we're displaying */
|
||||
application: App
|
||||
|
||||
constructor(
|
||||
private componentFactoryResolver: ComponentFactoryResolver,
|
||||
private appService: ApplicationService,
|
||||
private route: ActivatedRoute
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.route.params.subscribe(params => this.displayApp(params['appId']))
|
||||
}
|
||||
|
||||
/** Dynamically load the app-ropriate component */
|
||||
displayApp(appId: string) {
|
||||
const appComponent = this.apps.find(a => a.name === appId)
|
||||
|
||||
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(appComponent.component)
|
||||
const viewContainerRef = this.appDetail.viewContainerRef
|
||||
viewContainerRef.clear()
|
||||
|
||||
const componentRef = viewContainerRef.createComponent(componentFactory)
|
||||
this.appService.getApp(appId)
|
||||
.subscribe(app => {
|
||||
(<AppDetailComponent>componentRef.instance).app = app
|
||||
this.application = app
|
||||
})
|
||||
}
|
||||
|
||||
}
|
@ -1,323 +0,0 @@
|
||||
import { App, Category, Quote, Technology } from './application.types'
|
||||
|
||||
/** A Word from the Word */
|
||||
const aWordFromTheWord = new App('a-word-from-the-word', 'A Word from the Word', 'https://devotions.summershome.org')
|
||||
aWordFromTheWord.categoryId = Category.PERSONAL
|
||||
aWordFromTheWord.noAboutLink = true
|
||||
aWordFromTheWord.frontPageText = 'Devotions by Daniel'
|
||||
aWordFromTheWord.frontPageOrder = 2
|
||||
|
||||
/** Bay Vista Baptist Church */
|
||||
const bayVista = new App('bay-vista', 'Bay Vista Baptist Church', 'https://bayvista.org')
|
||||
bayVista.categoryId = Category.STATIC
|
||||
bayVista.frontPageText = 'Biloxi, Mississippi'
|
||||
bayVista.frontPageOrder = 1
|
||||
bayVista.indexText = 'Southern Baptist church in Biloxi, Mississippi'
|
||||
bayVista.techStack = [
|
||||
new Technology('Hugo', 'static site generation', true),
|
||||
new Technology('Azure', 'podcast file storage, automated builds, and static site hosting', true),
|
||||
new Technology('GitHub', 'source code control', true),
|
||||
new Technology('Hexo', 'static site generation'),
|
||||
new Technology('Jekyll', 'static site generation'),
|
||||
new Technology('WordPress', 'content management'),
|
||||
new Technology('MySQL', 'data storage')
|
||||
]
|
||||
|
||||
/** The Bit Badger Blog */
|
||||
const techBlog = new App('tech-blog', 'The Bit Badger Blog', 'https://blog.bitbadger.solutions')
|
||||
techBlog.categoryId = Category.STATIC
|
||||
techBlog.frontPageText = 'Technical information (“geek stuff”) from Bit Badger Solutions'
|
||||
techBlog.frontPageOrder = 3
|
||||
techBlog.indexText = 'Geek stuff from Bit Badger Solutions'
|
||||
techBlog.techStack = [
|
||||
new Technology('Hexo', 'static site generation', true),
|
||||
new Technology('Azure', 'static site hosting', true),
|
||||
new Technology('GitHub', 'source code control', true),
|
||||
new Technology('Custom software', 'content management'),
|
||||
new Technology('WordPress', 'content management'),
|
||||
new Technology('BlogEngine.NET', 'content management'),
|
||||
new Technology('Orchard', 'content management'),
|
||||
new Technology('myWebLog', 'content management'),
|
||||
new Technology('Jekyll', 'static site generation'),
|
||||
new Technology('MySQL', 'data storage'),
|
||||
new Technology('SQL Server', 'data storage'),
|
||||
new Technology('RethinkDB', 'data storage')
|
||||
]
|
||||
|
||||
/** Cassy Fiano */
|
||||
const cassyFiano = new App('cassy-fiano', 'Cassy Fiano', 'http://www.cassyfiano.com')
|
||||
cassyFiano.isActive = false
|
||||
cassyFiano.categoryId = Category.WORDPRESS
|
||||
cassyFiano.indexText = 'A “rising star” conservative blogger'
|
||||
cassyFiano.techStack = [
|
||||
new Technology('WordPress', 'blogging (with a custom theme)'),
|
||||
new Technology('MySQL', 'data storage'),
|
||||
new Technology('Rackspace Cloud', 'backup and recovery'),
|
||||
new Technology('Azure', 'backup and recovery')
|
||||
]
|
||||
|
||||
/** Daniel J. Summers */
|
||||
const danielJSummers = new App('daniel-j-summers', 'Daniel J. Summers', 'https://daniel.summershome.org')
|
||||
danielJSummers.categoryId = Category.PERSONAL
|
||||
danielJSummers.noAboutLink = true
|
||||
danielJSummers.frontPageText = 'Daniel’s personal blog',
|
||||
danielJSummers.frontPageOrder = 1
|
||||
|
||||
/** Dr. Melissa Clouthier */
|
||||
const drMelissaClouthier = new App('dr-melissa-clouthier', 'Dr. Melissa Clouthier', 'http://melissablogs.com')
|
||||
drMelissaClouthier.isActive = false
|
||||
drMelissaClouthier.categoryId = Category.WORDPRESS
|
||||
drMelissaClouthier.frontPageText = 'Information Pollination'
|
||||
drMelissaClouthier.frontPageOrder = 1
|
||||
drMelissaClouthier.indexText = 'Politics, health, podcasts and more'
|
||||
drMelissaClouthier.techStack = [
|
||||
new Technology('WordPress', 'blogging (with a custom theme)'),
|
||||
new Technology('MySQL', 'data storage'),
|
||||
new Technology('Rackspace Cloud', 'backup and recovery'),
|
||||
new Technology('Azure', 'backup and recovery')
|
||||
]
|
||||
|
||||
/** Emerald Mountain Christian School */
|
||||
const emcs = new App('emerald-mountain-christian-school', 'Emerald Mountain Christian School',
|
||||
'http://www.emeraldmountainchristianschool.org')
|
||||
emcs.isActive = false
|
||||
emcs.linkInactive = true
|
||||
emcs.indexText = 'Classical, Christ-centered education near Wetumpka, Alabama'
|
||||
emcs.techStack = [
|
||||
new Technology('PHP', 'page generation and interactivity'),
|
||||
new Technology('ASP.NET MVC', 'page generation and interactivity'),
|
||||
new Technology('PostgreSQL', 'data storage'),
|
||||
new Technology('Rackspace Cloud', 'hosting'),
|
||||
new Technology('Azure', 'hosting')
|
||||
]
|
||||
|
||||
/** Futility Closet */
|
||||
const futilityCloset = new App('futility-closet', 'Futility Closet', 'https://www.futilitycloset.com')
|
||||
futilityCloset.categoryId = Category.WORDPRESS
|
||||
futilityCloset.frontPageText = 'An idler’s miscellany of compendious amusements'
|
||||
futilityCloset.frontPageOrder = 2
|
||||
futilityCloset.indexText = 'An idler’s miscellany of compendious amusements'
|
||||
const fcQuote = new Quote('Greg Ross', 'Futility Closet')
|
||||
fcQuote.full =
|
||||
`Bit Badger Solutions has been an absolute godsend for Futility Closet. We have been with them since 2010, initially
|
||||
setting up and maintaining the site on a Rackspace VPS, and then hosting it completely. Daniel’s never failed
|
||||
in being friendly, knowledgeable, thoughtful, and farsighted. I’ve literally lost count of the number of times
|
||||
he’s saved us from one emergency or another, always with diligence and good humor, or recommended an
|
||||
improvement or a protection that saved us later. We would be out of business many times over if it weren’t for
|
||||
his reliability, expertise, and good judgment. And he’s a joy to work with.`
|
||||
fcQuote.pull = [
|
||||
`Daniel’s never failed in being friendly, knowledgeable, thoughtful, and farsighted…`,
|
||||
`We would be out of business many times over if it weren’t for his reliability, expertise, and good
|
||||
judgment…`
|
||||
]
|
||||
futilityCloset.quotes.push(fcQuote)
|
||||
futilityCloset.techStack = [
|
||||
new Technology('WordPress', 'blogging', true),
|
||||
new Technology('nginx', 'the web server', true),
|
||||
new Technology('MySQL', 'data storage', true),
|
||||
new Technology('Digital Ocean', 'web site hosting', true),
|
||||
new Technology('Azure', 'backup and recovery', true),
|
||||
new Technology('Rackspace Cloud', 'web site hosting')
|
||||
]
|
||||
|
||||
/** Hard Corps Wife */
|
||||
const hardCorpsWife = new App('hard-corps-wife', 'Hard Corps Wife', 'http://www.hardcorpswife.com')
|
||||
hardCorpsWife.isActive = false
|
||||
hardCorpsWife.categoryId = Category.WORDPRESS
|
||||
hardCorpsWife.indexText = 'Cassy’s life as a Marine wife'
|
||||
hardCorpsWife.techStack = [
|
||||
new Technology('WordPress', 'blogging'),
|
||||
new Technology('MySQL', 'data storage'),
|
||||
new Technology('Rackspace Cloud', 'web site hosting')
|
||||
]
|
||||
|
||||
/** Liberty Pundits */
|
||||
const libertyPundits = new App('liberty-pundits', 'Liberty Pundits', 'http://libertypundits.net')
|
||||
libertyPundits.isActive = false
|
||||
libertyPundits.categoryId = Category.WORDPRESS
|
||||
libertyPundits.indexText = 'The home for conservatives'
|
||||
libertyPundits.techStack = [
|
||||
new Technology('WordPress', 'blogging'),
|
||||
new Technology('PHP', 'custom data migration software'),
|
||||
new Technology('MySQL', 'data storage')
|
||||
]
|
||||
|
||||
/** Linux Resources */
|
||||
const linuxResources = new App('linux', 'Linux Resources', 'https://blog.bitbadger.solutions/linux/')
|
||||
linuxResources.noAboutLink = true
|
||||
linuxResources.frontPageText = 'Handy information for Linux folks'
|
||||
linuxResources.frontPageOrder = 3
|
||||
|
||||
/** Mindy Mackenzie */
|
||||
const mindyMackenzie = new App('mindy-mackenzie', 'Mindy Mackenzie', 'https://mindymackenzie.com')
|
||||
mindyMackenzie.categoryId = Category.WORDPRESS
|
||||
mindyMackenzie.frontPageText = 'WSJ-best-selling author of The Courage Solution'
|
||||
mindyMackenzie.frontPageOrder = 3
|
||||
mindyMackenzie.indexText = '<em>Wall Street Journal</em> best-selling author and C-suite advisor'
|
||||
const mmQuote = new Quote('Mindy Mackenzie', '')
|
||||
mmQuote.full =
|
||||
`Daniel is the best partner you could hope for in a web designer and for handling web maintenance! He is smart,
|
||||
creative, resourceful and fast. Daniel is able to produce high quality work on short time frames and with minimal
|
||||
creative direction and hit the mark over and over. The best part, is Daniel is a joy to work with. He is smart,
|
||||
customer-centric and trustworthy. If he says he will get it done, he does. After having a poor experience with
|
||||
another firm, I can highly recommend Daniel for all your website design and support needs – he’s terrific!`
|
||||
mmQuote.pull = [
|
||||
'…Daniel is able to produce high quality work on short time frames…',
|
||||
'[Daniel] is smart, customer-centric and trustworthy.'
|
||||
]
|
||||
mindyMackenzie.quotes.push(mmQuote)
|
||||
mindyMackenzie.techStack = [
|
||||
new Technology('WordPress', 'blogging', true),
|
||||
new Technology('nginx', 'the web server', true),
|
||||
new Technology('MySQL', 'data storage', true),
|
||||
new Technology('Digital Ocean', 'web site hosting', true),
|
||||
new Technology('Azure', 'backup and recovery', true),
|
||||
]
|
||||
|
||||
/** myPrayerJournal */
|
||||
const myPrayerJournal = new App('my-prayer-journal', 'myPrayerJournal', 'https://prayerjournal.me')
|
||||
myPrayerJournal.frontPageText = 'Minimalist personal prayer journal'
|
||||
myPrayerJournal.frontPageOrder = 2
|
||||
myPrayerJournal.indexText = 'Minimalist personal prayer journal'
|
||||
myPrayerJournal.techStack = [
|
||||
new Technology('Vue.js', 'the front-end', true),
|
||||
new Technology('Giraffe', 'the back-end data API', true),
|
||||
new Technology('RavenDB', 'data storage', true),
|
||||
new Technology('GitHub', 'source code control', true),
|
||||
new Technology('GitHub Pages', 'documentation', true),
|
||||
new Technology('PostgreSQL', 'data storage')
|
||||
]
|
||||
|
||||
/** Not So Extreme Makeover: Community Edition */
|
||||
const nsx = new App('nsx', 'Not So Extreme Makeover: Community Edition', 'http://notsoextreme.org')
|
||||
nsx.isActive = false
|
||||
nsx.archiveUrl = 'https://nsx.archive.bitbadger.solutions'
|
||||
nsx.indexText =
|
||||
'Public site for the makeover; provides event-driven management of volunteers, donations, and families needing help'
|
||||
nsx.techStack = [
|
||||
new Technology('WordPress', 'content management'),
|
||||
new Technology('PHP', 'NSXapp'),
|
||||
new Technology('MySQL', 'WordPress data storage'),
|
||||
new Technology('PostgreSQL', 'NSXapp data storage')
|
||||
]
|
||||
|
||||
/** Olivet Baptist Church */
|
||||
const olivet = new App('olivet-baptist', 'Olivet Baptist Church', 'https://olivet-baptist.org')
|
||||
olivet.isActive = false
|
||||
olivet.archiveUrl = 'https://olivet.archive.bitbadger.solutions'
|
||||
olivet.categoryId = Category.STATIC
|
||||
olivet.indexText = 'Southern Baptist church in Gulfport, Mississippi'
|
||||
olivet.techStack = [
|
||||
new Technology('Vue.js', 'the user interface for the PWA'),
|
||||
new Technology('Hexo', `generating the site's pages`),
|
||||
new Technology('Azure', 'podcast file storage and archive site hosting'),
|
||||
new Technology('WordPress', 'content management'),
|
||||
new Technology('MySQL', 'data storage')
|
||||
]
|
||||
|
||||
/** Photography by Michelle */
|
||||
const photographyByMichelle = new App('photography-by-michelle', 'Photography by Michelle',
|
||||
'https://www.summershome.org')
|
||||
photographyByMichelle.isActive = false
|
||||
photographyByMichelle.linkInactive = true
|
||||
photographyByMichelle.indexText = 'Photography services in Albuquerque, New Mexico'
|
||||
photographyByMichelle.techStack = [
|
||||
new Technology('ASP.NET MVC', 'content management / gallery creation API'),
|
||||
new Technology('PostgreSQL', 'data storage'),
|
||||
new Technology('C# / Windows Forms', 'desktop gallery application'),
|
||||
new Technology('WordPress', 'content management'),
|
||||
new Technology('MySQL', 'data storage')
|
||||
]
|
||||
|
||||
/** PrayerTracker */
|
||||
const prayerTracker = new App('prayer-tracker', 'PrayerTracker', 'https://prayer.bitbadger.solutions')
|
||||
prayerTracker.frontPageText = 'A prayer request tracking website (Free for any church or Sunday School class!)'
|
||||
prayerTracker.frontPageOrder = 1
|
||||
prayerTracker.indexText = 'Provides an ongoing, centralized prayer list for Sunday School classes and other groups'
|
||||
prayerTracker.techStack = [
|
||||
new Technology('Giraffe', 'server-side logic and dynamic page generation', true),
|
||||
new Technology('PostgreSQL', 'data storage', true),
|
||||
new Technology('GitHub', 'source code control', true),
|
||||
new Technology('GitHub Pages', 'documentation hosting', true),
|
||||
new Technology('MongoDB', 'data storage'),
|
||||
new Technology('ASP.NET MVC', 'dynamic content generation'),
|
||||
new Technology('Database Abstraction', 'data access'),
|
||||
new Technology('MySQL', 'data storage'),
|
||||
new Technology('PHP', 'dynamic content generation')
|
||||
]
|
||||
|
||||
/** Riehl World News */
|
||||
const riehlWorldNews = new App('riehl-world-news', 'Riehl World News', 'http://riehlworldview.com')
|
||||
riehlWorldNews.categoryId = Category.WORDPRESS
|
||||
riehlWorldNews.frontPageText = 'Riehl news for real people'
|
||||
riehlWorldNews.frontPageOrder = 4
|
||||
riehlWorldNews.indexText = 'Riehl news for real people'
|
||||
riehlWorldNews.techStack = [
|
||||
new Technology('WordPress', 'blogging', true),
|
||||
new Technology('MySQL', 'data storage', true),
|
||||
new Technology('F#', 'custom archive static page generation')
|
||||
]
|
||||
|
||||
/** The Shark Tank */
|
||||
const theSharkTank = new App('the-shark-tank', 'The Shark Tank', 'http://shark-tank.net')
|
||||
theSharkTank.isActive = false
|
||||
theSharkTank.categoryId = Category.WORDPRESS
|
||||
theSharkTank.indexText = 'Florida’s political feeding frenzy'
|
||||
theSharkTank.techStack = [ new Technology('WordPress', 'blogging') ]
|
||||
|
||||
/** The Clearinghouse Management System */
|
||||
var tcms = new App('tcms', 'The Clearinghouse Management System', 'http://tcms.us')
|
||||
tcms.isActive = false
|
||||
tcms.indexText =
|
||||
'Assists a needs clearinghouse in connecting people with needs to people that can help meet those needs'
|
||||
tcms.techStack = [
|
||||
new Technology('PHP', 'the TCMS application logic'),
|
||||
new Technology('WordPress', 'publicly-facing pages and authentication'),
|
||||
new Technology('PostgreSQL', 'application data storage'),
|
||||
new Technology('MySQL', 'WordPress data storage')
|
||||
]
|
||||
|
||||
/** Virtual Prayer Room */
|
||||
const vpr = new App('virtual-prayer-room', 'Virtual Prayer Room', 'https://virtualprayerroom.us')
|
||||
vpr.isActive = false
|
||||
vpr.indexText = 'Gives prayer warriors access to requests from wherever they may be, and sends them daily updates'
|
||||
vpr.techStack = [
|
||||
new Technology('PHP', 'the application logic'),
|
||||
new Technology('PostgreSQL', 'data storage')
|
||||
]
|
||||
|
||||
export default {
|
||||
|
||||
/** All categories */
|
||||
categories: [
|
||||
new Category(Category.SITES_APPS, 'Web Sites and Applications'),
|
||||
new Category(Category.WORDPRESS, 'WordPress'),
|
||||
new Category(Category.STATIC, 'Static Sites'),
|
||||
new Category(Category.PERSONAL, 'Personal')
|
||||
],
|
||||
|
||||
/** All apps */
|
||||
apps: [
|
||||
aWordFromTheWord,
|
||||
bayVista,
|
||||
cassyFiano,
|
||||
danielJSummers,
|
||||
drMelissaClouthier,
|
||||
emcs,
|
||||
futilityCloset,
|
||||
hardCorpsWife,
|
||||
libertyPundits,
|
||||
linuxResources,
|
||||
mindyMackenzie,
|
||||
myPrayerJournal,
|
||||
nsx,
|
||||
olivet,
|
||||
photographyByMichelle,
|
||||
prayerTracker,
|
||||
riehlWorldNews,
|
||||
tcms,
|
||||
techBlog,
|
||||
theSharkTank,
|
||||
vpr
|
||||
]
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
import { Injectable } from '@angular/core'
|
||||
import { Observable, of } from 'rxjs'
|
||||
|
||||
import Data from './application.data'
|
||||
import { Category, App } from './application.types'
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class ApplicationService {
|
||||
|
||||
constructor() { }
|
||||
|
||||
/**
|
||||
* Get all categories of apps
|
||||
*/
|
||||
getCategories(): Observable<Category[]> {
|
||||
return of(Data.categories)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all apps
|
||||
*/
|
||||
getApps(): Observable<App[]> {
|
||||
return of(Data.apps)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all applications for the given category ID
|
||||
* @param categoryId The ID of the category for which apps should be retrieved
|
||||
*/
|
||||
getAppsForCategory(categoryId: number): Observable<App[]> {
|
||||
return of(
|
||||
Data.apps
|
||||
.filter(app => app.categoryId === categoryId)
|
||||
.sort((a, b) => a.frontPageOrder - b.frontPageOrder)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific app
|
||||
* @param appId The ID of the app to retrieve
|
||||
*/
|
||||
getApp(appId: string): Observable<App> {
|
||||
return of(Data.apps.find(app => app.id === appId))
|
||||
}
|
||||
|
||||
}
|
@ -1,96 +0,0 @@
|
||||
/** A category of application */
|
||||
export class Category {
|
||||
|
||||
/**
|
||||
* Construct a new instance
|
||||
* @param id The ID of the category
|
||||
* @param name The name of the category
|
||||
*/
|
||||
constructor(public id: number, public name: string) {
|
||||
this.id = id
|
||||
this.name = name
|
||||
}
|
||||
|
||||
/** Sites/applications not otherwise specified */
|
||||
static SITES_APPS = 1
|
||||
|
||||
/** WordPress sites */
|
||||
static WORDPRESS = 2
|
||||
|
||||
/** Statically generated sites */
|
||||
static STATIC = 3
|
||||
|
||||
/** Daniel's personal sites */
|
||||
static PERSONAL = 99
|
||||
}
|
||||
|
||||
/** A quote from an app */
|
||||
export class Quote {
|
||||
|
||||
/** The full text of the quote */
|
||||
full: string = ''
|
||||
|
||||
/** Shorter portions of the full quote */
|
||||
pull: string[] = []
|
||||
|
||||
/**
|
||||
* Construct a new instance
|
||||
* @param name The name of the person who provided the quote
|
||||
* @param from What organization the person who provided the quote represents
|
||||
*/
|
||||
constructor(public name: string, public from: string) { }
|
||||
}
|
||||
|
||||
/** A description of a part of the technology stack used */
|
||||
export class Technology {
|
||||
|
||||
/**
|
||||
* Construct a new instace
|
||||
* @param name The name of the technology
|
||||
* @param usedFor What aspect was addressed by this technology
|
||||
* @param current Whether this technology is currently in use in the solution
|
||||
*/
|
||||
constructor(public name: string, public usedFor: string, public current: boolean = false) { }
|
||||
}
|
||||
|
||||
/** An application or web site */
|
||||
export class App {
|
||||
|
||||
/** Whether this app is active (default true) */
|
||||
isActive: boolean = true
|
||||
|
||||
/** The ID of the category to which this app belongs (default "Web Sites and Applictions") */
|
||||
categoryId: number = Category.SITES_APPS
|
||||
|
||||
/** Whether to skip displaying an About link on the front page */
|
||||
noAboutLink: boolean = false
|
||||
|
||||
/** Whether the generate a link for an inactive app (defaults to false) */
|
||||
linkInactive: boolean = false
|
||||
|
||||
/** The text to use for the short description in the front page sidebar */
|
||||
frontPageText: string = ''
|
||||
|
||||
/** The order (within category) in which this app should be displayed */
|
||||
frontPageOrder: number = 0
|
||||
|
||||
/** The text to display for the application on this index page */
|
||||
indexText: string = ''
|
||||
|
||||
/** The URL where an archived version of this app may be found */
|
||||
archiveUrl: string = ''
|
||||
|
||||
/** The technology used for this app */
|
||||
techStack: Technology[] = []
|
||||
|
||||
/** Customer quotes */
|
||||
quotes: Quote[] = []
|
||||
|
||||
/**
|
||||
* Construct a new instance
|
||||
* @param id The ID of the app
|
||||
* @param name The name of the app
|
||||
* @param url The URL of the app
|
||||
*/
|
||||
constructor(public id: string, public name: string, public url: string) { }
|
||||
}
|
@ -1,99 +0,0 @@
|
||||
import { NgModule } from '@angular/core'
|
||||
import { CommonModule } from '@angular/common'
|
||||
import { RouterModule } from '@angular/router'
|
||||
|
||||
import { AllSolutionsLinkComponent } from './all-solutions-link.component'
|
||||
import { ApplicationComponent } from './application.component'
|
||||
import { ApplicationDetailDirective } from './application-detail.directive'
|
||||
import { ApplicationHeaderComponent } from './application-header/application-header.component'
|
||||
import { ApplicationImageComponent } from './application-image/application-image.component'
|
||||
import { ApplicationListComponent } from './application-list/application-list.component'
|
||||
import { ApplicationListItemComponent } from './application-list-item/application-list-item.component'
|
||||
import { HideSectionComponent } from './hide-section/hide-section.component'
|
||||
import { QuotesComponent } from './quotes/quotes.component';
|
||||
import { SharedModule } from '../shared/shared.module'
|
||||
import { TechnologyComponent } from './technology/technology.component';
|
||||
import { TechStackComponent } from './tech-stack/tech-stack.component';
|
||||
|
||||
import { BayVistaComponent } from './solutions/bay-vista.component'
|
||||
import { BitBadgerBlogComponent } from './solutions/bit-badger-blog.component';
|
||||
import { CassyFianoComponent } from './solutions/cassy-fiano.component'
|
||||
import { DrMelissaClouthierComponent } from './solutions/dr-melissa-clouthier.component';
|
||||
import { EmeraldMountainChristianSchoolComponent } from './solutions/emerald-mountain-christian-school.component';
|
||||
import { FutilityClosetComponent } from './solutions/futility-closet.component';
|
||||
import { HardCorpsWifeComponent } from './solutions/hard-corps-wife.component';
|
||||
import { LibertyPunditsComponent } from './solutions/liberty-pundits.component';
|
||||
import { MindyMackenzieComponent } from './solutions/mindy-mackenzie.component';
|
||||
import { MyPrayerJournalComponent } from './solutions/my-prayer-journal.component';
|
||||
import { NsxComponent } from './solutions/nsx.component';
|
||||
import { OlivetBaptistComponent } from './solutions/olivet-baptist.component';
|
||||
import { PhotographyByMichelleComponent } from './solutions/photography-by-michelle.component';
|
||||
import { PrayerTrackerComponent } from './solutions/prayer-tracker.component'
|
||||
import { RiehlWorldNewsComponent } from './solutions/riehl-world-news.component';
|
||||
import { SharkTankComponent } from './solutions/shark-tank.component';
|
||||
import { TcmsComponent } from './solutions/tcms.component';
|
||||
import { VirtualPrayerRoomComponent } from './solutions/virtual-prayer-room.component'
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AllSolutionsLinkComponent,
|
||||
ApplicationComponent,
|
||||
ApplicationDetailDirective,
|
||||
ApplicationHeaderComponent,
|
||||
ApplicationImageComponent,
|
||||
ApplicationListComponent,
|
||||
ApplicationListItemComponent,
|
||||
BayVistaComponent,
|
||||
BitBadgerBlogComponent,
|
||||
CassyFianoComponent,
|
||||
DrMelissaClouthierComponent,
|
||||
EmeraldMountainChristianSchoolComponent,
|
||||
FutilityClosetComponent,
|
||||
HardCorpsWifeComponent,
|
||||
HideSectionComponent,
|
||||
LibertyPunditsComponent,
|
||||
MindyMackenzieComponent,
|
||||
MyPrayerJournalComponent,
|
||||
NsxComponent,
|
||||
OlivetBaptistComponent,
|
||||
PhotographyByMichelleComponent,
|
||||
PrayerTrackerComponent,
|
||||
QuotesComponent,
|
||||
RiehlWorldNewsComponent,
|
||||
SharkTankComponent,
|
||||
TcmsComponent,
|
||||
TechnologyComponent,
|
||||
TechStackComponent,
|
||||
VirtualPrayerRoomComponent
|
||||
],
|
||||
entryComponents: [
|
||||
BayVistaComponent,
|
||||
BitBadgerBlogComponent,
|
||||
CassyFianoComponent,
|
||||
DrMelissaClouthierComponent,
|
||||
EmeraldMountainChristianSchoolComponent,
|
||||
FutilityClosetComponent,
|
||||
HardCorpsWifeComponent,
|
||||
LibertyPunditsComponent,
|
||||
MindyMackenzieComponent,
|
||||
MyPrayerJournalComponent,
|
||||
NsxComponent,
|
||||
OlivetBaptistComponent,
|
||||
PhotographyByMichelleComponent,
|
||||
PrayerTrackerComponent,
|
||||
RiehlWorldNewsComponent,
|
||||
SharkTankComponent,
|
||||
TcmsComponent,
|
||||
VirtualPrayerRoomComponent
|
||||
],
|
||||
imports: [
|
||||
CommonModule,
|
||||
RouterModule,
|
||||
SharedModule
|
||||
],
|
||||
exports: [
|
||||
ApplicationComponent,
|
||||
ApplicationListComponent
|
||||
]
|
||||
})
|
||||
export class ApplicationsModule { }
|
@ -1,4 +0,0 @@
|
||||
<h3 (click)="toggle()">{{ heading }}<span class="arrow" [innerHtml]="label"></span></h3>
|
||||
<div *ngIf="shown" [@slideInOut]>
|
||||
<ng-content></ng-content>
|
||||
</div>
|
@ -1,6 +0,0 @@
|
||||
h3:hover
|
||||
cursor: hand
|
||||
cursor: pointer
|
||||
.arrow
|
||||
font-size: .75rem
|
||||
padding-left: 1rem
|
@ -1,38 +0,0 @@
|
||||
import { Component, OnInit, Input } from '@angular/core';
|
||||
import { trigger, transition, style, animate, group } from '@angular/animations';
|
||||
|
||||
@Component({
|
||||
selector: 'app-hide-section',
|
||||
templateUrl: './hide-section.component.html',
|
||||
styleUrls: ['./hide-section.component.sass'],
|
||||
animations: [
|
||||
trigger('slideInOut', [
|
||||
transition(':enter', [
|
||||
style({ opacity: 0 }),
|
||||
animate('500ms ease-in', style({ opacity: 1 }))
|
||||
]),
|
||||
transition(':leave', [
|
||||
style({opacity: 1}),
|
||||
animate('500ms ease-in', style({ opacity: 0 }))
|
||||
])
|
||||
])
|
||||
]
|
||||
})
|
||||
export class HideSectionComponent implements OnInit {
|
||||
|
||||
@Input() heading: string
|
||||
|
||||
label = '▼'
|
||||
|
||||
shown = false
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() { }
|
||||
|
||||
toggle() {
|
||||
this.shown = !this.shown
|
||||
this.label = this.shown ? '▲' : '▼'
|
||||
}
|
||||
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<div *ngIf="(quotes || []).length > 0">
|
||||
<h3>The Business Impact</h3>
|
||||
<blockquote *ngFor="let quote of quotes">
|
||||
<p class="quote" [innerHtml]="quote.full"></p>
|
||||
<p class="source">
|
||||
— <strong>{{ quote.name }}</strong>
|
||||
<span *ngIf="quote.from">, {{ quote.from }}</span>
|
||||
</p>
|
||||
</blockquote>
|
||||
</div>
|
@ -1,9 +0,0 @@
|
||||
blockquote
|
||||
border-left: solid 1px darkgray
|
||||
margin-left: 25px
|
||||
padding-left: 15px
|
||||
.quote
|
||||
font-style: italic
|
||||
.source
|
||||
text-align: right
|
||||
padding-right: 60px
|
@ -1,18 +0,0 @@
|
||||
import { Component, OnInit, Input } from '@angular/core'
|
||||
|
||||
import { Quote } from '../application.types'
|
||||
|
||||
@Component({
|
||||
selector: 'app-quotes',
|
||||
templateUrl: './quotes.component.html',
|
||||
styleUrls: ['./quotes.component.sass']
|
||||
})
|
||||
export class QuotesComponent implements OnInit {
|
||||
|
||||
@Input() quotes: Quote[]
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() { }
|
||||
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
import { App } from '../application.types'
|
||||
|
||||
/** An inteface implemented by all app detail components */
|
||||
export class AppDetailComponent {
|
||||
|
||||
/** The app to be displayed */
|
||||
app: App
|
||||
|
||||
/** The page title based on this app */
|
||||
get pageTitle () {
|
||||
return `${this.app.name} « Solutions`
|
||||
}
|
||||
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
<app-page-title [title]="pageTitle"></app-page-title>
|
||||
<app-application-header [app]="app"></app-application-header>
|
||||
<div class="app-info">
|
||||
<article class="content">
|
||||
<app-application-image [app]="app"></app-application-image>
|
||||
<h3>The Client</h3>
|
||||
<p>
|
||||
Bay Vista Baptist Church has served the spiritual needs of Mississippi’s Gulf Coast for decades. They
|
||||
emphasize serving their community as well; they were a hub for
|
||||
<abbr title="Federal Emergency Management Agency">FEMA</abbr> during Hurricane Katrina relief and recovery
|
||||
efforts, and they are a relay point for each year’s
|
||||
<a href="https://www.samaritanspurse.org/what-we-do/operation-christmas-child/">Operation Christmas Child</a>
|
||||
campaign.
|
||||
</p>
|
||||
<h3>The Problem</h3>
|
||||
<p>
|
||||
In late 2013, the authors of their current website were no longer around, and no one could get to the site to
|
||||
update it.
|
||||
</p>
|
||||
<h3>The Solution</h3>
|
||||
<p>
|
||||
We developed and continue to maintain a fast, static website that can be updated by multiple trained church
|
||||
members. The site also has a repository for their sermons dating back to January 2014, and a podcast feed that
|
||||
gives their ministry a global reach.
|
||||
</p>
|
||||
<app-hide-section heading="The Process">
|
||||
<p>
|
||||
Initially, we set up a WordPress-based site, where multiple people could have the ability to maintain the site.
|
||||
We manually downloaded all the publically-accessible parts of their old site, and used that content to form the
|
||||
basis for the new side, updating outdated information along the way. We maintained the same look-and-feel, but
|
||||
soon moved to a more mobile-friendly layout.
|
||||
</p>
|
||||
<p>
|
||||
In 2016, we determined that we were the only ones updating the site, so we transformed the site to use a static
|
||||
site generator; this resulted in fast page loads, with automation providing scheduled updates. We also wrote a
|
||||
custom template for the podcast feed, which is also generated as a static file.
|
||||
</p>
|
||||
<p>
|
||||
In 2019, we <a href="https://github.com/bayvistabc/www.bayvista.org">open sourced</a> the site's source code.
|
||||
We also set up Azure Pipelines to automatically build and deploy the site both on demand and on a schedule.
|
||||
Finally, we trained other church members on updating the site's contents and the podcast feed.
|
||||
</p>
|
||||
</app-hide-section>
|
||||
<app-tech-stack [stack]="app.techStack"></app-tech-stack>
|
||||
<app-all-solutions-link></app-all-solutions-link>
|
||||
</article>
|
||||
</div>
|
@ -1,18 +0,0 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
|
||||
import { AppDetailComponent } from './app-detail.component'
|
||||
import { App } from '../application.types'
|
||||
|
||||
@Component({
|
||||
selector: 'app-bay-vista',
|
||||
templateUrl: './bay-vista.component.html'
|
||||
})
|
||||
export class BayVistaComponent extends AppDetailComponent {
|
||||
|
||||
@Input() app: App
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
<app-page-title [title]="pageTitle"></app-page-title>
|
||||
<app-application-header [app]="app"></app-application-header>
|
||||
<div class="app-info">
|
||||
<article class="content">
|
||||
<app-application-image [app]="app"></app-application-image>
|
||||
<h3>The Problem</h3>
|
||||
<p>
|
||||
Daniel needed a place to journal his learning journey with the Linux operating system, and thought that allowing
|
||||
others read this journal would help them learn as well.
|
||||
</p>
|
||||
<h3>The Solution</h3>
|
||||
<p>
|
||||
<em>The Bit Badger Blog</em> contains that journal, plus tech tips and information for many different aspects of
|
||||
technology. It is written, maintained, and hosted by Bit Badger Solutions.
|
||||
</p>
|
||||
<app-hide-section heading="The Process">
|
||||
<p>
|
||||
The initial posts were titled “My Linux Adventure,” and existed as static files that were edited to
|
||||
add each post. Daniel then wrote a rudimentary system that stored the posts in a database, which meant that the
|
||||
entire site did not need manual changes – what a breakthrough! :)
|
||||
</p>
|
||||
<p>
|
||||
Over time, the <em>Bit Badger Blog</em> (and the <em>DJS Consulting Tech Blog</em> before it) has served as a
|
||||
place to support <em>(now inactive)</em> WordPress plug-ins, and go in depth on servers, databases, programming
|
||||
languages, and open-source software. It has also served as a useful live website for learning and
|
||||
experimentation with different content management systems and blogging tools. It has existed in at least 8
|
||||
different tools, with links preserved as systems change.
|
||||
</p>
|
||||
<p>
|
||||
It is currently a statically-generated site, utilizing <a href="https://hexo.io">Hexo</a>, and its code is
|
||||
<a href="https://github.com/bit-badger/blog.bitbadger.solutions">open source</a>. New posts are infrequent,
|
||||
but the information it has is good. It may have more behind-the-scenes posts about future open-source efforts.
|
||||
Stay tuned!
|
||||
</p>
|
||||
</app-hide-section>
|
||||
<app-tech-stack [stack]="app.techStack"></app-tech-stack>
|
||||
<app-all-solutions-link></app-all-solutions-link>
|
||||
</article>
|
||||
</div>
|
@ -1,18 +0,0 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
|
||||
import { AppDetailComponent } from './app-detail.component'
|
||||
import { App } from '../application.types'
|
||||
|
||||
@Component({
|
||||
selector: 'app-bit-badger-blog',
|
||||
templateUrl: './bit-badger-blog.component.html'
|
||||
})
|
||||
export class BitBadgerBlogComponent extends AppDetailComponent {
|
||||
|
||||
@Input() app: App
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
<app-page-title [title]="pageTitle"></app-page-title>
|
||||
<app-application-header [app]="app"></app-application-header>
|
||||
<div class="app-info">
|
||||
<article class="content">
|
||||
<app-application-image [app]="app"></app-application-image>
|
||||
<h3>The Client</h3>
|
||||
<p>
|
||||
Cassy Fiano (now Cassy Chesser) began blogging back in 2007 on Blogger. She worked hard to network with other
|
||||
bloggers, wrote prolifically, and gained a large audience with her coverage of life issues and of Sarah Palin as
|
||||
the first female Republican vice-presidential nominee.
|
||||
</p>
|
||||
<h3>The Problem</h3>
|
||||
<p>
|
||||
With her success, Cassy was quickly outgrowing Blogger. She was interested in moving to a different platform;
|
||||
specifically, Movable Type, as she had some authoring experience with that platform.
|
||||
</p>
|
||||
<h3>The Solution</h3>
|
||||
<p>
|
||||
We migrated her content to a WordPress site, and customized a theme to look very similar to her Blogger theme
|
||||
(which she liked). We maintained the site, and began hosting it a few years later.
|
||||
</p>
|
||||
<h3>The Epilogue</h3>
|
||||
<p>Cassy formally decommissioned this site in early 2014.</p>
|
||||
<app-hide-section heading="The Process">
|
||||
<p>
|
||||
Initially, we assisted her with finding a theme, and customized it. We also modified her old Blogger template
|
||||
to send redirect users to her new blog after displaying a note that the blog had moved. A few years later, we
|
||||
developed an advertising banner to generate income from her writing.
|
||||
</p>
|
||||
<p>
|
||||
In July 2012, we began hosting the site, as we were already hosting her military wife blog
|
||||
<a routerLink="/solutions/hard-corps-wife" title="Hard Corps Wife | Bit Badger Solutions">Hard Corps Wife</a>.
|
||||
When the time came to decommission the site, we backed up the data and ensured she had it.
|
||||
</p>
|
||||
</app-hide-section>
|
||||
<app-tech-stack [stack]="app.techStack"></app-tech-stack>
|
||||
<app-all-solutions-link></app-all-solutions-link>
|
||||
</article>
|
||||
</div>
|
@ -1,18 +0,0 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
|
||||
import { AppDetailComponent } from './app-detail.component'
|
||||
import { App } from '../application.types'
|
||||
|
||||
@Component({
|
||||
selector: 'app-cassy-fiano',
|
||||
templateUrl: './cassy-fiano.component.html'
|
||||
})
|
||||
export class CassyFianoComponent extends AppDetailComponent {
|
||||
|
||||
@Input() app: App
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
<app-page-title [title]="pageTitle"></app-page-title>
|
||||
<app-application-header [app]="app"></app-application-header>
|
||||
<div class="app-info">
|
||||
<article class="content">
|
||||
<app-application-image [app]="app"></app-application-image>
|
||||
<h3>The Client</h3>
|
||||
<p>
|
||||
Dr. Melissa Clouthier (now Mackenzie) blogged from the political right; she also covered health issues and social
|
||||
media techniques and utilization.
|
||||
</p>
|
||||
<h3>The Problem</h3>
|
||||
<p>
|
||||
She had seen our work with <a routerLink="/solutions/cassy-fiano"
|
||||
title="Cassy Fiano | Bit Badger Solutions">Cassy</a>’s site, also wanted to move off Blogger; however, she
|
||||
did not want to lose her years of posts up to that point.
|
||||
</p>
|
||||
<h3>The Solution</h3>
|
||||
<p>
|
||||
We created a custom theme for her site, imported the content into a WordPress site, and created a specialized
|
||||
front-page template. She obtained hosting elsewhere; Bit Badger Solutions maintained it there.
|
||||
</p>
|
||||
<p>
|
||||
<small><em>(NOTE: The thumbnail of the site represents a new skin on the original theme; while the theme is the
|
||||
same, Bit Badger Solutions did not create the graphics.)</em></small>
|
||||
</p>
|
||||
<h3>The Epilogue</h3>
|
||||
<p>Melissa decommissioned this site in 2018; we took final snapshots of the data before shutting it down.</p>
|
||||
<app-hide-section heading="The Process">
|
||||
<p>
|
||||
Initially, we created the theme based off another well-known blogger's site, which had been developed by one of
|
||||
WordPress's core contributors. We also advised on the type of hosting she would need for her site, and moved
|
||||
seveal domains there. We also took care of regular backups of her data.
|
||||
</p>
|
||||
</app-hide-section>
|
||||
<app-tech-stack [stack]="app.techStack"></app-tech-stack>
|
||||
<app-all-solutions-link></app-all-solutions-link>
|
||||
</article>
|
||||
</div>
|
@ -1,18 +0,0 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
|
||||
import { AppDetailComponent } from './app-detail.component'
|
||||
import { App } from '../application.types'
|
||||
|
||||
@Component({
|
||||
selector: 'app-dr-melissa-clouthier',
|
||||
templateUrl: './dr-melissa-clouthier.component.html'
|
||||
})
|
||||
export class DrMelissaClouthierComponent extends AppDetailComponent {
|
||||
|
||||
@Input() app: App
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
<app-page-title [title]="pageTitle"></app-page-title>
|
||||
<app-application-header [app]="app"></app-application-header>
|
||||
<div class="app-info">
|
||||
<article class="content">
|
||||
<app-application-image [app]="app"></app-application-image>
|
||||
<h3>The Client</h3>
|
||||
<p>
|
||||
Emerald Mountain Christian School is a private Christian school founded over 50 years ago. They use the Principle
|
||||
Approach®, which emphasizes research, reasoning, relating, and recording to help students synthesize the
|
||||
information they learn, rather than just requiring rote memorization. More information about the school’s
|
||||
rich history can be found on their site.
|
||||
</p>
|
||||
<h3>The Problem</h3>
|
||||
<p>
|
||||
They had a website with very basic information and very little styling; they also had no way of updating it.
|
||||
</p>
|
||||
<h3>The Solution</h3>
|
||||
<p>
|
||||
In 2004, we developed a theme that brought it in line with the design of their printed materials, adding the
|
||||
school calendar of events and the entirety of their Parent Information Packet, giving prospective families the
|
||||
information the needed to determine if the school was a good fit for their students.
|
||||
</p>
|
||||
<h3>The Epilogue</h3>
|
||||
<p>
|
||||
In 2013, we passed off the content and hosting of the site to a new maintainer. They have since redesigned it;
|
||||
it is accessible via the URL above, and at <a href="http://emcspatriots.org"
|
||||
title="EMCS Patriots">EMCSpatriots.org</a>.
|
||||
</p>
|
||||
<app-hide-section heading="The Process">
|
||||
<p>
|
||||
Initially, we downloaded the content from their old site, and put it into a custom PHP-based framework. We
|
||||
then added a database of events, and a calendar page that read that database, enabling us to display multiple
|
||||
years, as well as future and past years. The design of the online information packet looked like a tabbed
|
||||
notebook, with each page highlighting a different tab.
|
||||
</p>
|
||||
<p>
|
||||
In 2011, we switched the site to use ASP.NET MVC instead of the custom PHP solution, and migrated the data from
|
||||
MySQL to PostgreSQL; these efforts increased the performance of the site.
|
||||
</p>
|
||||
</app-hide-section>
|
||||
<app-tech-stack [stack]="app.techStack"></app-tech-stack>
|
||||
<app-all-solutions-link></app-all-solutions-link>
|
||||
</article>
|
||||
</div>
|
@ -1,18 +0,0 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
|
||||
import { AppDetailComponent } from './app-detail.component'
|
||||
import { App } from '../application.types'
|
||||
|
||||
@Component({
|
||||
selector: 'app-emerald-mountain-christian-school',
|
||||
templateUrl: './emerald-mountain-christian-school.component.html'
|
||||
})
|
||||
export class EmeraldMountainChristianSchoolComponent extends AppDetailComponent {
|
||||
|
||||
@Input() app: App
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
<app-page-title [title]="pageTitle"></app-page-title>
|
||||
<app-application-header [app]="app"></app-application-header>
|
||||
<div class="app-info">
|
||||
<article class="content">
|
||||
<app-application-image [app]="app"></app-application-image>
|
||||
<h3>The Client</h3>
|
||||
<p>
|
||||
Futility Closet exists as a place to give people a break from the dullness of work, by providing puzzles,
|
||||
anecdotes, and more. They also publish a weekly podcast highlighting “forgotten stories from the pages of
|
||||
history,” along with story updates and lateral thinking puzzles.
|
||||
</p>
|
||||
<h3>The Problem</h3>
|
||||
<p>
|
||||
The site was running on a shared host, but was growing too large for that platform. The site had also suffered
|
||||
regular security breaches.
|
||||
</p>
|
||||
<h3>The Solution</h3>
|
||||
<p>
|
||||
We architected an environment that would support a Reddit or Slashdot deluge of requests, and moved the site to
|
||||
an implementation of that environment. We continue to maintain that environment and back up data and files for
|
||||
the over 10,000 posts.
|
||||
</p>
|
||||
<app-quotes [quotes]="app.quotes"></app-quotes>
|
||||
<app-hide-section heading="The Process">
|
||||
<p>
|
||||
In mid-2010, we obtained a backup of the previous site, and looked through it to ensure that none of the
|
||||
breaches had made any permanent changes to the site's structure and data. We also locked down the new server
|
||||
(hosted on Rackspace Cloud) to only required protocols, training the client on SSH so that they could have
|
||||
access. We also stood up nginx as the front-end server, boosting performance significantly while requiring a
|
||||
much smaller server.
|
||||
</p>
|
||||
<p>
|
||||
In 2015, we began hosting Futility Closet (using Digital Ocean).
|
||||
</p>
|
||||
</app-hide-section>
|
||||
<app-tech-stack [stack]="app.techStack"></app-tech-stack>
|
||||
<app-all-solutions-link></app-all-solutions-link>
|
||||
</article>
|
||||
</div>
|
@ -1,18 +0,0 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
|
||||
import { AppDetailComponent } from './app-detail.component'
|
||||
import { App } from '../application.types'
|
||||
|
||||
@Component({
|
||||
selector: 'app-futility-closet',
|
||||
templateUrl: './futility-closet.component.html'
|
||||
})
|
||||
export class FutilityClosetComponent extends AppDetailComponent {
|
||||
|
||||
@Input() app: App
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
<app-page-title [title]="pageTitle"></app-page-title>
|
||||
<app-application-header [app]="app"></app-application-header>
|
||||
<div class="app-info">
|
||||
<article class="content">
|
||||
<app-application-image [app]="app"></app-application-image>
|
||||
<h3>The Client</h3>
|
||||
<p>
|
||||
Our existing client <a routerLink="/solutions/cassy-fiano"
|
||||
title="Cassy Fiano | Bit Badger Solutions">Cassy Fiano</a>
|
||||
</p>
|
||||
<h3>The Problem</h3>
|
||||
<p>Cassy (now Chesser) wanted a separate place from which to chronicle her experience as a military spouse.</p>
|
||||
<h3>The Solution</h3>
|
||||
<p>
|
||||
In mid-2010, we set up her domain name, created a WordPress site, and customized the header and sidebar for her
|
||||
selected theme. We also hosted and maintained the site for the duration of its run.
|
||||
</p>
|
||||
<h3>The Epilogue</h3>
|
||||
<p>In 2013, Cassy shifted priorities and closed this site down.</p>
|
||||
<app-tech-stack [stack]="app.techStack"></app-tech-stack>
|
||||
<app-all-solutions-link></app-all-solutions-link>
|
||||
</article>
|
||||
</div>
|
@ -1,18 +0,0 @@
|
||||
import { Component, Input } from '@angular/core'
|
||||
|
||||
import { AppDetailComponent } from './app-detail.component'
|
||||
import { App } from '../application.types'
|
||||
|
||||
@Component({
|
||||
selector: 'app-hard-corps-wife',
|
||||
templateUrl: './hard-corps-wife.component.html'
|
||||
})
|
||||
export class HardCorpsWifeComponent extends AppDetailComponent {
|
||||
|
||||
@Input() app: App
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
<app-page-title [title]="pageTitle"></app-page-title>
|
||||
<app-application-header [app]="app"></app-application-header>
|
||||
<div class="app-info">
|
||||
<article class="content">
|
||||
<app-application-image [app]="app"></app-application-image>
|
||||
<h3>The Client</h3>
|
||||
<p>
|
||||
<a routerLink="/solutions/dr-melissa-clouthier">Melissa Clouthier</a>, Bill Dupray, and Clyde Middleton, all
|
||||
established conservative bloggers, started a joint venture called <em>Liberty Pundits</em>.
|
||||
</p>
|
||||
<h3>The Problem</h3>
|
||||
<p>
|
||||
Bill and Clyde had a significant amount of content on a prior site. As they were starting this with established
|
||||
authors, they needed a site that would handle their expected traffic spikes on popular posts.
|
||||
</p>
|
||||
<h3>The Solution</h3>
|
||||
<p>
|
||||
In early 2010, we migrated their content from a custom solution into WordPress's database; we then set them up on
|
||||
the same host where their podcast was being distributed. However, the combination of theme complexity and traffic
|
||||
overwhelmed that server, so we configured a standalone server with more memory and more efficient software; this
|
||||
allowed them to routinely eclipse 100,000 views per day, most of those coming on posts within the first few
|
||||
hours.
|
||||
</p>
|
||||
<h3>The Epilogue</h3>
|
||||
<p>
|
||||
The site closed in late 2011, as its authors closed their joint venture and moved on to other sites and topics.
|
||||
</p>
|
||||
<app-hide-section heading="The Process">
|
||||
<p>
|
||||
Before we could migrate the data from <em>Patriot Room</em>, Bill and Clyde's prior home, we had to get into
|
||||
the server and determine how data was stored in the custom solution. Once we identified where all the data was,
|
||||
we wrote a custom migration script to shape the data the way WordPress needed it.
|
||||
</p>
|
||||
<p>
|
||||
Bit Badger Solutions maintained the server, keeping it current with performance and security upgrades. We also
|
||||
provided support to the primary 3 bloggers, when they had questions about WordPress or how the site was
|
||||
performing.
|
||||
</p>
|
||||
</app-hide-section>
|
||||
<app-tech-stack [stack]="app.techStack"></app-tech-stack>
|
||||
<app-all-solutions-link></app-all-solutions-link>
|
||||
</article>
|
||||
</div>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user