GC와 GraphQL을 사용하여 Strapi를 위한 식당 목록 UI 구축 방법
간단한 소개
이 글은 디자인을 감상하는 자유롭지만 설치할 필요가 없는 웹 기반 개발 환경에서 코드를 적게 쓰는 웹 개발자를 위해 쓴 것이다.
이것은 Strapi 사용GlueCodes Studio과 통합된 도구로 다른 곳에서 본 적이 없는 방식으로 일상적인 업무에 동력을 제공한다.자동화 부하에 만족하는 사람들에게는 매우 빠르고 확장 가능한 코드, 즉 서로 다른 JSX 구축 시간을 사용하고 은밀한 단방향 데이터 흐름을 둘러싸고 조직할 수 있다.분명히 너는 그것을 무료로 사용할 수 있다.더 이상 상하문 그리기가 없으니 시작합시다.
SolidJS 우리는 무엇을 짓고 있습니까?
우리는 를 머리 없는 CMS로 사용할 것이다.그것은 가상 미식 컨설턴트 사이트의 위탁 관리 시범을 곁들였고 식당 데이터를 심어 놓았다.실례를 요청할 수 있습니다 Strapi.양식을 작성하면 소량의 URL이 포함된 이메일이 전송됩니다.내 것은 이렇게 보인다.
Demo URL: https://api-hi2zm.strapidemo.com/admin
API restaurants URL: https://api-hi2zm.strapidemo.com/restaurants
GraphQL URL: https://api-hi2zm.strapidemo.com/graphql
Credentials: [email protected] / welcomeToStrapi123
Don't try to be a smartass, the URLs won't work longer that the demo duration you provided in the demo form.
Strapi를 어떻게 사용하는지 소개하지 않겠습니다. 마음에 들면 직접 탐색해 보십시오.Google 자습서에는 다음 두 개의 URL만 필요합니다.
GraphQL:
https://api-{someHash}.strapidemo.com/graphql
Image Server:
https://api-{someHash}.strapidemo.com
애플리케이션에는 다음과 같은 기능이 제공됩니다.here
부호화
우선, 당신은 로 이동해야 합니다.구글이나 Github를 통해 등록을 요구받을 것입니다.걱정하지 마라, 그것은 너의 어떤 세부 사항도 필요 없다.프로젝트 관리자가 되면 Strapi Food Advisor 템플릿을 선택합니다.항목에 저장할 디렉터리를 선택하라는 요청을 받을 것입니다.하나만 선택하면 IDE로 리디렉션됩니다.
GlueCodes Studio
당신은 다음과 같은 소개적인 안내를 받을 수 있습니다.
위에서 설명한 대로 두 개의 URL이 필요합니다.
GraphQL:
https://api-{someHash}.strapidemo.com/graphql
Image Server:
https://api-{someHash}.strapidemo.com
글로벌 변수GQL_URL
및 IMAGE_BASE_URL
에 추가하겠습니다.현재 실행 중인 프로그램을 보기 위해 '미리 보기' 를 누르면 됩니다.
응용 프로그램 데이터 흐름 설계
Strapi의 GraphQL API에서 추출한 식당 목록이 필요합니다. 데이터 흐름 관리 기능이 내장되어 있습니다.비즈니스 논리는 응용 프로그램 작업에 분포되어 있으며, 이 작업은 되돌아오거나 해석된 값을 단일 대상 저장소에 저장합니다.데이터 변경 사항이 한 방향으로 흐르고 UI는 저장된 변경 사항에 반응하며 영향을 받는 부분만 업데이트합니다.DOM 차이는 컴파일할 때 발생합니다GlueCodes Studio.
두 가지 유형의 행위가 있다.이전에 제공한 데이터를 공급자라고 하고 사용자가 촉발한 것을 명령자라고 한다.두 반환/해결 값은 각각 이름을 사용하여 단일 객체 저장소에서 액세스할 수 있습니다.UI에서 전역 변수:
actions
및 actionResults
에 액세스할 수 있습니다.변수actions
는 조작(예를 들어 반환/해석으로 얻은 데이터)을 실행할 수 있는 명령을 호출할 수 있는 대상이다.너는 SolidJS에서 더 많은 내용을 읽을 수 있다.하는 것이 말하는 것보다 쉬우니 인내심을 가지고 내 말을 들어 주세요.우리가 사용하는 API 호출은 식당과 클래스로 돌아갑니다.GraphQL 호출에 영향을 줄 커뮤니티 목록과 URL 조회 파라미터를 분석해야 합니다.UI로 데이터를 전송하기 전에 몇 가지 기본적인 데이터 변환이 필요합니다.이러한 정보를 바탕으로 다음 공급업체를 선택하기로 결정했습니다.
docs
우리는 다음과 같은 목표를 달성하기를 희망한다.
fetchRestaurantData
사용parseUrlQueryParams
의 결과.getRestaurants
와 getCategories
fetchRestaurantData를 사용한 결과.다음과 같습니다.
행동
providers/fetchRestaurantData
:export default async (actionResults) => {
const { category, district, locale } = actionResults.parseUrlQueryParams
const where = {
locale: 'en'
}
if (category !== 'all') {
where.category = category
}
if (district !== 'all') {
where.district = district
}
if (locale) {
where.locale = locale
}
const query = `
query ($limit: Int, $start: Int, $sort: String, $locale: String, $where: JSON) {
restaurants(limit: $limit, start: $start, sort: $sort, locale: $locale, where: $where) {
id
description
district
cover {
url
}
category {
name
}
name
locale
localizations {
id
locale
}
note
price
reviews {
note
content
}
}
restaurantsConnection(where: $where) {
aggregate {
count
}
}
categories {
id
name
}
}
`
const records = await (await fetch(global.GQL_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
query,
variables: {
limit: 15,
start: actionResults.parseUrlQueryParams.start || 0,
sort: 'name:ASC',
locale: 'en',
where
}
})
})).json()
return records.data
}
노트:actionResults.parseUrlQueryParams
액세스 쿼리 URL 매개 변수global.GQL_URL
액세스GQL_URL
글로벌 변수providers/getCategories
:export default (actionResults) => {
return [
{
id: 'all',
name: 'All'
},
...actionResults.fetchRestaurantData.categories
]
}
노트:actionResults.fetchRestaurantData.categories
액세스가 fetchRestaurantData
결과providers/getLanguages
:export default () => {
return [
{
id: 'en',
name: 'En'
},
{
id: 'fr',
name: 'Fr'
}
]
}
providers/getNeighborhoods
:export default () => {
return [
{ name: 'All', id: 'all' },
{ name: '1st', id: '_1st' },
{ name: '2nd', id: '_2nd' },
{ name: '3rd', id: '_3rd' },
{ name: '4th', id: '_4th' },
{ name: '5th', id: '_5th' },
{ name: '6th', id: '_6th' },
{ name: '7th', id: '_7th' },
{ name: '8th', id: '_8th' },
{ name: '9th', id: '_9th' },
{ name: '10th', id: '_10th' },
{ name: '11th', id: '_11th' },
{ name: '12th', id: '_12th' },
{ name: '13th', id: '_13th' },
{ name: '14th', id: '_14th' },
{ name: '15th', id: '_15th' },
{ name: '16th', id: '_16th' },
{ name: '17th', id: '_17th' },
{ name: '18th', id: '_18th' },
{ name: '19th', id: '_19th' },
{ name: '20th', id: '_20th' }
]
}
providers/getRestaurants
:export default (actionResults) => {
return actionResults.fetchRestaurantData.restaurants
.map((record) => ({
id: record.id,
name: record.name,
description: record.description,
category: record.category.name,
district: record.district,
thumbnail: record.cover[0].url
}))
}
노트:actionResults.fetchRestaurantData.restaurants
방문fetchRestaurantData
결과providers/parseUrlQueryParams
:export default (actionResults) => {
return imports.parseUrlQueryParams()
}
노트:imports.parseUrlQueryParams
외부 의존 함수에 접근합니다.In GlueCodes Studio you can use any UMD-bundled modules including those in UNPKG. Just click on Dependencies icon and edit the JSON file to look like:
{
"css": {
"bootstrap": "https://unpkg.com/[email protected]/dist/css/bootstrap.min.css",
"fa": "https://unpkg.com/@fortawesome/[email protected]/css/all.min.css"
},
"js": {
"modules": {
"parseUrlQueryParams": "https://ide.glue.codes/repos/df67f7a82cbdc5efffcb31c519a48bf6/basic/reusable-parseUrlQueryParams-1.0.4/index.js",
"setUrlQueryParam": "https://ide.glue.codes/repos/df67f7a82cbdc5efffcb31c519a48bf6/basic/reusable-setUrlQueryParam-1.0.4/index.js"
},
"imports": {
"parseUrlQueryParams": {
"source": "parseUrlQueryParams",
"importedName": "default"
},
"setUrlQueryParam": {
"source": "setUrlQueryParam",
"importedName": "default"
}
}
}
}
commands/changeCategory
:export default (categoryId) => {
imports.setUrlQueryParam({ name: 'category', value: categoryId })
}
노트:imports.setUrlQueryParam
외부 의존 함수 접근 commands/changeLanguage
:export default (languageId) => {
imports.setUrlQueryParam({ name: 'locale', value: languageId })
}
commands/changeNeighborhood
:export default (neighborhoodId) => {
imports.setUrlQueryParam({ name: 'district', value: neighborhoodId })
}
구조
에서는 각 페이지가 논리적 UI 섹션으로 나누어져 있어 UI를 모듈식으로 유지할 수 있습니다.단일 슬롯에는 해당 역할 도메인 CSS가 있습니다. 즉, 지정된 슬롯에만 영향을 주는 클래스 설정 스타일이 있고 다른 슬롯에서 해당 이름을 복사할 수 있습니다.내보낸 코드에서 슬롯은 전용 파일로 추출되어 유지보수하기 쉽습니다.
HTML을 동적으로 하려면 현대 웹 프레임워크에서처럼 속성 명령을 사용할 수 있습니다.대부분의 명령을 입력하면 필요한 명령을 자동으로 만들고 프로그램을 제공하거나 작은 위젯을 설치하는 알림을 받을 수 있습니다.어휘표는 매우 간단합니다.attribute
[gc-as]
는 우리에게 그것이 무엇인지 알려주고 기타[gc-*]
속성은 매개 변수입니다.주의: 모든 명칭 속성에 대해camelcase를 사용하십시오. 예를 들어 사용할 슬롯[gc-name="myAwesomeSlot"]
을 사용하십시오.다음은 간략한 색인 페이지 HTML입니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta gc-as="navName" gc-name="Home">
<title>FoodAdvisor</title>
<body>
<div gc-as="layout">
<div class="container-fluid">
<div gc-as="slot" gc-name="header"></div>
<div class="d-flex">
<div gc-as="slot" gc-name="filters"></div>
<div gc-as="slot" gc-name="content">
<div class="contentWrapper">
<h1 class="heading">Best restaurants in Paris</h1>
<div class="grid">
<div gc-as="listItemPresenter" gc-provider="getRestaurants" class="card">
<img-x class="card-img-top thumbnail" alt="Card image cap">
<script>
props.src = `${global.IMAGE_BASE_URL}${getRestaurantsItem.thumbnail}`
</script>
</img-x>
<div class="card-body">
<h4 gc-as="listFieldPresenter" gc-provider="getRestaurants" gc-field="name" class="name">restaurant name</h4>
<h5 gc-as="listFieldPresenter" gc-provider="getRestaurants" gc-field="category" class="category">restaurant category</h5>
<p gc-as="listFieldPresenter" gc-provider="getRestaurants" gc-field="description" class="card-text">restuarant description</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div gc-as="slot" gc-name="footer"></div>
</div>
</div>
</body>
</html>
노트:<div gc-as="layout">
는 응용 프로그램 패키지입니다.<div gc-as="slot" gc-name="content">
는 논리 사용자 인터페이스로 역할 영역 CSS가 있고 전용 파일로 추출됩니다.이것은 유일한 (페이지 내) camelcase gc 이름을 필요로 합니다.슬롯의 모든 물건은 저장, 명령, 기타 유용한 변수에 접근할 수 있다.당신은 더 많은 것을 알 수 있습니다GlueCodes Studio.<div gc-as="slot" gc-name="filters"></div>
는 재사용 가능한 슬롯입니다.슬롯과 비슷하지만 여러 페이지에서 사용할 수 있습니다.재사용 가능한 플러그는 일부 플러그로 이해할 수 있다.전용 HTML 편집기에서 재사용 가능한 슬롯을 편집하고 empty slot 명령을 사용하여 페이지에 삽입합니다.<div gc-as="listItemPresenter" gc-provider="getRestaurants" class="card">
프로그램이 되돌아오는 그룹에서 이div를 반복합니다.getRestaurants
프로그램에서 순환할 때 항목의 속성<h4 gc-as="listFieldPresenter" gc-provider="getRestaurants" gc-field="name" class="name">restaurant name</h4>
을 표시합니다.<img-x class="card-img-top thumbnail" alt="Card image cap">
<script>
props.src = `${global.IMAGE_BASE_URL}${getRestaurantsItem.thumbnail}`
</script>
</img-x>
정적 HTML은 내장된 방식으로 반응하지 않습니다.따라서 herelike:name
라고 명명되고 삽입식getRestaurants
이 포함된 확장 라벨이라는 개념이 있다.코드는 샌드박스입니다. 다른 명령 (예를 들어 슬롯이나 목록 항목 표시기) 에서 사용할 수 있는 변수에 접근할 수 있습니다.스크립트는 tagName + '-x'
변수에 분배하여 확장 표시된 도구/속성을 변경할 수 있습니다.Note that when an extended tag is placed inside a list item presenter you get access to a variable called like:
providerName + Item
, in our casegetRestaurantsItem
which is an item while looping overgetRestaurants
provider. You could also accessgetRestaurantsIndex
for a numeric index in the array.
기타 템플릿:
<script>
:<div class="wrapper">
<h2 class="heading">Categories</h2>
<ul class="filterSet">
<li gc-as="listItemPresenter" gc-provider="getCategories" class="filterItem">
<label>
<input-x type="radio">
<script>
props.name = 'category'
props.value = getCategoriesItem.id
props.checked = getCategoriesItem.id === (actionResults.parseUrlQueryParams.category || 'all')
props.onChange = (e) => {
actions.changeCategory(e.target.value)
actions.reload()
}
</script>
</input-x>
<span gc-as="listFieldPresenter" gc-provider="getCategories" gc-field="name" class="label">category name</span>
</label>
</li>
</ul>
<h2 class="heading">Neighborhood</h2>
<ul class="filterSet">
<li gc-as="listItemPresenter" gc-provider="getNeighborhoods" class="filterItem">
<label>
<input-x type="radio">
<script>
props.name = 'neighborhood'
props.value = getNeighborhoodsItem.id
props.checked = getNeighborhoodsItem.id === (actionResults.parseUrlQueryParams.district || 'all')
props.onChange = (e) => {
actions.changeNeighborhood(e.target.value)
actions.reload()
}
</script>
</input-x>
<span gc-as="listFieldPresenter" gc-provider="getNeighborhoods" gc-field="name" class="label">neighborhood name</span>
</label>
</li>
</ul>
<h2 class="heading">Language</h2>
<ul class="filterSet">
<li gc-as="listItemPresenter" gc-provider="getLanguages" class="filterItem">
<label>
<input-x type="radio">
<script>
props.name = 'languages'
props.value = getLanguagesItem.id
props.checked = getLanguagesItem.id === (actionResults.parseUrlQueryParams.locale || 'en')
props.onChange = (e) => {
actions.changeLanguage(e.target.value)
actions.reload()
}
</script>
</input-x>
<span gc-as="listFieldPresenter" gc-provider="getLanguages" gc-field="name" class="label">language name</span>
</label>
</li>
</ul>
</div>
props
:<footer class="wrapper">
<p>Try <a href="https://www.glue.codes" class="link">GlueCodes Studio</a> now!</p>
<ul class="nav">
<li class="navItem">
<a href="https://www.facebook.com/groups/gluecodesstudio" class="navLink"><i class="fab fa-facebook"></i></a>
</li>
<li class="navItem">
<a href="https://www.youtube.com/channel/UCDtO8rCRAYyzM6pRXy39__A/featured?view_as=subscriber" class="navLink"><i class="fab fa-youtube"></i></a>
</li>
<li class="navItem">
<a href="https://www.linkedin.com/company/gluecodes" class="navLink"><i class="fab fa-linkedin-in"></i></a>
</li>
</ul>
</footer>
reusableSlots/filters
:<nav class="navbar navbar-light bg-light wrapper">
<a class="navbar-brand link" href="/">
<img-x width="30" height="30" alt="FoodAdvisor" class="logo">
<script>
props.src = mediaFiles['logo.png'].src
</script>
</img-x> FoodAdvisor
</a>
</nav>
You can access any images or videos you drop in the studio via
mediaFiles
variable which is an object where file names are the keys. Implicitly there is a Webpack Responsive Loader involved which gives yousrc
andplaceholder
.
GlueCodes Room 콘셉트
스타일에 대해서는 구식 HTML과 CSS를 작성하는 것 같지만, 은식으로 사용합니다. CSS Modules 범위와 글로벌 스타일 사이의 완벽한 균형을 제공합니다.따라서 당신은 당신의 응용에 대해 전역적인 주제화를 할 수 있고 사용자 인터페이스에서 선택한 부분에 대해 단독으로 스타일 디자인을 할 수 있다.CSS 클래스만 사용하면 스텔스 필드로 인해 서로 다른 슬롯 사이에서 클래스 이름을 안전하게 복사할 수 있습니다.
GlueCodes Studio
Notice a rather unusual
@import
statements. It's a way of importing third-party CSS from dependencies or global styles. The names must match the ones in Dependencies JSON or name of a global stylesheet.
reusableSlots/footer
@import 'bootstrap';
reusableSlots/header
@import 'bootstrap';
@import 'fa';
@import 'theme';
.contentWrapper {
padding: 0 20px;
}
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-gap: 30px;
margin-top: 40px;
}
.heading {
margin-bottom: 0;
font-size: 32px;
}
.thumbnail {
transition: transform 0.3s;
}
.thumbnail:hover {
transform: translateY(-4px);
}
.name {
font-weight: 700;
font-size: 16px;
color: rgb(25, 25, 25);
}
.category {
font-size: 13px;
color: #666;
}
pages/index/This Page CSS
:.wrapper {
padding: 0 20px;
padding-top: 75px;
min-width: 250px;
}
.filterSet, .filterItem {
margin: 0;
padding: 0;
}
.filterSet {
margin-bottom: 30px;
}
.filterItem {
list-style: none;
}
.filterItem label {
cursor: pointer;
}
.label {
padding-left: 4px;
}
.heading {
padding-bottom: 15px;
font-weight: 700;
font-size: 16px;
color: rgb(25, 25, 25);
}
pages/index/Content Slot CSS
:@import 'fa';
.wrapper {
margin-top: 70px;
padding: 20px;
background-color: #1C2023;
color: white;
}
.link {
color: white;
}
.link:hover {
color: #219F4D;
text-decoration: none;
}
.nav {
display: flex;
margin: 0;
padding: 0;
}
.navItem {
list-style: none;
}
.navLink {
display: inline-block;
margin-right: 2px;
width: 40px;
height: 40px;
line-height: 40px;
text-align: center;
font-size: 18px;
border-radius: 50%;
background-color: #272a2e;
}
.navLink,
.navLink:hover,
.navLink:active,
.navLink.visited {
text-decoration: none;
color: white;
}
.navLink:hover {
background-color: #219F4D;
}
reusableSlots/filters
:.wrapper {
padding: 20px;
background: #1C2023;
margin-bottom: 30px;
}
.link {
color: white;
font-size: 18px;
font-weight: 700;
}
.link,
.link:hover,
.link:active,
.link:visited {
color: white;
text-decoration: none;
}
.logo {
margin-right: 3px;
}
다음은요?
네가 이미 알아차렸듯이, 여기에는 세부적인 기조가 있는데, 그것이 합리적으로 흡수되기를 바란다.본문을 발표한 지 얼마 되지 않아 저는 여러분과 이 프로젝트의 직접 링크를 공유할 것입니다. 및 Strapi를 사용하여 맞춤형 CMS를 구축할 수 있습니다.
내가 두 번째 부분을 써야 하는지, 아니면 네가 보고 싶은 통합이 있는지 알게 해 줘.
또한 DellGlueCodes Studio에 가입해 주십시오.
Reference
이 문제에 관하여(GC와 GraphQL을 사용하여 Strapi를 위한 식당 목록 UI 구축 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/chrisczopp/how-to-build-a-food-advisor-ui-for-strapi-using-gc-graphql-1o31텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)