From f2d7855fa3a689d5f1023e3c043d07bf8750f714 Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Sat, 9 Nov 2019 18:51:34 -0600 Subject: [PATCH] Add applications list and detail pages done; still need to do sidebar --- .../src/app/app-routing.module.ts | 6 +- .../application-list-item.component.html | 9 + .../application-list-item.component.sass | 5 + .../application-list-item.component.ts | 18 + .../application-list.component.html | 8 + .../application-list.component.ts | 25 + .../src/app/applications/application.data.ts | 600 ++++++++++++++++++ .../app/applications/application.service.ts | 48 ++ .../src/app/applications/application.types.ts | 115 ++++ .../application/application.component.html | 35 + .../application/application.component.sass | 21 + .../application/application.component.ts | 50 ++ .../app/applications/applications.module.ts | 24 +- .../about/process-automation.component.html | 2 +- .../app/shared/footer/footer.component.html | 2 +- .../src/app/shared/shared.module.ts | 5 +- bit-badger-solutions/src/index.html | 2 +- 17 files changed, 965 insertions(+), 10 deletions(-) create mode 100644 bit-badger-solutions/src/app/applications/application-list-item/application-list-item.component.html create mode 100644 bit-badger-solutions/src/app/applications/application-list-item/application-list-item.component.sass create mode 100644 bit-badger-solutions/src/app/applications/application-list-item/application-list-item.component.ts create mode 100644 bit-badger-solutions/src/app/applications/application-list/application-list.component.html create mode 100644 bit-badger-solutions/src/app/applications/application-list/application-list.component.ts create mode 100644 bit-badger-solutions/src/app/applications/application.data.ts create mode 100644 bit-badger-solutions/src/app/applications/application.service.ts create mode 100644 bit-badger-solutions/src/app/applications/application.types.ts create mode 100644 bit-badger-solutions/src/app/applications/application/application.component.html create mode 100644 bit-badger-solutions/src/app/applications/application/application.component.sass create mode 100644 bit-badger-solutions/src/app/applications/application/application.component.ts diff --git a/bit-badger-solutions/src/app/app-routing.module.ts b/bit-badger-solutions/src/app/app-routing.module.ts index b144d4e..dc86f8a 100644 --- a/bit-badger-solutions/src/app/app-routing.module.ts +++ b/bit-badger-solutions/src/app/app-routing.module.ts @@ -1,6 +1,8 @@ import { NgModule } from '@angular/core' import { Routes, RouterModule } from '@angular/router' +import { ApplicationComponent } from './applications/application/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' @@ -14,7 +16,9 @@ const routes: Routes = [ { 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: 'about/why-bit-badger', component: WhyBitBadgerComponent }, + { path: 'solutions', component: ApplicationListComponent }, + { path: 'solutions/:appId', component: ApplicationComponent } ]; @NgModule({ diff --git a/bit-badger-solutions/src/app/applications/application-list-item/application-list-item.component.html b/bit-badger-solutions/src/app/applications/application-list-item/application-list-item.component.html new file mode 100644 index 0000000..ed79de5 --- /dev/null +++ b/bit-badger-solutions/src/app/applications/application-list-item/application-list-item.component.html @@ -0,0 +1,9 @@ +

+  ~ About +  ~ Visit + + ~ Visit (archive) + +
+ +

diff --git a/bit-badger-solutions/src/app/applications/application-list-item/application-list-item.component.sass b/bit-badger-solutions/src/app/applications/application-list-item/application-list-item.component.sass new file mode 100644 index 0000000..8c0c02d --- /dev/null +++ b/bit-badger-solutions/src/app/applications/application-list-item/application-list-item.component.sass @@ -0,0 +1,5 @@ +.app-name + font-family: "Oswald", "Segoe UI", Ubuntu, "DejaVu Sans", "Liberation Sans", Arial, sans-serif + font-size: 1.3rem + font-weight: bold + color: maroon diff --git a/bit-badger-solutions/src/app/applications/application-list-item/application-list-item.component.ts b/bit-badger-solutions/src/app/applications/application-list-item/application-list-item.component.ts new file mode 100644 index 0000000..60fc926 --- /dev/null +++ b/bit-badger-solutions/src/app/applications/application-list-item/application-list-item.component.ts @@ -0,0 +1,18 @@ +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() { } + +} diff --git a/bit-badger-solutions/src/app/applications/application-list/application-list.component.html b/bit-badger-solutions/src/app/applications/application-list/application-list.component.html new file mode 100644 index 0000000..677e19a --- /dev/null +++ b/bit-badger-solutions/src/app/applications/application-list/application-list.component.html @@ -0,0 +1,8 @@ + +
+

All Solutions

+

Active Solutions

+ +

Past Solutions

+ +
diff --git a/bit-badger-solutions/src/app/applications/application-list/application-list.component.ts b/bit-badger-solutions/src/app/applications/application-list/application-list.component.ts new file mode 100644 index 0000000..085e534 --- /dev/null +++ b/bit-badger-solutions/src/app/applications/application-list/application-list.component.ts @@ -0,0 +1,25 @@ +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) + }) + } + +} diff --git a/bit-badger-solutions/src/app/applications/application.data.ts b/bit-badger-solutions/src/app/applications/application.data.ts new file mode 100644 index 0000000..d4f0ca9 --- /dev/null +++ b/bit-badger-solutions/src/app/applications/application.data.ts @@ -0,0 +1,600 @@ +import { App, Activity, 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.paragraphs = [ + `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 FEMA + during Hurricane Katrina relief and recovery efforts, and they are a relay point for each year’s + Operation Christmas Child + campaign. As of late 2013, the authors of their current website were no longer around, and no one could get to the + site to update it. We proposed setting up a site based on WordPress, where multiple people could have the ability to + maintain the site, reducing the risk of that happening again. We also mentioned that such a site could also serve a + sermon podcast feed, increasing the reach of their ministry.` +] +bayVista.activities = [ + new Activity('What We Did (2014)', + `We manually downloaded all the publically-accessible parts of their old site, and used that content to create a + WordPress-based site, updating a few outdated items along the way. We also established a podcast feed for their + sermons. A few months after initially setting up the site, we updated the theme to be more mobile-friendly.`), + new Activity('What We Did (2016)', + `In the nearly three years since we had set up the site, we were the only ones updating it. We had recently migrated + some older blogs to use a static site generator and were impressed with the performance gains. We converted their + site, to include writing a custom template to support the podcast feed; it is now generated along with the rest of + the site.`), + new Activity('What We Still Do', + `Bit Badger Solutions hosts this site; we also host the church e-mail accounts, and publish sermons to their podcast + feed weekly.`) +] +bayVista.techStack = [ + new Technology('Hexo', 'static site generation'), + new Technology('Azure', 'podcast file 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.paragraphs = [ + `Cassy Fiano (now Cassy Chesser) began blogging back in 2007 on Blogger. She worked hard to network with other + bloggers, and wrote prolifically. As she approached the end of her first year of blogging, she was about to outgrow + Blogger. She asked in a blog post if anyone had experience with Movable Type, the platform used by another blog to + which she contributed. I replied that I did not, but that I had experience with WordPress.` +] +cassyFiano.activities = [ + new Activity('What We Did (2008)', + `We assisted her with finding a theme, and customized that theme to contain the same sidebar elements as her current + Blogger theme. We modified her old Blogger template to send people to her new blog (using redirection) after + displaying a note that the blog had moved.`), + new Activity('What We Did (2012)', + `In July 2012, we began hosting the site, as well as continuing support for theme updates. This joined her military + wife blog Hard Corps Wife, + which we had begun hosting in mid-2011.`), + new Activity('What We Still Do', 'Cassy formally decommissioned this site in early 2014.') +] +cassyFiano.techStack = [ new Technology('WordPress', 'blogging (with a custom theme)') ] + +/** 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.paragraphs = [ + `Dr. Melissa Clouthier saw our work with + Cassy’s site, and asked us to + help her move off Blogger as well. Melissa blogs from the political right, but also covers health issues and social + media. She had been blogging for a several years, and wanted to bring her old content with her to her new site.` +] +drMelissaClouthier.activities = [ + new Activity('What We Did (2009)', + `We created a custom theme based on another site, and developed graphics to complement that theme. We also imported + the content from her Blogger site into the WordPress site, and created a featured content template for the front + page.`), + new Activity('What We Did (2018)', + `Melissa decommissioned her site; we took final snapshots of the information there, then assisted with shutting it + down.`) +] +drMelissaClouthier.footnotes = [ + `(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.)` +] +drMelissaClouthier.techStack = [ new Technology('WordPress', 'blogging (with a custom theme)') ] + +/** 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.paragraphs = [ + `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.` +] +emcs.activities = [ + new Activity('What We Did (2004)', + `They had a website with very basic information and very little styling. We developed a theme (the one in the + thumbnail), based in large part on the design of their printed materials, and they approved the design. Initially, + the site only contained the content from their previous site. We then put their school calendar of events up on + the site, where parents could find the dates for upcoming events. Finally, we put all the material from their + Parent Information Packet online, which helped prospective families learn more about the school before visiting + it.`), + new Activity('What We Did (2011)', + `The underlying engine of the basic website was switched from PHP to an ASP MVC web application, and the back-end + database was switched from MySQL to a PostgreSQL database.`), + new Activity('What We Did (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.`) +] +emcs.techStack = [ + new Technology('ASP.NET MVC', 'page generation and interactivity'), + new Technology('PostgreSQL', 'data storage') +] + +/** 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' +futilityCloset.paragraphs = [ + `Futility Closet exists as a place to give people a break from the dullness of work, by providing puzzles, anecdotes, + and more. It began on a shared host, but was growing too large and popular for that platform.` +] +futilityCloset.activities = [ + new Activity('What We Did', + `We determined what the traffic requirements and size of the blog were, then made some recommendations. Greg Ross, + the site author, decided on one of our recommendations. He had backups of the existing database, so we were able to + set up a server and restore the data onto that new server. We configured WordPress and locked down the server, and + this blog was moved quickly.`), + new Activity('What We Still Do', + `Bit Badger Solutions still hosts Futility Closet, ensuring that the underlying server receives performance and + security upgrades, monitoring site performance, and maintaining regular backups.`) +] +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'), + new Technology('nginx', 'the web server') +] + +/** 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.paragraphs = [ + `Capitalizing on the growth from her Cassy Fiano blog, Cassy (now Chesser) began a separate blog in which she could + chronicle her experience as a military spouse.` +] +hardCorpsWife.activities = [ + new Activity('What We Did', + 'We customized the header and sidebar of the theme, and set up the hardcorpswife.com domain.'), + new Activity('What We Still Do', + `In 2013, Cassy shifted priorities and closed this site down. She can still be found at other places around the + web.`) +] +hardCorpsWife.techStack = [ new Technology('WordPress', 'blogging') ] + +/** 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.paragraphs = [ + `At its founding, Liberty Pundits was a joint venture by 3 established bloggers (Melissa Clouthier, Bill Dupray, and + Clyde Middleton) that, in their words, was aimed at becoming the new home for conservatives on the Internet. With the + three of them all being prolific bloggers in their own right, and the help of many contributors, Liberty Pundits was + a bustling hub of information.` +] +libertyPundits.activities = [ + new Activity('What We Did', + `Bill and Clyde had been part of Patriot Room, an already-recognized powerhouse, and their desire was for Liberty + Pundits to contain the content that they had contributed to Patriot Room. The technical lead on that blog had moved + on, so we did some divining of what was there. Once we deduced the current setup, we obtained the data from that + site, determined how it would need to be manipulated to become part of a WordPress blog, then accomplished the data + migration. Initially, this was deployed on the same shared hosting account where LibertyPundits.com, their podcast + distribution site, already resided. The site’s traffic quickly overwhelmed that solution. They then were + moved by their host to a VPS, which performed moderately better, but + still had quite a few issues, mostly related to the site’s traffic volume. We recommended a new server + configuration, including migrating from a fully-featured web server to a more lightweight web server, along with + caching, and configured that server. This configuration eliminated the bottlenecks, and enabled them to have + several 100,000+ hit days with no appreciable slowdowns.`), + new Activity('What We Still Do', + `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. + The site closed in August of 2011, as the primary authors moved on to other endeavors.`) +] +libertyPundits.techStack = [ + new Technology('WordPress', 'blogging'), + new Technology('Custom software', 'data migration') +] + +/** 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 = 'Wall Street Journal best-selling author and C-suite advisor' +mindyMackenzie.paragraphs = [ + `Mindy Mackenzie, the prior Chief Performance Officer of Beam, Inc., is known as the “Velvet Hammer” + for her tough-yet-caring style of leadership. Her Wall Street Journal best-selling book The Courage + Solution: The Power of Truth-Telling with Your Boss, Peers, and Team details her spin-free approach to personal + and business success.` +] +mindyMackenzie.activities = [ + new Activity('What We Did (2015)', + `We assumed maintenance of her site several months in advance of the book launch of The Courage Solution. + We worked with her, and her publicists and other professionals, to ensure that the book launch went smoothly. We + customized her WordPress installation to support her Media Appearances in a way that allowed them to be entered, + tracked, and listed as of the date they occurred. We also implemented rotating videos on the front page of the + site.`), + new Activity('What We Did (2018)', + `We developed the pages for her You First Integrative Leadership Summit, with speaker bios, conference + schedule, and an application form.`), + new Activity('What We Still Do', + 'We continue to provide backups, WordPress support, and content updates for Mindy’s site.') +] +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'), + new Technology('nginx', 'the web server') +] + +/** 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.paragraphs = [ + `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. He believed that he was not the only person + who felt this way regarding prayer, and decided to use this as an opportunity to fill both a spiritual and a learning + need. Given Auth0's policy of offering free authentication services for open-source + applications, he decided to develop this as an open-source application.`, + `The goal of myPrayerJournal is to get out of the way, so that the user can focus on the requests and their prayer; + once requests have been entered, the journal provides a way to easily pray through these requests, helping people not + forget about active requests. It also provides a means of going back through answered requests, which can be reviewed + whenever the user desires. There is a documentation page + that fully describes all it can do.`, + `As an open-source project, anyone can review the source code on + GitHub; we also track open issues there.` +] +myPrayerJournal.activities = [ + new Activity('What We Did (2017-2018)', + `We went through several iterations of front-end and back-end technologies, trying to find one that would provide + the optimal experience for praying through the list. The front end uses Vue.js, and + the back end uses Giraffe to serve the data.`), + new Activity('What We Still Do', + `Bit Badger Solutions hosts the instance of this at the URL linked above. We back up the data, and also continue to + develop it. Anyone can use it by logging in with a Google or Microsoft account.`) +] +myPrayerJournal.techStack = [ + new Technology('Vue', 'the front-end'), + new Technology('Giraffe', 'the back-end data API'), + 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.paragraphs = [ + `In January 2008, a few members of Hoffmantown Church + in Albuquerque, New Mexico had an idea. The ABC show + Extreme Makeover: Home Edition had just + done a build for a pastor in the “war zone” area + of town, 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, 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. From an idea in January to 57 families helped by March 29th, it was an amazing whirlwind.` +] +nsx.activities = [ + new Activity('What We Did', + `The call went out for the need for “everything from carpenters to computer nerds,” and Daniel thought, + “Hey, I’m a computer nerd!” We obtained the domain name and stood up the public website quickly + using WordPress, which also allowed the coordinators to put content up. We next began developing 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, we generated + schedules and reports that were used to track the execution of the project.

After we recovered, Love INC + expressed an interest in a version that would allow them to handle these same areas on an ongoing basis; this was + the genesis of TCMS.`), + new Activity('What We Still Do', + `NSXapp was officially decommissioned in 2012. (It still exists in archived form, if a need arises to use it again.) + A snapshot of the NSX public site remains as a record of + what happened those three months in 2008.`) +] +nsx.techStack = [ + new Technology('WordPress', 'content management'), + new Technology('Custom PHP code', 'NSXapp'), + new Technology('PostgreSQL', '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.paragraphs = [ + `Olivet Baptist Church’s pastor saw our work with Bay Vista, and asked us what would be involved with + setting up something similar for his church. Olivet did not currently have a website.` +] +olivet.activities = [ + new Activity('What We Did (2014)', + `We registered the domain name for the church, then set up a fresh WordPress install. 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. We + also, as with Bay Vista, established the framework for a sermon podcast feed.`), + new Activity('What We Did (2016)', + `As with Bay Vista’s site, this was converted to be a statically-generated site. We also created a + mobile-friendly site layout that looked similar to the one they had been using.`), + new Activity('What We Did (2018)', + `We turned their site into a Progressive Web Application (PWA), which allows users to “install” the + site, like an app, to their phone’s home screen. The site is also still accessible from the web via a + browser.`), + new Activity('What We Did (2019)', + `The church closed its doors February 24th, 2019. We converted the PWA back to a static web site, set up a static + 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.`) +] +olivet.techStack = [ + new Technology('Vue', 'the user interface for the PWA'), + new Technology('Hexo', `generating the site's pages`), + new Technology('Azure', 'podcast file 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.paragraphs = [ + `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. Thus was + born Photography by Michelle. She specializes in outdoor photography of families, children, and sports teams, as well + as maternity photography and holiday cards.` +] +photographyByMichelle.activities = [ + new Activity('What We Did (2007)', + `We created the site with a few custom pages, including a gallery page that would automatically display whatever + pictures were there. We also, using WordPress and a custom image plugin, set up a site where customers can view the + proofs from their photography session.`), + new Activity('What We Did (2012)', + `The custom PHP/WordPress site was replaced by a custom ASP MVC web application, which handles the front pages and + the proof set galleries. The proof display was also upgraded to allow cursor-key navigation of proofs.`), + new Activity('What We Still Do', + `As Michelle is no longer doing professional photography, the current version of this site is a simple thank-you to + her customers over the years.`) +] +photographyByMichelle.techStack = [ new Technology('ASP.NET MVC', 'content management') ] + +/** 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.paragraphs = [ + `Years ago, Daniel was responsible for keeping up with prayer requests for his Sunday School class. To help him keep + up with requests, automatically drop requests that were old, and track long-term requests, he wrote a custom app made + up of a few pages. Over time, he added security mechanisms and other options, arriving at the site that exists today. + It is provided free for the asking to any church, Sunday School class, or small group that desires a tool to help + them establish a continuous list of prayer requests.` +] +prayerTracker.activities = [ + new Activity('What We Did (2005)', 'Created the original site.'), + new Activity('What We Did (2011)', + `We rewrote this application using a more modern (at the time) framework (ASP MVC 3), building the security + additions from the ground up, and posturing it for an interface with Virtual Prayer Room.`), + new Activity('What We Did (2012)', + 'In April 2012, version 4 was released with support for Spanish - our first multi-lingual application!'), + new Activity('What We Did (2018)', + 'Version 7 brought full mobile accessibility, along with an upgrade to a modern, ultra-fast web framework.'), + new Activity('What We Did (2019)', + 'PrayerTracker became an open source project.'), + new Activity('What We Still Do', 'Host and maintain this application.') +] +prayerTracker.techStack = [ + new Technology('Giraffe', 'server-side logic and dynamic page generation'), + new Technology('PostgreSQL', 'data storage') +] + +/** 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.paragraphs = [ + `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. He wanted to take his blog in a + different direction, and was having trouble getting his Movable Type blog do move with him.` +] +riehlWorldNews.activities = [ + new Activity('What We Did (2012)', + `We spoke with him regarding his ideal direction and assisted through the selection and customization of his + eventual chosen theme. We also did some work on the customization of that theme. Additionally, we imported the + large volume of posts from the Movable Type blog into his new WordPress blog.`), + new Activity('What We Did (2018)', + `Dan wanted a fresh start for Riehl World View, so we generated flat files to preserve his prior archive. The post + volume meant that none of the existing WordPress plugins that do that would work, so we built a custom converter + to preserve that content.`), + new Activity('What We Still Do', + 'Bit Badger Solutions continues to provide backups and WordPress updates for Riehl World News.') +] +riehlWorldNews.techStack = [ + new Technology('WordPress', 'blogging'), + new Technology('Custom F# code', 'archive static page generation') +] + +/** 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.paragraphs = [ + `The TCMS motto, “Putting People Over Paperwork,” sums up the mission of this system. To successfully run + a needs clearinghouse, such as those run by Love INC affiliates, there is a lot of paperwork involved. Clients must + be tracked, along with their needs; these needs must be verified; resources for goods and services must be known; + volunteers must be known and sent communications to keep them involved. All of this adds up to a significant + recordkeeping (i.e., paperwork) burden.`, + `TCMS addressed these issues by providing a repository for all clearinghouse operation needs. It helped eliminate + duplication of work, and also linke clients with goods and services. It also provided the means to communicate with + volunteers, either en masse or using selective criteria. This allowed the recordkeeping requirement to be smaller + and quicker, giving more time for the actual helping of clients. It used WordPress for its front end; this provided + organizations with a web presence that they could maintain without having to employ a web guru, using + WordPress’s WYSIWYG editor and management tools.`, + `TCMS was decommissioned in 2014.` +] +tcms.techStack = [ + new Technology('Custom PHP code', 'the application logic'), + new Technology('WordPress', 'publicly-facing pages and authentication'), + new Technology('PostgreSQL', 'application 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.paragraphs = [ + `The Bit Badger Blog grew from Daniel’s personal experience with learning and using the Linux operating system. + His first experience with blogging consisted of pages that had to be edited every time a new post was made. The + initial posts were titled “My Linux Adventure,” and existed as a copy of this home-grown blog. The Bit + Badger Blog has that, plus tech tips regarding many different computer products. It covers web servers, databases, + programming languages, and open-source software. Bit Badger Solutions also hosts 64-bit RPM builds of xine, a Linux + multimedia player; the blog, via the RSS feed for that category, can deliver notices of updated versions directly to + subscribed users. Finally, it also contains notices of new versions of Bit Badger Solutions-developed WordPress + plug-ins (“Daniel’s Dropdowns” (inactive, as its functionality is now part of the WordPress + core) and “HCSB Verse of the Day (Plus)”).`, + `It is currently a statically-generated site, utilizing Hexo, and its code is + open source.` +] +techBlog.techStack = [ new Technology('Hexo', 'static site 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.paragraphs = [ + `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 are continuing their focused news and + opinion to current political races.` +] +theSharkTank.activities = [ + new Activity('What We Did', + `They were displeased with their current theme, and had found a theme (and a demo site) that they preferred. We set + up the theme, ensured 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.`) +] + +/** 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.paragraphs = [ + `Many churches have prayer rooms – rooms set aside for people to come in to pray. Hoffmantown Church in + Albuquerque, New Mexico was one of these churches. However, they 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.`, + `Having seen our work with the Not So Extreme Makeover: Community + Edition, the church contacted us to see if something similar could be developed to help their prayer ministry. + The resulting application that was developed extended the prayer room to wherever the 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.`, + `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.` +] +vpr.techStack = [ + new Technology('Custom PHP code', 'the application'), + 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 + ] +} diff --git a/bit-badger-solutions/src/app/applications/application.service.ts b/bit-badger-solutions/src/app/applications/application.service.ts new file mode 100644 index 0000000..4a1dc0b --- /dev/null +++ b/bit-badger-solutions/src/app/applications/application.service.ts @@ -0,0 +1,48 @@ +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 { + return of(Data.categories) + } + + /** + * Get all apps + */ + getApps(): Observable { + 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 { + 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 { + return of(Data.apps.find(app => app.id === appId)) + } + +} diff --git a/bit-badger-solutions/src/app/applications/application.types.ts b/bit-badger-solutions/src/app/applications/application.types.ts new file mode 100644 index 0000000..65bdcbb --- /dev/null +++ b/bit-badger-solutions/src/app/applications/application.types.ts @@ -0,0 +1,115 @@ +/** An activity performed for a customer */ +export class Activity { + + /** + * Construct a new instance + * @param heading The heading of the activity + * @param narrative The description of the activity + */ + constructor(public heading: string, public narrative: string) { } +} + +/** 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 + */ + constructor(public name: string, public usedFor: string) { } +} + +/** 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 = '' + + /** Paragraphs of text that describe the app */ + paragraphs: string[] = [] + + /** Footnotes for the long description */ + footnotes: string[] = [] + + /** Discrete activities performed for this app */ + activities: Activity[] = [] + + /** 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) { } +} diff --git a/bit-badger-solutions/src/app/applications/application/application.component.html b/bit-badger-solutions/src/app/applications/application/application.component.html new file mode 100644 index 0000000..f2796b8 --- /dev/null +++ b/bit-badger-solutions/src/app/applications/application/application.component.html @@ -0,0 +1,35 @@ + +
+

+ {{ application.name }}
+ + {{ application.url }} + {{ application.url }} +     + (Archive) + + +

+
+ +
+

+
+

{{ act.heading }}

+

+
+
+

What They Say

+
+

+

+ — {{ q.name }} + , {{ q.from }} +

+
+
+

+


« Back to All Solutions

+
+
+
diff --git a/bit-badger-solutions/src/app/applications/application/application.component.sass b/bit-badger-solutions/src/app/applications/application/application.component.sass new file mode 100644 index 0000000..8a12cfd --- /dev/null +++ b/bit-badger-solutions/src/app/applications/application/application.component.sass @@ -0,0 +1,21 @@ +h1 + line-height: 1.6rem +.app-info + display: flex + flex-flow: row-reverse wrap + justify-content: center +aside + padding-left: 15px +aside img + border: dotted 1px darkgray + border-radius: 10px +blockquote + border-left: solid 1px darkgray + margin-left: 25px + padding-left: 15px +.quote + font-style: italic +.source + text-align: right + padding-right: 60px + \ No newline at end of file diff --git a/bit-badger-solutions/src/app/applications/application/application.component.ts b/bit-badger-solutions/src/app/applications/application/application.component.ts new file mode 100644 index 0000000..5e1abf6 --- /dev/null +++ b/bit-badger-solutions/src/app/applications/application/application.component.ts @@ -0,0 +1,50 @@ +import { Component, OnInit, Input } from '@angular/core' +import { ActivatedRoute } from '@angular/router' + +import { ApplicationService } from '../application.service' +import { App } from '../application.types' + +@Component({ + selector: 'app-application', + templateUrl: './application.component.html', + styleUrls: ['./application.component.sass'] +}) +export class ApplicationComponent implements OnInit { + + /** The app we're displaying */ + application: App + + /** The page title based on this app */ + pageTitle: string + + /** Whether to link to the app's URL */ + linkToApp: boolean + + /** Whether to link to an archive URL */ + linkToArchive: boolean + + /** The link to the screenshot image */ + imageLink: string + + /** The alt text for the screenshot image */ + imageAlt: string + + constructor( + private appService: ApplicationService, + private route: ActivatedRoute + ) { } + + ngOnInit() { + const appId = this.route.snapshot.paramMap.get('appId') + this.appService.getApp(appId) + .subscribe(app => { + this.application = app + this.pageTitle = `${app.name} « Solutions` + this.linkToApp = app.isActive || app.linkInactive + this.linkToArchive = !app.isActive && !app.linkInactive && (app.archiveUrl > '') + this.imageLink = `/assets/screenshots/${app.id}.png` + this.imageAlt = `Screen shot for ${app.name}` + }) + } + +} diff --git a/bit-badger-solutions/src/app/applications/applications.module.ts b/bit-badger-solutions/src/app/applications/applications.module.ts index 096f62b..c29000e 100644 --- a/bit-badger-solutions/src/app/applications/applications.module.ts +++ b/bit-badger-solutions/src/app/applications/applications.module.ts @@ -1,12 +1,26 @@ -import { NgModule } from '@angular/core'; -import { CommonModule } from '@angular/common'; - +import { NgModule } from '@angular/core' +import { CommonModule } from '@angular/common' +import { RouterModule } from '@angular/router' +import { SharedModule } from '../shared/shared.module' +import { ApplicationComponent } from './application/application.component'; +import { ApplicationListComponent } from './application-list/application-list.component'; +import { ApplicationListItemComponent } from './application-list-item/application-list-item.component' @NgModule({ - declarations: [], + declarations: [ + ApplicationComponent, + ApplicationListComponent, + ApplicationListItemComponent + ], imports: [ - CommonModule + CommonModule, + RouterModule, + SharedModule + ], + exports: [ + ApplicationComponent, + ApplicationListComponent ] }) export class ApplicationsModule { } diff --git a/bit-badger-solutions/src/app/pages/about/process-automation.component.html b/bit-badger-solutions/src/app/pages/about/process-automation.component.html index c1f6965..7879886 100644 --- a/bit-badger-solutions/src/app/pages/about/process-automation.component.html +++ b/bit-badger-solutions/src/app/pages/about/process-automation.component.html @@ -35,7 +35,7 @@
  • We continue to offer PrayerTracker - (about), + (about), 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.

    diff --git a/bit-badger-solutions/src/app/shared/footer/footer.component.html b/bit-badger-solutions/src/app/shared/footer/footer.component.html index 5aa5d83..7e7b6e2 100644 --- a/bit-badger-solutions/src/app/shared/footer/footer.component.html +++ b/bit-badger-solutions/src/app/shared/footer/footer.component.html @@ -1,3 +1,3 @@ diff --git a/bit-badger-solutions/src/app/shared/shared.module.ts b/bit-badger-solutions/src/app/shared/shared.module.ts index d7c8fc0..6939814 100644 --- a/bit-badger-solutions/src/app/shared/shared.module.ts +++ b/bit-badger-solutions/src/app/shared/shared.module.ts @@ -1,5 +1,7 @@ import { NgModule } from '@angular/core' import { CommonModule } from '@angular/common' +import { RouterModule } from '@angular/router' + import { HeaderComponent } from './header/header.component' import { FooterComponent } from './footer/footer.component'; import { PageTitleComponent } from './page-title.component' @@ -11,7 +13,8 @@ import { PageTitleComponent } from './page-title.component' PageTitleComponent ], imports: [ - CommonModule + CommonModule, + RouterModule ], exports: [ HeaderComponent, diff --git a/bit-badger-solutions/src/index.html b/bit-badger-solutions/src/index.html index 3834e8f..e25efa0 100644 --- a/bit-badger-solutions/src/index.html +++ b/bit-badger-solutions/src/index.html @@ -2,7 +2,7 @@ - BitBadgerSolutions + Bit Badger Solutions