Skip to content

Commit

Permalink
✨ feat(appaddurl): crowd sourced url (closes #24)
Browse files Browse the repository at this point in the history
closes #24
  • Loading branch information
MartinsOnuoha committed Nov 4, 2023
1 parent 0c0fa8b commit eeed9ab
Show file tree
Hide file tree
Showing 24 changed files with 321 additions and 60 deletions.
32 changes: 18 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,44 @@
# What Should I Design? 🎨

[![Build & Deploy 🚀](https://github.com/MartinsOnuoha/what-should-i-design/actions/workflows/firebase-hosting-merge.yml/badge.svg)](https://github.com/MartinsOnuoha/what-should-i-design/actions/workflows/firebase-hosting-merge.yml)

You're fresh out of learning UI/UX Design, you want to get your hands dirty with _almost_ real-world example problems to harness your design skills and build up a portfolio.
You're fresh out of learning UI/UX Design, you want to get your hands dirty with _almost_ real-world example problems to harness your design skills and build up a portfolio.
Problem is, You don't know what to design?.


Well [Fake Clients](https://fakeclients.com/) isn't completely Free and is limited, and [WhatshouldIdesign.com](http://www.whatshouldidesign.com/) is all jokes. So here's an alternative completely free and crowdsourced collection of real-world design problems to try.

![what-should-i-design-banner-image](https://whatshouldidesign.space/screen1.webp)
![what-should-i-design-banner-image](https://whatshouldidesign.space/screen2.webp)
![what-should-i-design-banner-image](https://whatshouldidesign.space/screen3.webp)

## Features
- Community Source UI/UX Design problem Statements
- Community Sourced Samples for each Statement
- Category Specific Statements

## How to Contribute

### Content
You can contribute to this project by sourcing more problem statements from anywhere, or just coming up with yours (you silly genius).
One recommended source would be [ChatGPT](https://chat.openai.com/).

Head over to [OpenAI chat](https://chat.openai.com/) and start a conversation to request as many design problem statement within any of the following categories [below](#problem-statements).
You can contribute to this project by sourcing more problem statements from anywhere, or just coming up with yours (you silly genius).
One recommended source would be [ChatGPT](https://chat.openai.com/).

Head over to [OpenAI chat](https://chat.openai.com/) and start a conversation to request as many design problem statement within any of the following categories [below](#problem-statements).

### Code

This project runs on Vue and Vite, feel free to create [issues](https://github.com/MartinsOnuoha/what-should-i-design/issues) first. Fork and open MRs for improvements.

## Problem Statements

<details open>
<summary>🛒 E-commerce</summary>

| Title | Description |
|--------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Artisanal Food Delivery App | Create a food delivery app specializing in artisanal and local food products. Prioritize an appealing marketplace and a simple ordering process. |
| Sustainable Fashion Marketplace | Create a sustainable fashion e-commerce platform that connects environmentally conscious shoppers with eco-friendly clothing brands. Design a user-friendly shopping experience with a focus on sustainability. |
| Grocery Delivery App | Design a mobile app for a grocery delivery service. Ensure a seamless user experience for browsing products, adding items to the cart, scheduling deliveries, and tracking orders. |
| E-commerce Marketplace for Handmade Crafts | Design an e-commerce platform exclusively for handmade craft products. Focus on creating a visually appealing and user-friendly marketplace for artisans and craft enthusiasts. |
| Title | Description | Samples |
|--------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|
| Artisanal Food Delivery App | Create a food delivery app specializing in artisanal and local food products. Prioritize an appealing marketplace and a simple ordering process. | |
| Sustainable Fashion Marketplace | Create a sustainable fashion e-commerce platform that connects environmentally conscious shoppers with eco-friendly clothing brands. Design a user-friendly shopping experience with a focus on sustainability. | |
| Grocery Delivery App | Design a mobile app for a grocery delivery service. Ensure a seamless user experience for browsing products, adding items to the cart, scheduling deliveries, and tracking orders. | |
| E-commerce Marketplace for Handmade Crafts | Design an e-commerce platform exclusively for handmade craft products. Focus on creating a visually appealing and user-friendly marketplace for artisans and craft enthusiasts. | |
</details>

<details>
Expand Down Expand Up @@ -243,8 +249,6 @@ This project runs on Vue and Vite, feel free to create [issues](https://github.c
<summary>🎮 Blockchain and Cryptocurrency Gaming</summary>
</details>



Here's a [sample chat](https://chat.openai.com/share/2aa6268a-7a4e-4740-bca4-f068e100126a)

You can open a new MR and update this [README](https://github.com/MartinsOnuoha/what-should-i-design/blob/master/README.md) adding new problem statements to the list above.
Expand Down
Binary file modified public/screen2.webp
Binary file not shown.
Binary file removed public/screen3.webp
Binary file not shown.
13 changes: 13 additions & 0 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,20 @@ input statements_bool_exp {
category_id: Int_comparison_exp
}


type Query {
categories: [Category!]!
statements(where: statements_bool_exp): [Statement!]!
}

input samples_insert_input {
statement_id: ID
url: String
}
type samples_mutation_response {
affected_rows: Int
}

type Mutation {
insert_samples(objects: [samples_insert_input!]!): samples_mutation_response
}
5 changes: 5 additions & 0 deletions src/assets/styles/color-scheme.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
body[color-scheme='dark'] {
@import '@/components/AppAddUrl/AppAddUrl.dark';
@import '@/components/AppAddUrl/AppAddUrlPreview.dark';
@import '@/components/AppFilter/AppFilter.dark';
@import '@/components/AppHeader/HeaderActions.dark';
@import '@/components/AppSideBanner/AppSideBanner.dark';
Expand All @@ -9,12 +11,15 @@ body[color-scheme='dark'] {
}

body[color-scheme='light'] {
@import '@/components/AppAddUrl/AppAddUrl';
@import '@/components/AppAddUrl/AppAddUrlPreview';
@import '@/components/AppCategory/AppCategory';
@import '@/components/AppFilter/AppFilter';
@import '@/components/AppHeader/HeaderActions';
@import '@/components/AppSideBanner/AppSideBanner';
@import '@/components/AppSidePanel/AppSidePanel';
@import '@/components/AppStatementCard/AppStatementCard';
@import '@/components/AppToggleDarkMode/AppToggleDarkMode';
@import '@/components/AppCommunity/AppLink';
@import '@/views/HomeView';
}
8 changes: 7 additions & 1 deletion src/assets/styles/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ body {
font-family: 'Ibarra Real Nova', serif;
color: var(--color-dark-text);

input {
input,
button {
&:disabled {
@apply cursor-not-allowed;
}
Expand All @@ -20,6 +21,11 @@ body {
@apply outline-amber-500;
}
}
button {
&:disabled {
@apply opacity-50;
}
}
}
.font {
&--fira {
Expand Down
90 changes: 67 additions & 23 deletions src/components/AppAddUrl/AppAddUrl.vue
Original file line number Diff line number Diff line change
@@ -1,34 +1,78 @@
<script lang="ts" setup>
import { ref } from 'vue'
import { computed, type PropType, ref, watch } from 'vue'
import { isValidUrl } from '@/utils/util'
import { useMutation } from '@vue/apollo-composable'
import { ADD_SAMPLE } from '@/graphql/mutations/samples'
import type { Statement } from '@/entities/Statement'
import { GET_STATEMENTS } from '@/graphql/queries/statements'
import { useValidateOgUrl } from '@/composables/useValidateOgUrl'
import AppAddUrlError from '@/components/AppAddUrl/AppAddUrlError.vue'
import AppAddUrlPreview from '@/components/AppAddUrl/AppAddUrlPreview.vue'
const showInput = ref(false)
const input = ref()
const toggleShowInput = () => {
showInput.value = !showInput.value
input.value.focus()
}
const props = defineProps({
statement: { type: Object as PropType<Statement>, required: true }
})
const inputValue = ref('')
const canCreate = computed(() => !!inputValue.value && isValidUrl(inputValue.value))
const { loading: loadingValidation, data, validate } = useValidateOgUrl()
watch(data, (n) => {
if (!n?.error && n?.data.success) {
addSample()
}
})
const { loading: loadingMutation, mutate: addSample } = useMutation(ADD_SAMPLE, () => ({
variables: {
objects: {
statement_id: props.statement?.id,
url: inputValue.value
}
},
update: (cache, { data: { insert_samples } }) => {
let data: any = cache.readQuery({ query: GET_STATEMENTS })
data = {
...data,
statements: [...data.statements, insert_samples]
}
cache.writeQuery({ query: GET_STATEMENTS, data })
inputValue.value = ''
}
}))
</script>
<template>
<div class="AppAddUrl font--fira">
<button @click="toggleShowInput">{{ showInput ? 'Cancel' : 'Add Inspiration ✨' }}</button>
<input
ref="input"
:class="[showInput ? 'visible opacity-100' : 'invisible opacity-0']"
placeholder="https://dribbble.com/shots..."
type="text"
/>
<label
class="mr-3 flex-1"
title="Add new inspiration"
aria-label="Add new inspiration"
for="add-url"
>
<input
required
name="add-url"
v-model="inputValue"
placeholder="e.g https://dribbble.com/shots..."
type="text"
/>
</label>
<button
:disabled="!canCreate || loadingValidation || loadingMutation"
@click="validate(inputValue)"
>
Add Inspiration ✨
</button>
</div>
<AppAddUrlError :msg="data?.error ? 'Provided URL is invalid ❌' : ''" />
<AppAddUrlPreview v-if="!data?.error && data?.data" :og-item="data.data" />
</template>

<style lang="scss">
.AppAddUrl {
@apply flex mb-5 text-sm items-baseline;
input {
@apply ml-3 p-3 rounded-lg border transition-all;
max-height: 43px;
}
button {
@apply p-3 bg-black text-white mt-3 rounded-lg w-44;
}
@import 'AppAddUrl';
@media (prefers-color-scheme: dark) {
@import 'AppAddUrl.dark';
}
</style>
17 changes: 17 additions & 0 deletions src/components/AppAddUrl/AppAddUrlError.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<script setup lang="ts">
defineProps({
msg: String
})
</script>

<template>
<div class="AppAddUrlError font--fira" v-if="msg">
{{ msg }}
</div>
</template>

<style lang="scss">
.AppAddUrlError {
@apply p-2 bg-red-500 text-sm rounded-sm;
}
</style>
48 changes: 48 additions & 0 deletions src/components/AppAddUrl/AppAddUrlPreview.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<script lang="ts" setup>
import type { PropType } from 'vue'
import { computed } from 'vue'
import { truncate } from '@/utils/util'
import type { OgItem } from '@/composables/useValidateOgUrl'
import MdiCheckCircleOutline from '@/components/Icons/MdiCheckCircleOutline.vue'
const ogImage = computed(() => (props.ogItem?.ogImage?.length ? props.ogItem.ogImage[0].url : ''))
const ogTitle = computed(() => props.ogItem?.ogTitle ?? '')
const ogDescription = computed(() => props.ogItem?.ogDescription ?? props.ogItem?.requestUrl)
const ogUrl = computed(() => props.ogItem?.ogUrl ?? '')
const props = defineProps({
ogItem: {
type: Object as PropType<OgItem>
}
})
</script>

<template>
<a
:href="ogUrl"
target="_blank"
:title="ogTitle"
:aria-description="ogDescription"
class="AppAddUrlPreview font--fira"
>
<MdiCheckCircleOutline class="absolute right-1 top-1 text-green-400 text-xl" />
<div
class="AppAddUrlPreview__img"
v-if="ogImage"
:style="{ backgroundImage: `url(${ogImage})` }"
/>
<div class="AppAddUrlPreview__content">
<div class="AppAddUrlPreview__content--title" v-if="ogTitle">{{ truncate(ogTitle, 30) }}</div>
<div class="AppAddUrlPreview__content--desc" v-if="ogDescription">
{{ truncate(ogDescription, 100) }}
</div>
</div>
</a>
</template>

<style lang="scss">
@import 'AppAddUrlPreview';
@media (prefers-color-scheme: dark) {
@import 'AppAddUrlPreview.dark';
}
</style>
5 changes: 5 additions & 0 deletions src/components/AppAddUrl/_AppAddUrl.dark.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.AppAddUrl {
input {
@apply bg-transparent;
}
}
10 changes: 10 additions & 0 deletions src/components/AppAddUrl/_AppAddUrl.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.AppAddUrl {
@apply flex mb-5 text-sm items-baseline;
input {
@apply p-3 rounded-lg border transition-all w-full;
max-height: 44px;
}
button {
@apply p-3 bg-black text-white mt-3 rounded-lg w-44;
}
}
9 changes: 9 additions & 0 deletions src/components/AppAddUrl/_AppAddUrlPreview.dark.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.AppAddUrlPreview {
@apply bg-transparent;
&__content {
@apply text-gray-300;
&--desc {
@apply text-gray-500;
}
}
}
16 changes: 16 additions & 0 deletions src/components/AppAddUrl/_AppAddUrlPreview.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.AppAddUrlPreview {
@apply flex h-auto w-full bg-white border rounded-lg mb-4 transition-all overflow-hidden relative;

&__img {
@apply min-w-[33%] w-1/3 rounded-l-lg bg-cover;
}
&__content {
@apply flex flex-col p-3 text-gray-800;
&--title {
@apply text-sm;
}
&--desc {
@apply text-xs text-gray-600 mt-2;
}
}
}
19 changes: 1 addition & 18 deletions src/components/AppCommunity/AppLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,5 @@ const formattedLink = computed(() => props.link.url.replace('https://', ''))
</template>

<style lang="scss">
.AppLink {
font-family: 'Fira Mono', serif;
@apply pl-3 pr-3 rounded-lg flex items-center;
background: linear-gradient(
89.84deg,
rgba(230, 36, 174, 0.15) 0.34%,
rgba(94, 58, 255, 0.15) 16.96%,
rgba(10, 136, 255, 0.15) 34.66%,
rgba(75, 191, 80, 0.15) 50.12%,
rgba(137, 206, 0, 0.15) 66.22%,
rgba(239, 183, 0, 0.15) 82%,
rgba(246, 73, 0, 0.15) 99.9%
);
border: 1px solid #d9e1ec;
&__url {
@apply text-xs truncate text-ellipsis ml-2;
}
}
@import 'AppLink';
</style>
21 changes: 21 additions & 0 deletions src/components/AppCommunity/_AppLink.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.AppLink {
font-family: 'Fira Mono', serif;
@apply pl-3 pr-3 rounded-lg flex items-center;
background: linear-gradient(
89.84deg,
rgba(230, 36, 174, 0.15) 0.34%,
rgba(94, 58, 255, 0.15) 16.96%,
rgba(10, 136, 255, 0.15) 34.66%,
rgba(75, 191, 80, 0.15) 50.12%,
rgba(137, 206, 0, 0.15) 66.22%,
rgba(239, 183, 0, 0.15) 82%,
rgba(246, 73, 0, 0.15) 99.9%
);
border: 1px solid #d9e1ec;
&__icon {
@apply w-3 min-w-[0.9rem];
}
&__url {
@apply text-xs truncate text-ellipsis ml-2;
}
}
2 changes: 1 addition & 1 deletion src/components/AppSidePanel/AppSidePanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const closePanel = () => {
<UilCommentShare class="mr-1" />
Community Inspirations
</h3>
<AppAddUrl />
<AppAddUrl v-if="statement" :statement="statement" />
<div class="AppSidePanel__links">
<AppSidePanelSamples :samples="samples" />
</div>
Expand Down
Loading

0 comments on commit eeed9ab

Please sign in to comment.