cyber-elx 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/DEV_DOC.md ADDED
@@ -0,0 +1,567 @@
1
+ # CyberOcean Custom Elx Theme
2
+
3
+ ## Steps
4
+
5
+ 1. Make a detailled plan of the website
6
+ - Layout
7
+ - List all the pages
8
+ - List all the sections
9
+ - Header & Footer
10
+ - Which available variables are going to be used
11
+ - Confirm with the user
12
+ + Give the user the plan of the pages
13
+ + Ask for images/icons if you need (The user can upload files from the admin dashboard and give you back the links)
14
+ + Ask about the language to use
15
+ + Ask about the colors to use
16
+ 2. Start by creating the layout
17
+ - Create the `layouts/theme.liquid` file
18
+ - Create the `sections/header.liquid` file
19
+ - Create the `sections/footer.liquid` file
20
+ - **Important**: If there will be modifications on the existing, then always start by creating a fresh copy from the default files, and then modify it
21
+ 3. Create the rest of the pages (With the sections IN CASE YOU USED THEM)
22
+ - Create the `templates/home_page.liquid`
23
+ - Create the `templates/course_page.liquid`
24
+ - Create the `templates/about_page.liquid`
25
+ - Create the `templates/category_page.liquid`
26
+ - Create the `templates/courses_page.liquid`
27
+ - Create the `templates/contact_page.liquid`
28
+ - Create the `templates/blogs_page.liquid`
29
+ - Create the `templates/blog_page.liquid`
30
+ - Rules:
31
+ + **Do not** use translation unless asked for it
32
+ + **Do not** try to always to copy paste the default files, use them as a reference, unless asked for it
33
+ + **Do not** try to always use all available variables, use only the variables you need, unless asked for it
34
+ + **Always** make your design mobile responsive
35
+ + **Always** keep sections, templates and layouts file names simple
36
+ > Correct: `sections/header.liquid`
37
+ > Wrong: `sections/header_custom_elx.liquid`
38
+
39
+ ## Defaults
40
+
41
+ The default files are stored in the `defaults` folder
42
+ - The files in `defaults` folder are read-only
43
+ - Their purpose is to provide a reference when creating custom files
44
+ - The files in `defaults` folder are created using an old template
45
+ - The files in `defaults` folder use css/js/media files from the server, you can use them too, if needed
46
+ - The files in `defaults` folder are going to be used by the server if you don't provide custom files, example: if you don't provide a custom `layouts/theme.liquid`, the server will use the default one from `defaults/layouts/theme.liquid`
47
+
48
+ ## Customization
49
+
50
+ - You are not forced to use all the available variables in the templates/sections/layouts, you can use only the variables you need
51
+
52
+ ### Layout
53
+
54
+ - `layouts/theme.liquid` is the main layout file of the website
55
+ - By editing it, you can modify the layout of the website
56
+ - To override the default layout's header or footer, you need to:
57
+ 1. Create a custom file in `sections` folder (example: `sections/header.liquid` or `sections/footer.liquid`)
58
+ 2. Use the `section` tag in `layouts/theme.liquid` to include the custom section, like this:
59
+ ```liquid
60
+ {% section 'header_custom_elx.liquid' %}
61
+ {{ content_for_layout }}
62
+ {% section 'footer_custom_elx.liquid' %}
63
+ ```
64
+ 3. The tag `{{ content_for_layout }}` is crucial as it represents the content of the page, the pages (templates) will not be displayed without it
65
+ 4. The custom section is MANDATORY, the admin uses it for third-party services, scripts and styles:
66
+ ```liquid
67
+ <script>
68
+ {% setting "el-x.custom_js" %}
69
+ </script>
70
+ <style>
71
+ {% setting "el-x.custom_css" %}
72
+ </style>
73
+ {% setting "el-x.custom_html" %}
74
+ ```
75
+
76
+ ### Sections
77
+
78
+ - The only allowed section names for now are:
79
+ - `header`
80
+ - `footer`
81
+ - `hero`
82
+ - `ad`
83
+ - `banner`
84
+ - `banner_1`
85
+ - `banner_2`
86
+ - `banner_3`
87
+ - `reviews`
88
+ - `menu`
89
+ - `menu_1`
90
+ - `menu_2`
91
+ - `menu_3`
92
+ - `category`
93
+ - `category_related`
94
+ - `categories`
95
+ - `category_element`
96
+ - `course`
97
+ - `course_related`
98
+ - `courses`
99
+ - `course_element`
100
+ - `testimonial`
101
+ - `about`
102
+ - `cta`
103
+ - `cta_1`
104
+ - `cta_2`
105
+ - `cta_3`
106
+ Note: The sections can be loaded using the `section` tag from any template, layout or section, using the syntax: `{% section '<SECTION_NAME>_custom_elx.liquid' %}`, example: `{% section 'header_custom_elx.liquid' %}`
107
+
108
+ ### Templates
109
+
110
+ - The templates represent the pages of the website
111
+ - The `home_page.liquid` is the home page of the website
112
+ - The `course_page.liquid` is a single course page on the website
113
+ - The `courses_page.liquid` is the page that shows all courses on the website
114
+ - The `category_page.liquid` s a single category page on the website
115
+ - The `blog_page.liquid` is a single blog page on the website
116
+ - The `blogs_page.liquid` is the main blogs page of the website
117
+ - The `contact_page.liquid` is the contact page of the website
118
+ - The `about_page.liquid` is the about page of the website
119
+
120
+ ### Available Liquid Variables
121
+
122
+ **Global Available vairables:**
123
+ Note: Available in All pages, and configurable from the website administration, recommended to use, so the user can change them from the admin, without the need to edit the code
124
+ - Path to the logo image:
125
+ + Name: `logo`
126
+ + Sample: `https://example.com/logo.png`
127
+ - Primary Color:
128
+ + Name: `primary`
129
+ + Sample: `#ff0000`
130
+ - Secondary Color:
131
+ + Name: `secondary`
132
+ + Sample: `#00ff00`
133
+ - Texts used in the footer
134
+ + Name: `footerTexts`
135
+ + Sample:
136
+ ```json
137
+ {
138
+ "descreption": "...", // Footer description (yes it's misspelled as `descreption`, it will be fixed in the future)
139
+ "newsletter": "...", // Newsletter text
140
+ "copyright": "..." // Copyright text
141
+ }
142
+ ```
143
+ - Links to be used in the footer
144
+ + Name: `footerLinks`
145
+ + Sample:
146
+ ```json
147
+ [
148
+ {
149
+ "title": "...", // Link title
150
+ "link": "..." // Link url
151
+ },
152
+ ... // The admin can add as many links as he wants
153
+ ]
154
+ ```
155
+ - Social media Urls
156
+ + Name: `footerSocial`
157
+ + Sample:
158
+ ```json
159
+ {
160
+ "twitter": "...",
161
+ "facebook": "...",
162
+ "linkedIn": "..."
163
+ }
164
+ ```
165
+ - About us texts:
166
+ + Name: `aboutUsTexts`
167
+ + Sample:
168
+ ```json
169
+ {
170
+ "title": "...",
171
+ "descreption": "..."
172
+ "picture_one": {
173
+ "path": "...", // Image path
174
+ }
175
+ "picture_two": {
176
+ "path": "...", // Image path
177
+ }
178
+ }
179
+ ```
180
+ - CTA texts:
181
+ + Name: `ctaTexts`
182
+ + Sample:
183
+ ```json
184
+ {
185
+ "title": "...",
186
+ "button": "..."
187
+ }
188
+ ```
189
+ - Apply now text:
190
+ + Name: `applyNow`
191
+ + Sample:
192
+ ```json
193
+ [
194
+ {
195
+ "title": "...",
196
+ "descreption": "..."
197
+ "picture": {
198
+ "path": "...", // Image path
199
+ }
200
+ },
201
+ ... // The admin can add as many applyNow as he wants
202
+ ]
203
+ ```
204
+ - Blog section text:
205
+ + Name: `blogText`
206
+ + Sample:
207
+ ```json
208
+ {
209
+ "title": "...",
210
+ "descreption": "...",
211
+ "number_blogs": 5 // The limit of blogs to be displayed in the blog main page (Configurable from the admin)
212
+ }
213
+ ```
214
+ - Pages top banner background:
215
+ + Name: `pagesTopBannerBackground`
216
+ + Sample:
217
+ ```json
218
+ {
219
+ "picture": {
220
+ "path": "...", // Image path
221
+ }
222
+ }
223
+ ```
224
+ - Promotion background:
225
+ + Name: `promotionBackground`
226
+ + Sample:
227
+ ```json
228
+ {
229
+ "picture": {
230
+ "path": "...", // Image path
231
+ }
232
+ }
233
+ ```
234
+ - Address:
235
+ + Name: `adresse`
236
+ + Sample: `"123 Main St, City"`
237
+ - Phone:
238
+ + Name: `phone`
239
+ + Sample: `"+1 234 567 890"`
240
+ - Email:
241
+ + Name: `email`
242
+ + Sample: `"contact@example.com"`
243
+ - Frame (embedded Maps iframe code):
244
+ + Name: `frame`
245
+ + Sample: `"<iframe>...</iframe>"`
246
+ - Icon for the browser tab:
247
+ + Name: `icon`
248
+ + Sample: `"https://example.com/icon.png"`
249
+ - All categories:
250
+ + Name: `allCategories`
251
+ + Sample:
252
+ ```json
253
+ [
254
+ { ... }, // Category object
255
+ ...
256
+ ]
257
+ ```
258
+ - Website URL (The url of the website):
259
+ + Name: `websiteUrl`
260
+ + Sample: `"https://example.com"`
261
+ - Admin URL (The url of the website App, where users and admins can login):
262
+ + Name: `adminUrl`
263
+ + Sample: `"https://admin.example.com"`
264
+ + Login url: `{{ adminUrl }}/public/el-x/login`
265
+ + Register url: `{{ adminUrl }}/public/el-x/register`
266
+ - Website name:
267
+ + Name: `websiteName`
268
+ + Sample: `"My Website"`
269
+ - Navbar categories style:
270
+ + Name: `navbarCategoriesStyle`
271
+ + Sample: `true` or `false` (If true, the categories will be displayed in the navbar as a dropdown menu, parent [with parentId == null])
272
+ - Language:
273
+ + Name: `lang`
274
+ + Sample: `"en"`, `"ar"` or `"fr"`
275
+ - Current user:
276
+ + Name: `user`
277
+ + Sample:
278
+ ```json
279
+ {
280
+ "id": 1,
281
+ "name": "John Doe",
282
+ "email": "john@example.com",
283
+ "image": {
284
+ "path": "...", // Image path
285
+ "thumbnail": "...", // Lower res, and truncated 200x200 variant of the image
286
+ }
287
+ }
288
+ ```
289
+
290
+ **Home Page Available vairables:**
291
+ - Page template key:
292
+ + Name: `template`
293
+ + Value: key that includes the string `home_page`
294
+ - All categories:
295
+ + Name: `categories`
296
+ + Sample:
297
+ ```json
298
+ [
299
+ { // Category object
300
+ ...
301
+ "courses": [ // Additional field per category
302
+ { ... }, // Course object
303
+ ...
304
+ ]
305
+ },
306
+ ...
307
+ ]
308
+ ```
309
+ - All courses:
310
+ + Name: `allCourses`
311
+ + Sample:
312
+ ```json
313
+ [
314
+ { ... }, // Course object
315
+ ...
316
+ ]
317
+ ```
318
+ - All reviews:
319
+ + Name: `allReviews`
320
+ + Sample:
321
+ ```json
322
+ [
323
+ { ... }, // Review object
324
+ ...
325
+ ]
326
+ ```
327
+ - List of all courses on promo (with `course.promo == true`):
328
+ + Name: `coursePromo`
329
+ + Sample:
330
+ ```json
331
+ [
332
+ { ... }, // Course object
333
+ ...
334
+ ]
335
+ ```
336
+
337
+ **Course Page Available vairables:**
338
+ - Page template key:
339
+ + Name: `template`
340
+ + Value: key that includes the string `course_page`
341
+ - Course object:
342
+ + Name: `course`
343
+ + Sample:
344
+ ```json
345
+ { ... } // Course object
346
+ ```
347
+ - Course Elements array:
348
+ + Name: `chapterWithElements`
349
+ + Sample:
350
+ ```json
351
+ [
352
+ { ... }, // Course Element object
353
+ ...
354
+ ]
355
+ ```
356
+ + **Important**: Never ever show the content of the course elements with `element.free == false` (The user must purchase the course to access the content), and always show the content of the course elements with `element.free == true && element.type == "video"` (The user need to watch the free video to decide if he wants to purchase the course or not)
357
+ - Course duration:
358
+ + Name: `minutes`
359
+ + Sample: `45` (number of minutes)
360
+ - Course duration in hours:
361
+ + Name: `hours`
362
+ + Sample: `2` (number of hours)
363
+ - Courses list from the same category:
364
+ + Name: `courses`
365
+ + Sample:
366
+ ```json
367
+ [
368
+ { ... }, // Course object
369
+ ...
370
+ ]
371
+ ```
372
+ - If online payment is enabled (User can pay with credit card):
373
+ + Name: `onlineMode`
374
+ + Sample: `true` or `false`
375
+ - If offline payment is enabled (User can demand the course, and admin will contact the user):
376
+ + Name: `offlineMode`
377
+ + Sample: `true` or `false`
378
+ - If the course is purchased (User has already purchased the course):
379
+ + Name: `isPurchased`
380
+ + Sample: `true` or `false`
381
+ + Course Url if purchased: `<ADMIN_URL>/p/el-x/course-player/<COURSE_ID>`
382
+
383
+ **Courses Page Available vairables:**
384
+ - Page template key:
385
+ + Name: `template`
386
+ + Value: key that includes the string `courses_page`
387
+ - Courses list (With pagination and search):
388
+ + Name: `courses`
389
+ + Sample:
390
+ ```json
391
+ [
392
+ { ... }, // Course object
393
+ ...
394
+ ]
395
+ ```
396
+ - Keyword:
397
+ + Name: `keyword`
398
+ + Sample: `...` (search keyword)
399
+ - Total items:
400
+ + Name: `totalItems`
401
+ + Sample: `100` (number of courses)
402
+ - Current page:
403
+ + Name: `currentPage`
404
+ + Sample: `100` (number of courses)
405
+ - Page size:
406
+ + Name: `pageSize`
407
+ + Sample: `10` (number of courses per page)
408
+ - Total pages:
409
+ + Name: `totalPages`
410
+ + Sample: `10` (number of pages)
411
+ - Query Parameters:
412
+ + `?keyword=...` => `keyword` variable
413
+ + `?page=...` => `currentPage` variable
414
+ + `?page_size=...` => `pageSize` variable
415
+ + `?sort_by_tag=...` => handled by the server
416
+ + `?sort_by_direction=...` => handled by the server
417
+
418
+ **Category Page Available vairables:**
419
+ - Page template key:
420
+ + Name: `template`
421
+ + Value: key that includes the string `categories_page`
422
+ - Courses list of the category:
423
+ + Name: `courses`
424
+ + Sample:
425
+ ```json
426
+ [
427
+ { ... }, // Course object
428
+ ...
429
+ ]
430
+ ```
431
+ - Category:
432
+ + Name: `category`
433
+ + Sample:
434
+ ```json
435
+ { ... }, // Category object
436
+ ```
437
+
438
+ **Blog Page Available vairables:**
439
+ - Page template key:
440
+ + Name: `template`
441
+ + Value: key that includes the string `blog_page`
442
+ - Page title:
443
+ + Name: `page_title`
444
+ + Sample: `...` (page title)
445
+ - Blog Post:
446
+ + Name: `article`
447
+ + Sample:
448
+ ```json
449
+ { ... }, // Article object
450
+ ```
451
+
452
+ **Blogs Page Available vairables:**
453
+ - Page template key:
454
+ + Name: `template`
455
+ + Value: key that includes the string `blogs_page`
456
+ - Page title:
457
+ + Name: `page_title`
458
+ + Sample: `...` (page title)
459
+ - Blog Posts:
460
+ + Name: `articles`
461
+ + Sample:
462
+ ```json
463
+ [
464
+ { ... }, // Article object
465
+ ...
466
+ ]
467
+ ```
468
+
469
+ **Contact Page Available vairables:**
470
+ - Page template key:
471
+ + Name: `template`
472
+ + Value: key that includes the string `contact_page`
473
+
474
+ **About Page Available vairables:**
475
+ - Page template key:
476
+ + Name: `template`
477
+ + Value: key that includes the string `about_page`
478
+ - All reviews:
479
+ + Name: `allReviews`
480
+ + Sample:
481
+ ```json
482
+ [
483
+ { ... }, // Review object
484
+ ...
485
+ ]
486
+ ```
487
+ - List of all courses on promo (with `course.promo == true`):
488
+ + Name: `coursePromo`
489
+ + Sample:
490
+ ```json
491
+ [
492
+ { ... }, // Course object
493
+ ...
494
+ ]
495
+ ```
496
+
497
+ **Objects Structure:**
498
+ - Course Object:
499
+ ```json
500
+ {
501
+ "id": "...",
502
+ "name": "...",
503
+ "description": "...",
504
+ "promo": true, // If true, the course is on promo
505
+ "price": "99.99", // "0" if free
506
+ "barredPrice": "99.99", // The price before the promo
507
+ "logo": {
508
+ "path": "..."
509
+ },
510
+ "elements": [ // Use {{ elements.size }} to get length in liquid
511
+ "...", // Course Element ID
512
+ ...
513
+ ]
514
+ }
515
+ ```
516
+
517
+ - Course Element Object:
518
+ ```json
519
+ {
520
+ "freePreview": false, // If true, and type is "video", the `element.content` will be available
521
+ "type": "...", // Types: quiz, youtube, video, pdf, iframe, video-iframe
522
+ "title": "...", // The title of the element
523
+ "time": {
524
+ "minutes": 3,
525
+ "seconds": 20
526
+ },
527
+ "content": { // Only available if type is "video"
528
+ "path": "..." // The path of the video
529
+ }
530
+ }
531
+
532
+ - Category Object:
533
+ ```json
534
+ {
535
+ "parentId": null, // Or the id of the parent category
536
+ "id": "...",
537
+ "logo": {
538
+ "path": "...", // Image path
539
+ "thumbnail": "...", // Lower res, and truncated 200x200 variant of the image
540
+ },
541
+ "name": "..."
542
+ }
543
+ ```
544
+
545
+ - Article Object:
546
+ ```json
547
+ {
548
+ "image": {
549
+ "path": "..." // Image path
550
+ },
551
+ "excerpt": "...",
552
+ "parsedBody": "...", // HTML content
553
+ "title": "...",
554
+ "formatted_created_at": "...", // Formatted date
555
+ "formatted_updated_at": "...", // Formatted date
556
+ }
557
+
558
+ - Review Object:
559
+ ```json
560
+ {
561
+ "userName": "...",
562
+ "reviewContent": "...",
563
+ "userImage": {
564
+ "path": "..."
565
+ }
566
+ }
567
+ ```