Skip to content

Instantly share code, notes, and snippets.

@jasonleow
Created July 4, 2024 07:42
Show Gist options
  • Save jasonleow/778e9d4b63584bd33c93dfd61554119d to your computer and use it in GitHub Desktop.
Save jasonleow/778e9d4b63584bd33c93dfd61554119d to your computer and use it in GitHub Desktop.
jasonleow.com project portfolio site - Vue, Tailwind
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.7.8/vue.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
<style>
</style>
</head>
<body>
<div id="app">
<div>
<!-- <h1 class="text-5xl font-semibold text-center m-5 leading-tight">{{ message }}</h1> -->
<!-- tailwind product component -->
<div v-for="project in projects" :key="project.id">
<div class="flex flex-col justify-center my-8">
<div class="relative flex flex-col md:flex-row md:space-x-5 space-y-3 md:space-y-0 rounded-xl shadow-xl p-3 max-w-xs md:max-w-3xl mx-auto border border-gray-100 bg-white">
<div class="w-full md:w-1/3 bg-white grid place-items-center rounded-lg border border-0 border-gray-100 border-solid">
<a :href=`https://${project.url}` class="">
<img :src="`${project.logo}`" :alt="`${project.name}` + ' logo'" class="rounded-xl w-50 h-50 hover:opacity-50" />
</a>
</div>
<div class="w-full md:w-2/3 bg-white flex flex-col space-y-2 p-3">
<div class="flex justify-between item-center">
<p class="text-gray-500 font-medium hidden md:block">{{project.type}}</p>
<div class="flex items-center">
<p class="text-gray-600 font-bold text-sm">
{{project.year}}
<span class="text-gray-500 font-normal">{{yearsSinceFn(project.year)}}</span>
</p>
</div>
<div v-if="`${project.status}` == 'Active'" class="bg-green-200 px-3 py-1 rounded-full text-xs font-medium text-gray-800">
{{project.status}}
</div>
<div v-else-if="`${project.status}` == 'Paused'" class="bg-yellow-200 px-3 py-1 rounded-full text-xs font-medium text-gray-800">
{{project.status}}
</div>
<div v-else-if="`${project.status}` == 'Closed'" class="bg-red-200 px-3 py-1 rounded-full text-xs font-medium text-gray-800">
{{project.status}}
</div>
<div v-else class="bg-gray-200 px-3 py-1 rounded-full text-xs font-medium text-gray-800">
{{project.status}}
</div>
</div>
<h3 class="font-black text-gray-700 md:text-3xl text-xl py-3">{{project.name}}</h3>
<p class="md:text-lg text-gray-500 text-base py-2">{{project.description}}</p>
<div class="w-full md:w-3/3 bg-white flex flex-col space-y-2">
<div class="flex justify-between item-center">
<a :href=`https://${project.url}` class="text-gray-600 font-normal text-sm hover:text-gray-300">
{{project.url}}
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
<script>
var app = new Vue({
el: '#app',
data: {
message: 'Hello, World!',
isActive: '',
projects: [{
id: 1,
hashtag: "indiejourney",
name: "Jason's indie solopreneur journey",
description: "Sharing my indie solopreneur journey and growing an audience on Substack and Twitter.",
url: "jasonleow.substack.com",
logo: "https://i.ibb.co/xSNVh5J/linkedin-profile-pic.jpg",
type: "Newsletter",
status: "Active",
year: "2023",
revenue: "$0/y",
filters: ["ALL", "Newsletter", "Active", "None", "substack"]
},
{
id: 2,
hashtag: "pluginsforcarrd",
name: "Jason's Plugins For Carrd",
description: "Plugins, widgets, components, & scripts to power up your Carrd sites.",
url: "plugins.carrd.co",
logo: "https://navbar.carrd.co/assets/images/image01.jpg",
type: "Software",
status: "Active",
year: "2020",
revenue: "$1000/m",
filters: ["ALL", "Software", "Active", "One-time", "pluginsforcarrd"]
},
{
id: 3,
hashtag: "lifelog",
name: "Lifelog",
description: "Write 100 words a day, every day. A writing community for creators to develop a daily writing habit.",
url: "golifelog.com",
logo: "https://i.ibb.co/pZRTs9z/Group-141-Copy.jpg",
type: "SaaS",
status: "Active",
year: "2020",
revenue: "$100/m",
filters: ["ALL", "Software", "Active", "Recurring", "lifelog"]
},
{
id: 4,
hashtag: "listskit",
name: "Lists Kit",
description: "A plain HTML, CSS, JavaScript boilerplate for making business directories with minimal maintenance.",
url: "listskit.com",
logo: "https://i.postimg.cc/bNXXp1ZL/listskit-icon-transparent.png",
type: "Software",
status: "Active",
year: "2024",
revenue: "$500/y",
filters: ["ALL", "Software", "Active", "One-time", "listskit"]
},
{
id: 5,
hashtag: "outsprint",
name: "Outsprint Design",
description: "The fastest way to innovate public policy & social services.",
url: "outsprint.io",
logo: "https://i.ibb.co/TYx3v9v/outsprint-400x400.jpg",
type: "Service",
status: "Active",
year: "2015",
revenue: "$50,000/y",
filters: ["ALL", "Service", "Active", "Fee-based", "outsprint"]
},
{
id: 6,
hashtag: "sheet2bio",
name: "Sheet2Bio",
description: "Create a link-in-bio using Google Sheets. For creators and indie hackers.",
url: "sheet2bio.com",
logo: "https://i.ibb.co/sygHyT3/sheet2bio-square-thumbnail.png",
type: "SaaS",
status: "Paused",
year: "2022",
revenue: "$100",
filters: ["ALL", "SaaS", "Paused", "One-time", "sheet2bio"]
},
{
id: 7,
hashtag: "ketolistsg",
name: "Keto List Singapore",
description: "Singapore's local directory of LCHF, keto-friendly bakeries, restaurants, cafes, supermarkets and online retail outlets.",
url: "ketolistsingapore.com",
logo: "https://i.ibb.co/yNVjpXy/ketolistsg-logo-new-greensquare.png",
type: "Info product",
status: "Active",
year: "2019",
revenue: "$0/y",
filters: ["ALL", "Info product", "Active", "One-time", "ketolistsg"]
},
{
id: 8,
hashtag: "granthunt",
name: "Grant Hunt",
description: "Easiest way to hunt down that grant for your social impact project, using a chat bot.",
url: "gogranthunt.com",
logo: "https://i.ibb.co/wKSWW8Q/granthuntlogo.png",
type: "Info product",
status: "Paused",
year: "2018",
revenue: "$0",
filters: ["ALL", "Info product", "Paused", "One-time", "granthunt"]
},
{
id: 9,
hashtag: "safedistancingsg",
name: "Safe Distancing SG ๐Ÿ‡ธ๐Ÿ‡ฌ",
description: "The latest COVID-19 safe distancing rules for Singapore all in one place.",
url: "safedistancing.sg",
logo: "https://i.ibb.co/7zF13xJ/safedistancingsg-logo.png",
type: "Info product",
status: "Closed",
year: "2021",
revenue: "$1000+",
filters: ["ALL", "Info product", "Closed", "One-time", "safedistancingsg"]
},
{
id: 10,
hashtag: "psisg",
name: "PSI.SG ๐Ÿ‡ธ๐Ÿ‡ฌ",
description: "Quick updates at a glance on PSI and PM2.5 readings for the haze situation in Singapore.",
url: "psi.sg",
logo: "https://i.postimg.cc/4NYP309T/psisg-logo2-7.png",
type: "Single page app",
status: "Active",
year: "2023",
revenue: "$0",
filters: ["ALL", "Single page app", "Active", "Free", "psisg"]
},
{
id: 11,
hashtag: "uvindexsg",
name: "UVIndex.SG ๐Ÿ‡ธ๐Ÿ‡ฌ",
description: "Quick updates at a glance on UV Index readings for sunny Singapore.",
url: "uvindex.sg",
logo: "https://i.postimg.cc/0NkJz6BJ/uvindexsg-logo-500px.png",
type: "Single page app",
status: "Active",
year: "2024",
revenue: "$0",
filters: ["ALL", "Single page app", "Active", "Free", "uvindexsg"]
},
],
},
computed: {},
mounted: {},
methods: {
yearsSinceFn(startYear) {
const d = new Date()
let year = d.getFullYear() - startYear
if (year == 0) {
return ''
} else if (year == 1) {
return '(' + year + ' year)'
} else {
return '(' + year + ' years)'
}
},
},
})
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment