اذهب إلى المحتوى

البحث في الموقع

المحتوى عن 'page'.

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المحتوى


التصنيفات

  • الإدارة والقيادة
  • التخطيط وسير العمل
  • التمويل
  • فريق العمل
  • دراسة حالات
  • التعامل مع العملاء
  • التعهيد الخارجي
  • السلوك التنظيمي في المؤسسات
  • عالم الأعمال
  • التجارة والتجارة الإلكترونية
  • نصائح وإرشادات
  • مقالات ريادة أعمال عامة

التصنيفات

  • مقالات برمجة عامة
  • مقالات برمجة متقدمة
  • PHP
    • Laravel
    • ووردبريس
  • جافاسكربت
    • لغة TypeScript
    • Node.js
    • React
    • Vue.js
    • Angular
    • jQuery
    • Cordova
  • HTML
  • CSS
    • Sass
    • إطار عمل Bootstrap
  • SQL
  • لغة C#‎
    • ‎.NET
    • منصة Xamarin
  • لغة C++‎
  • لغة C
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • لغة Rust
  • برمجة أندرويد
  • لغة R
  • الذكاء الاصطناعي
  • صناعة الألعاب
  • سير العمل
    • Git
  • الأنظمة والأنظمة المدمجة

التصنيفات

  • تصميم تجربة المستخدم UX
  • تصميم واجهة المستخدم UI
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب GIMP
    • كريتا Krita
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • نصائح وإرشادات
  • مقالات تصميم عامة

التصنيفات

  • مقالات DevOps عامة
  • خوادم
    • الويب HTTP
    • البريد الإلكتروني
    • قواعد البيانات
    • DNS
    • Samba
  • الحوسبة السحابية
    • Docker
  • إدارة الإعدادات والنشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
    • ريدهات (Red Hat)
  • خواديم ويندوز
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • شبكات
    • سيسكو (Cisco)

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح
  • مبادئ علم التسويق

التصنيفات

  • مقالات عمل حر عامة
  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • العمل الحر المهني
    • العمل بالترجمة
    • العمل كمساعد افتراضي
    • العمل بكتابة المحتوى

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
    • بريستاشوب
    • أوبن كارت
    • دروبال
  • الترجمة بمساعدة الحاسوب
    • omegaT
    • memoQ
    • Trados
    • Memsource
  • برامج تخطيط موارد المؤسسات ERP
    • تطبيقات أودو odoo
  • أنظمة تشغيل الحواسيب والهواتف
    • ويندوز
    • لينكس
  • مقالات عامة

التصنيفات

  • آخر التحديثات

أسئلة وأجوبة

  • الأقسام
    • أسئلة البرمجة
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات

التصنيفات

  • كتب ريادة الأعمال
  • كتب العمل الحر
  • كتب تسويق ومبيعات
  • كتب برمجة
  • كتب تصميم
  • كتب DevOps

ابحث في

ابحث عن


تاريخ الإنشاء

  • بداية

    نهاية


آخر تحديث

  • بداية

    نهاية


رشح النتائج حسب

تاريخ الانضمام

  • بداية

    نهاية


المجموعة


النبذة الشخصية

تم العثور على 4 نتائج

  1. بدأنا في الدرس السابق بتخصيص الموقع عبر تعريف الثوابت وإنشاء ملفات header.php و footer.php والعمل على ملفات searchform.php و sidebar.php. الخطوة 2.6- كتابة ملفِّ index بعد إضافة كلِّ تلك الملفّات للقالب، حان الوقت للعمل على الصفحة الرئيسية للموقع، طبعا نحن نتحدّث عن ملفّ index.php. قم بإنشائه داخل مجلّد قالبنا ثم أضف إليه الكود التّالي: <?php get_header(); ?> <?php get_sidebar(); ?> <?php get_footer(); ?> دعنا الآن نلقي نظرةً على رئيسيّة الموقِع لنرى التغييرات التي طرأت عليها. لاحظ أنّه ما عدا القائمة الجانبيّة، فإنّ كلًّا من رأس وتذييل القالب في مكانها المحدّد. لإضافة بعض المحتوى إلى رئيسيّة الموقع افتح ملفّ index.html وقم بنسخ المنطقة المحدّدة بين “blog area section” إلى غاية وسم غلق div ذو الكلاس box-layer align-center page-nav ثمّ ألصِق كلّ ذلك في ملفِّ index.php مباشرةً تحت دالّة get_header ستحصل على شيء مشابه لهذا: <!-- BLOG AREA --> <section> <hr class=&"no-margin&" /> <div class=&"blog-container section-content&"> <div class=&"container&"> <div class=&"row&"> <div class=&"col-md-8&"> <ul class=&"negative-margin&"> <li> <h1><a href=&"single-blog.html&" class=&"gray&">Should I use a Pencil or a Ballpen?</a></h1> By <a href=&"#&">Sam Norton</a> / On July 20, 2014 / <a href=&"#&">Life Hacks</a> <figure> <img class=&"opacity-hover box-layer img-responsive&" src=&"images/thumb1.jpg&" alt=&"Pencil or Ballpen&" /> </figure> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.. <div class=&"btn-margin&"> <a href=&"single-blog.html&" class=&"btn btn-primary&">CONTINUE READING >>> </a> </div> </li> <li> <h1><a href=&"single-blog.html&" class=&"gray&">How to test your patience!</a></h1> By <a href=&"#&">Sam Norton</a> / On July 20, 2014 / <a href=&"#&">Life Tips</a> <figure> <img class=&"box-layer img-responsive&" src=&"images/thumb2.jpg&" alt=&"Pencil or Ballpen&" /> </figure> Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.. <div class=&"btn-margin&"> <a href=&"single-blog.html&" class=&"btn btn-primary&">CONTINUE READING >>> </a> </div> </li> </ul> <div class=&"box-layer align-center page-nav&"> <ul class=&"btn&"> <li><a href=&"#&">Next Page >>> </a></li> </ul> </div> </div> الكود أعلاه سيقوم بعرض محتوًى ساكنٍ. لجعله ديناميكيٍّ سنستخدم حلقة تِكرارِ ووردبريس داخل منطقة التدوينات لعرضها بشكل متكرّرٍ مع محتوًى مختلفٍ. قم بتعويض الكود الذي نسخته سابقا بهذا الكود: <?php get_header(); ?> <!-- BLOG AREA --> <section> <hr class=&"no-margin&" /> <div class=&"blog-container section-content&"> <div class=&"container&"> <?php if (have_posts()) : ?> <div class=&"row&"> <div class=&"col-md-8&"> <ul class=&"negative-margin&"> <li> <?php while(have_posts()) : the_post(); ?> <h1><a href=&"<?php the_permalink(); ?>&" class=&"gray&"><?php the_title(); ?></a></h1> By <a href=&"<?php the_author_posts() ?>&"><?php the_author(); ?> </a> / On <?php echo get_the_date('F j, Y'); ?> / In <?php the_category(', '); ?> <?php if (has_post_thumbnail()) : ?> <figure> <a href=&"<?php the_permalink(); ?>&"><?php the_post_thumbnail('', array('class' => 'opacity-hover box-layer img-responsive')); ?></a> </figure> <?php the_excerpt(); ?> <div class=&"btn-margin&"> <a href=&"<?php the_permalink(); ?>&" class=&"btn btn-primary&">CONTINUE READING >>> </a> </div> </li> <?php endif; ?> <?php endwhile; ?> </ul> <?php global $wp_query; if ($wp_query->max_num_pages > 1) : ?> <div class=&"box-layer align-center page-nav&"> <ul class=&"btn&"> <li><?php previous_posts_link('<<< Previous Page', $wp_query->max_num_pages); ?></li> <li><?php next_posts_link('Next Page >>>', $wp_query->max_num_pages); ?></li> </ul> </div> <!-- end box --> <?php endif; ?> <?php endif; ?> </div> <aside> <div class=&"col-md-3 col-md-offset-1 margin-sidebar&"> <?php get_sidebar(); ?> </div> </aside> </div> </div> </div> </section> <?php get_footer(); ?> حلقة تِكرار ووردبريس عبارة عن أقسامِ أكواد تُستخدم من طرف ووردبريس لعرض المقالات. باستخدام حلقة التِّكرار هذه ووردبريس سيقوم بتناول كلِّ مقالٍ على حِدى ليتمّ عرضه في الصّفحة الحاليّة، بحيث يتم العرض وفق المعايير المحدّدة داخل وسوم حلقة التِّكرار. في العادة هذه الحلقة تأتي بهذه الأقسام من الأكواد: <?php if ( have_posts() ) { while ( have_posts() ) { the_post(); // // Post Content here // } // end while } // end if ?> الكود أعلاه يمثّل الشّكل القياسيِّ لحلقة تكرار ووردبريس لِعرض المقالات ومع ذلك مازال علينا استخدام الدوالّ التالية ضمن الحلقة: the_permalink : تقوم بعرضِ الرّابط الدائم للمقالِ الحاليِّ. the_title : تقوم باسترجاع عنوان المقالِ الحاليِّ. the_author_posts : تقوم بعرض عدد المقالات التّي قام الكاتب الحاليُّ بنشرها. the_author : تقوم بعرض اسم كاتبِ المقالِ الحاليِّ. get_the_date : تسترجع التوقيت الذي كُتب به المقالُ الحاليِّ. the_category : تعرض التصنيف أو التصنيفات التي ينتمي إليها المقال الحاليّ. the_post_thumbnail : تعرض الصّورة البارزة للمقالِ الحاليِّ كما تمّ تحديده في شاشة تعديل المقال (سنرى هذا بشكل مفصّلٍ بعد قليل). the_excerpt : تعرض المقتطف للمقالِ الحاليِّ. بعد تطبيقِ بعض الفلاتر عليها وتضمين auto-p عليها سنقوم بتحويل line-breaks إلى فقرة HTML فيما يتعلّق بالصّورة البارزة فسنستخدم الكود التّالي: <?php if (has_post_thumbnail()) : ?> <figure> <a href=&"<?php the_permalink(); ?>&"><?php the_post_thumbnail('', array('class' => 'opacity-hover box-layer img-responsive')); ?></a> </figure> <?php endif; ?> أوّلًا يتّم التأكّد من أنّ المقال يحتوي على صورةٍ بارزة، بعد ذلك إذا كان يحتوي على واحدةٍ، سنقوم بعرض رابط الموضوع إضافة إلى الصورة نفسها. لاحظ أنّنا أضفنا مصفوفة تحتوي على كلاس opacity-hover box-layer img-responsive. هذه طريقة لإضافة كلاس للصورة البارزة وجعلها تبدو بشكلٍ أجمل عن طريق إضافة: تأثيرٍ عند تمرير الفأرة فوقها، حدودٍ وظِلّ صندوق. لكنّ القيّام بكلّ هذا لن يقوم بعرض الصورة البارزة، يجب عليك أوّلًا تسجيل الصّورة البارزة. قم بنسخ الكود التّالي وأضِفه في ملفِّ functions.php. <?php /***********************************************************************************************/ /* Add Theme Support for Post Thumbnails */ /***********************************************************************************************/ if (function_exists('add_theme_support')) { add_theme_support('post-thumbnails'); set_post_thumbnail_size(742, 428); } ?> جيّد! الصورة البارزة ستظهر الآن. التّالي سيكون إضافة دالّةٍ تقوم بنزع العارِضات والنِّقاط بينهما من نهاية المقتطف التي تعرض فيه بطريقة افتراضية. دائما في ملفِّ functions.php أضف الكود التالي: <?php /***********************************************************************************************/ /* Remove the brackets, ellipsis and hellip on excerpt */ /***********************************************************************************************/ function trim_excerpt($text) { $text = str_replace('[hellip;]', '...', $text); return $text; } add_filter('get_the_excerpt', 'trim_excerpt'); ?> تاليًّا، سنقوم بتشغيل ترقيم الصّفحات التيّ قمنا بإضافتها سابقًا في ملفِّ index.php. الكود التّالي سيقوم باستدعاء wp_query، هناك كلاس محدّدة في نواةِ ووردبريس تتعامل مع تعقيدات استعلامات المقالات (أو الصفحات) لمدوّنة ووردبريس. هذه الكلاس بإضافة روابط لـ previous_post_link و next_posts_link function للتنقّل بين صفحاتِ مدوّنتك. ألقِ نظرةً على الكود التّالي: <?php global $wp_query; if ($wp_query->max_num_pages > 1) : ?> <div class=&"box-layer align-center page-nav&"> <ul class=&"btn&"> <li><?php previous_posts_link('<<< Previous Page', $wp_query->max_num_pages); ?></li> <li><?php next_posts_link('Next Page >>>', $wp_query->max_num_pages); ?></li> </ul> </div> <!-- end box --> <?php endif; ?> <?php endif; ?> كلمسةٍ ختاميِّة، قم بتضمين دالّة get_sidebar داخل وسم div ذو كلاس col-md-3 col-md-offset-1 margin-sidebar الكلُّ داخل وسمِ HTML5 aside، ستحصل كود مشابه للتّالي: <aside> <div class=&"col-md-3 col-md-offset-1 margin-sidebar&"> <?php get_sidebar(); ?> </div> </aside> كمراجعة نهائيّة ملفّ index.php يجب أن يحتوي على الكود أدناه، راجعه لتفادي أيّة أخطاء محتملة. <?php get_header(); ?> <!-- BLOG AREA --> <section> <hr class=&"no-margin&" /> <div class=&"blog-container section-content&"> <div class=&"container&"> <?php if (have_posts()) : ?> <div class=&"row&"> <div class=&"col-md-8&"> <ul class=&"negative-margin&"> <li> <?php while(have_posts()) : the_post(); ?> <h1><a href=&"<?php the_permalink(); ?>&" class=&"gray&"> <?php the_title(); ?> </a></h1> By <a href=&"<?php the_author_posts() ?>&"><?php the_author(); ?> </a> / On <?php echo get_the_date('F j, Y'); ?> / In <?php the_category(', '); ?> <?php if (has_post_thumbnail()) : ?> <figure> <a href=&"<?php the_permalink(); ?>&"><?php the_post_thumbnail('', array('class' => 'opacity-hover box-layer img-responsive')); ?></a> </figure> <?php the_excerpt(); ?> <div class=&"btn-margin&"> <a href=&"<?php the_permalink(); ?>&" class=&"btn btn-primary&">CONTINUE READING >>> </a> </div> </li> <?php endif; ?> <?php endwhile; ?> </ul> <?php global $wp_query; if ($wp_query->max_num_pages > 1) : ?> <div class=&"box-layer align-center page-nav&"> <ul class=&"btn&"> <li><?php previous_posts_link('<<< Previous Page', $wp_query->max_num_pages); ?></li> <li><?php next_posts_link('Next Page >>>', $wp_query->max_num_pages); ?></li> </ul> </div> <!-- end box --> <?php endif; ?> <?php endif; ?> </div> <aside> <div class=&"col-md-3 col-md-offset-1 margin-sidebar&"> <?php get_sidebar(); ?> </div> </aside> </div> </div> </div> </section> <?php get_footer(); ?> الخطوة 2.7- العملُ مع ملفِّ single.php الآن سنقوم بعرض كلِّ مقالةٍ بشكل منفصل، أنشئ ملفّ single.php ثمّ أضف له الكود التّالي: <?php get_header(); ?> <!-- BLOG AREA --> <section> <hr class=&"no-margin&" /> <?php if (have_posts()) : while(have_posts()) : the_post(); ?> <div class=&"blog-container section-content&"> <div class=&"container&"> <div class=&"row&"> <div class=&"col-md-8&"> <div class=&"box-layer custom-padding&"> <section> <h1><a href=&"<?php the_permalink(); ?>&" class=&"gray&"><?php the_title(); ?></a></h1> By <a href=&"<?php the_author_posts() ?>&"><?php the_author(); ?> </a> / On <?php echo get_the_date('F j, Y'); ?> / In <?php the_category(', '); ?> <?php if (has_post_thumbnail()) : ?> <figure> <a href=&"<?php the_permalink(); ?>&"><?php the_post_thumbnail('', array('class' => 'opacity-hover box-layer img-responsive')); ?></a> </figure> <?php the_content(); ?> <?php endif; ?> </section> <?php endwhile; ?> <?php endif; ?> <section> <div class=&"comment-section&"> <?php // If comments are open or we have at least one comment, load up the comment template if ( comments_open() || '0' != get_comments_number() ) : comments_template(); endif; ?> </div> </section> </div> <!-- RELATED ARTICLE AREA --> <section> <div class=&"box-layer related-articles custom-padding&"> <h3 class=&"align-center&">Related Articles</h3> <?php $current_categories = get_the_category(); $first_category = $current_categories[0]->term_id; $args = array( 'post_per_page' => 3, 'category__in' => array($first_category), 'post__not_in' => array($post->ID) ); $related_articles = new WP_Query($args); if ($related_articles->have_posts()) : ?> <ul> <?php while ($related_articles->have_posts()) : $related_articles->the_post(); ?> <li class=&"col-md-4&"> <?php if (has_post_thumbnail()) : ?> <figure> <a href=&"<?php the_permalink(); ?>&"><?php the_post_thumbnail('', array('class' => 'opacity-hover box-layer img-responsive')); ?></a> </figure> </figure> <a href=&"<?php the_permalink(); ?>&"><?php the_title(); ?></a> <?php endif; ?> </li> <?php endwhile; ?> <div class=&"clear&"></div> </ul> <?php endif; ?> <?php // Restore original Post Data wp_reset_postdata(); ?> </div> </section> </div> <!-- SIDEBAR AREA --> <aside> <div class=&"col-md-3 col-md-offset-1 margin-sidebar&"> <?php get_sidebar(); ?> </div> </aside> </section> <?php get_footer(); ?> ولإظهار التعليقات، قم بإضافة الكود التّالي: <section> <div class=&"comment-section&"> <?php if ( comments_open() || '0' != get_comments_number() ) : comments_template(); endif; ?> </div> </section> هذا الكود سيتحقّق إن كانت التعليقات مُتاحةً أو إن كانت هناك تعليقات ليقوم باستدعاء نموذج التعليقات (سنتناول ذلك لاحقا). الخطوة 2.8- العملُ مع ملفِّ page.php بعد أن أنهينا العمل على صفحة التّدوينة، سنتوجّه للعملِ على الصّفحات العادية. أنشئ ملفّ page.php ثم ألصق به الكود التّالي: <?php get_header(); ?> <!-- BLOG AREA --> <section> <hr class=&"no-margin&" /> <div class=&"blog-container section-content&"> <div class=&"container&"> <div class=&"row&"> <div class=&"col-md-8&"> <div class=&"box-layer custom-padding&"> <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?> <h3> <?php the_title(); ?> </h3> <?php if (has_post_thumbnail()) : ?> <figure> <a href=&"<?php the_permalink(); ?>&"><?php the_post_thumbnail('', array('class' => 'opacity-hover box-layer img-responsive')); ?></a> </figure> <?php endif; ?> <?php the_content(); ?> <?php endwhile; endif; //ends the loop ?> </div> </div> <!-- SIDEBAR AREA --> <aside> <div class=&"col-md-3 col-md-offset-1 margin-sidebar&"> <?php get_sidebar(); ?> </div> </aside> </section> <?php get_footer(); ?> مجدّدًا لا جديد في هذا الملفِّ عدا أنّه لا يحتوي على قسمٍ للتعليقات كونه سيعرضُ صفحةً عاديّة. في الملفّين المقبلين سنقوم باستخدام نموذجين مُدمجين في ووردبريس لعرض الصّفحات بِنسقٍ مختلفٍ. ترجمة -وبتصرّف- للمقال How to Convert a Static HTML Template into a Responsive WordPress Theme
  2. هذا هو الدّرس الأخير في سلسلة تعلّم CSS، ولقد كان اهتمامنا في الدّروس السابقة مُنصبًّا على خصائص CSS وقيمها التي يمكن استخدامها للتأثير في عرض المستند؛ وفي هذا الدّرس سنُعيد النّظر في غايات استخدام CSS وبنية ورقة الأنماط. للتذكير، هذا هو فهرس السلسلة: مدخل إلى أوراق الأنماط المتتالية (CSS). آلية عمل تعليمات CSS داخل المتصفحات. المحددات (Selectors) في CSS. رصف العناصر (Layout) في CSS. كيفية كتابة تعليمات CSS يسهل قراءتها. تنسيق نصوص صفحات الويب باستخدام CSS. التعامل مع الألوان في CSS. إضافة محتوى إلى صفحة ويب باستخدام CSS. الجداول (Tables) في CSS. تعرف على الصناديق (Boxes) في CSS. تنسيق القوائم (Lists) في CSS. التعامل مع أجهزة العرض المختلفة والمطبوعات في CSS (هذا الدرس). أجهزة العرض والمطبوعات تهدف CSS إلى تحديد أسلوب عرض المستندات للمستخدم، ويمكن لعرض المستند أن يكون على عدّة أشكال. مثلاً: أنت تقرأ هذا المستند على جهاز ذي شاشة عرض (في الغالب)، ولكن يمكن أيضًا إسقاطها على شاشة تستهدف جمهورًا كبيرًا، أو يمكن طباعتها؛ ولهذه الوسائط خصائص مختلفة يمكن لـCSS استغلالها للحصول على طريقة عرض للمحتوى تلائم هذا الوسط. مثال يكون للمستند على موقع ويب مجموعة من الروابط الّتي تسمح للانتقال بين صفحات الوقع. يُستخدم المُعرَّف nav-area على العنصر الأب لمساحة التّنقّل في لغة الرّماز (أو يمكن استخدام الوسم <nav> بدل ذلك في الإصدار الخامس من HTML). عندما يُطبع المستند، فإنّ مساحة التّنقل تصبح غير ذات فائدة، ولذا يمكن إزالتها بالقاعدة التّالية: @media print { #nav-area { display: none; } } فيما يلي بعض أنواع الوسائط الشّائعة: الخاصّية تُشير إلى screen شاشة عرض ملوّنة print صفحة مطبوعة projection جهاز إسقاط all كل الوسائط (الخيار المبدئيّ) تفاصيل أكثر هناك طرق أخرى لتحديد نوع الوسط لمجموعة من القواعد. قد تسمح لغة الرماز المُستخدمة في المستند بتعيين نوع الوسط عند ربط ورقة الأنماط بالمستند، فمثلًا في HTML يمكن تحديد الخاصّية media على الوسم link لتحقيق ذلك. ويمكن أيضًا استخدام الأمر ‎@import‎ في CSS الّذي يسمح باستيراد ورقة أنماط من رابطٍ مُعيّن ويسمح أيضًا باشتراط نوع الوسط عند استيراده؛ وهذا يعني أنّه يمكن استخدام ملفات مختلفة لأنواع الوسائط المُختلفة، وهذا مفيد في التنظيم. الطباعة توفّر CSS دعمًا لتنسيق الصّفحات المطبوعة. يمكن استخدام قاعدة تبدأ بـ‎@page ‎ لتعيين مقدار هوامش الصّفحة المطبوعة، كما يمكن تعيين هوامش الجانب الأيمن بصورة مختلفة عن مقابلها الأيسر باستخدام ‎@page:left‎ و‎@page:right ‎. تُستخدم عادة واحدات مناسبة للطّباعة مثل البوصة (in) والنُقطة (pt والّتي تساوي 1 من 72 جزءًا من البوصة)، والسنتيمتر (cm) والميلّيمتر (mm)، كما يمكن استخدام واحدة em الّتي تعتمد على حجم الخطّ، والنّسب المئويّة (%). يمكن التّحكم بموضع فصل المحتوى على صفحتين باستخدام الخواصّ page-break-before و page-break-after و page-break-inside. مثال القاعدة التّالية تعيّن هوامش الصّفحة المطبوعة على كل الجوانب لتساوي بوصة واحدة: @page {margin: 1in;} القاعدة التّالية تُجبر العناوين الرئيسيّة (h1) على أن تكون في رأس الصّفحة دومًا: h1 {page-break-before: always;} تفاصيل أكثر يختلف دعم المتصفّحات لهذه الميّزات، فمتصفّح Firefox يُعيّن قيمًا مبدئيّة للهوامش والترويسات والتّذييلات عند الطّباعة، فلا يمكن توقّع المظهر الّذي ستبدو عليه الصّفحة عند طباعتها بدقّة. واجهة المستخدم لـCSS بعض الخواصّ المُخصّصة للأجهزة الّتي توفّر واجهة استخدام، كشاشات العرض، بحيث تسمح بتغيّر مظهر المستند بصورة ديناميكيّة استجابةً لتفاعل المستخدم مع الواجهة. لا توفّر CSS نوع وسيطٍ خاصّ بالأجهزة ذات واجهات المُستخدم. هناك خمس مُحدِّدات خاصّة: المُحدّد يُحدّد ‏E:hover أي عنصر E تمرّ فوقه الفأرة أو جهاز تأشير آخر ‏E:focus أي عنصر E استحوذ على تركيز لوحة المفاتيح ‏E:active أي عنصر E فعّال (أي يتمّ النقر عليه بالفأرة أو بالإصبع...) ‏E:link أي عنصر E هو رابط لم يزره المستخدم مؤخّرًا. ‏E:visited أي عنصر E هو رابط زاره المُستخدم مؤخّرًا. الخاصّية cursor تسمح بتغيير شكل مؤشّر الفأرة، وفيما يلي بعض الأشكال الشّائعة (مرّر الفأرة فوق كلّ القيمة لترى الشّكل الموافق): المُحدِّد يُحدِّد ‏pointer يُشير إلى رابط ‏wait يُشير إلى أنّ البرنامج لا يستطيع استقبال أي مدخلات لانشغاله ‏progress يُشير إلى أن البرنامج يُنفّذ أمرًا ما، لكنّه ما زال يستطيع استقبال المُدخلات ‏default المبدئيّ (سهم عادةً) الخاصّية outline تُنشئ خطًّا حول العنصر يُستخدم عادةً للإشارة إلى استحواذه على تركيز لوحة المقاتيح، وتكون قيمتها مُشابهة لقيم border، إلّا أنه لا يمكن تعيين قيم مختلفة لكلّ جانب من الخطّ. بعض المزايا الأخرى لواجهات الاستخدام تعتمد على خواص الوسوم (attributes)، فمثلًا يمكن جعل العنصر مُعطّلًا (disabled) أو السّماح بقراءته فقط (read-only) بالخاصّتين disabled و readonly على التّرتيب، ثمّ يمكن استهداف العناصر الّتي تحمل هذه الخواصّ في CSS، كأي خواصّ أخرى، بجعلها ضمن قوسين مُربّعين هكذا: [disabled] و [readonly]. مثال القاعدة التالية تعيّن تنسيق زرّ يتغيرّ استجابة لتفاعل المُستخدم: .green-button { background-color:#cec; color:#black; border:2px outset #cec; } .green-button[disabled] { background-color:#cdc; color:#777; } .green-button:active { border-style: inset; } وهكذا يبدو الزّر في الحالات المختلفة: يُحيط للزّر في الحالة المبدئيّة خطّ داكن عندما يُجعل هذا الزّر هو الزّر المبدئيّ، وخطّ مُنقّط عندما يستحوذ على تركيز لوحة المفاتيح. وقد يكون له تنسيق خاصّ عندما يحطّ فوقه المؤشّر. تدريب: طباعة مستند أنشئ مستند HTML جديدًا، سمّه doc4.html، والصق فيه ما يلي: <!DOCTYPE html> <html> <head> <title>Print sample</title> <link rel="stylesheet" href="style4.css"> </head> <body> <h1>Section A</h1> <p>This is the first section...</p> <h1>Section B</h1> <p>This is the second section...</p> <div id="print-head"> Heading for paged media </div> <div id="print-foot"> Page: </div> </body> </html> أنشئ ورقة أنماط جديدة، سمّها style4.css والصق فيها ما يلي: /*** Print sample ***/ /* defaults for screen */ #print-head, #print-foot { display: none; } /* print only */ @media print { h1 { page-break-before: always; padding-top: 2em; } h1:first-child { page-break-before: avoid; counter-reset: page; } #print-head { display: block; position: fixed; top: 0pt; left:0pt; right: 0pt; font-size: 200%; text-align: center; } #print-foot { display: block; position: fixed; bottom: 0pt; right: 0pt; font-size: 200%; } #print-foot:after { content: counter(page); counter-increment: page; } } /* end print only */ اعرض المستند في متصفّحك. يستخدم المستند تنسيق المتصفّح المبدئيّ. اطبع المستند (أو عاينه قبل الطّباعة)، تجعل ورقة الأنماط كلّ قسم في صفحة مستقلّة، وتُضيف ترويسة وتذييلًا لكل صفحة، وتستخدم رقم الصّفحة في التّذييل (فقط إن كان المتصفّح يدعم العدّادات). تمرين انقل التنسيق الخاصّ بالطّباعة إلى ملفّ CSS مُستقلّ، ثمّ راجع صفحة ‎@import‎ لإيجاد كيفيّة استيراد ورقة أنماط للوسائط المطبوعة ضمن ملفّ style4.css. اجعل العناوين زرقاء عندما يحطّ فوقها مؤشّر الفأرة. شاهد الحل ملف منفصل لتنسيق الطباعة قص السّطور بين /* print only */ و/* end print only */ والصقها ضمن ملفّ سمّه style4_print.css، ثمّ أضف السّطر التّالي لبداية الملفّ style4.css: @import url("style4_print.css") print; لون العناوين عندما يحط المؤشر فوقها القاعدة التّالية تُحقّق التأثير المطلوب: h1:hover { color: blue; } ترجمة بتصرّف للدرس Media من سلسلة Getting started with CSS على شبكة مطوّري Mozilla.
  3. هناك الكثير من الوسائل التي "يجب" عليك أن تستخدمها. ولكنها خطرة وإليك الأسباب. هناك شيءٌ ما يبدو غريبًا عند قول ذلك. وكأننا على وشك مخالفة القوانين. ولكن كلما ناقشنا الأمر أكثر، أصبح الخيار أكثر وضوحًا: يجب علينا إلغاء حساب شركتنا على فيس بوك. لقد كان هناك عاملان رئيسيان أديا بنا إلى اتخاذ هذا القرار: بصراحة، لقد كان الأمر محرجًا، فنحن لدينا أكثر من 2000 زبون و20000 متابع للمدونة وعدة آلاف من الزوار كل أسبوع، وحتى الآن صفحة شركتنا النّاشئة (Groove) على فيس بوك لم تحصل إلا على أقل من 200 مُعجب فقط. وهذا مالا أريد أن يراه من يبحث عنا على فيس بوك.لقد كانت مضيعة للوقت بالنسبة لنا...أنا لا أقول أن فيس بوك هو مضيعة للوقت، فهناك العديد من الشركات تستخدم فيس بوك بنجاح كبير لمساعدتها على النمو. لكننا كنا نمضي نحو ساعة من الزمن أسبوعيًا في العمل على تحديث الصفحة. ومن الواضح أننا لم نحصل على أيّة نتيجة. لا نتيجة.. وعندما كنا نمضي الوقت في مناقشة الأمر والتفكير بالسبب الذي يدفعنا للتواجد على فيسبوك في المقام الأول، كان الجواب يأتينا بسيطًا ومباشرًا ومُحرجًا تمامًا كعدد الإعجابات على الصفحة. ولم نكن موجودين على فيس بوك سوى لأنّ الجميع كان موجودًا هناك، ولأنه كان “يُفترض بنا” أن نتواجد هناك أيضًا. ولكن هذا السبب ليس مقنعاً بما فيه الكفاية. استثمار الوقت بحكمةإن مواردنا محدودة شأننا شأن أغلب الشّركات الناشئة والنشّاطات التّجارية الصغيرة الأخرى. لذا، عندما أعددنا سويّة لاستراتيجية النمو خلال 12 شهراً الخاصة بنا، لم يكن السؤال "ما الذي يمكننا فعله؟" وإنما "ما هي الجهود الأقوى والتي ستكون أفضل استثمار لوقت كل عضو من أعضاء الفريق؟" أي ما الذي يمكننا فعله من أجل تحقيق أكبر نمو لشركة Groove؟ على سبيل المثال، إننا نعلم أن التدوين يساعدنا على تحقيق النمو، وذلك لأننا نتتبع الأرقام بدقة. ولكن ومن جهة أخرى، لا يمكننا ربط جهودنا على صفحة فيس بوك بأية إيرادات على الإطلاق. وكل ساعة نمضيها في إدارة صفحتنا على فيس بوك يمكن أن نمضيها ببناء المدونة. ساعة واحدة أسبوعيًا قد تبدو عديمة الأهمية ولكنها 52 ساعة في السنة. فحجم الزّيارات والاشتراكات التي يمكن أن نحصل عليها خلال 52 ساعة مُعتبر. وفوق ذلك، كنا نهدر الساعات الاثنتين وخمسين الإضافية التي كان يجب أن نقضيها ببناء المدونة، وذلك بسبب ميلنا الأعمى وغير المحسوب لفعل ما "يجب" أن نقوم به. فائدة: قد يكون من المدهش أن تعرف كم كنت تهدر وقتك دون أن تدرك ذلك. وهذا ما كان يحصل معنا، قم بحساب كم فرصة تفوت لدى قيامك بأمور عقيمة. ثلاثة أمور "يجب" علينا القيام بها ولكننا لا نفعلهاهناك عشرات وربما مئات الوسائل التي قد يدّعي بعض الخبراء بأنها أمور "لابد من القيام بها" في كل مشروع. ولذلك، كثير من الناس ينفذون هذه الأمور في مشاريعهم مما يجعلنا نجد صعوبة في تقبل فكرة أن نحيد بتفكيرنا عنها نحو حقيقة أنه في كثير من الأوقات يحتمل ألا تكون غالبية هذه الوسائل مفيدة لنا. ولقد عانيت من هذا الأمر كثيراً. فالابتعاد عن فعل ما نعتقد أنه واجب علينا فعله أمرٌ صعب. وبالرّغم من أننا شركة تبني قراراتها على البيانات والتّحليلات فسأكون كاذباً إن أنكرت شعوري بشيء من الذنب حيال حذف صفحتنا على فيس بوك. ولكن في النهاية هذا الأمر يصب في صالح الأمر الأكثر أهمية: أداء المشروع. لم تكن فيس بوك الأمر الوحيد التي قمنا بالتّخلص منه من بين ما "يجب" القيام به خلال الأشهر القليلة الماضية: فعاليات التواصل Networking Events: أخبرني الكثير من الأشخاص في السابق أنني بحاجة للخروج وبناء العلاقات، وأن الطريقة الأفضل للقيام بذلك هي من خلال فعاليات التواصل. ولكنني وجدت أنّ الجزء الأول من كلامهم صحيح تماماً في حين كان الجزء الثاني عكس ذلك. فقد قابلت الكثير من الأشخاص المثيرين للاهتمام في الفعاليات ولكن لم تكن بداية أيّ من العلاقات التي على قدر عالٍ من الأهمية في فعاليات التواصل. المؤتمرات: إنّ أحد طقوس العبور نحو تنمية المشاريع التقنية الناشئة هو أن تحظى بجناح يعتليه شعارك في مؤتمر مثل مؤتمر DreamForce و South By Southwest. ومن خلال تجربتنا في المعارض التجارية، ومع أن رؤية اسمك هناك أمر جميل، إلا أنها لم تكن ذات نتيجة قيّمة كالتي نحصل عليها عن طريق جهودنا الأخرى. إضافة إلى أنها تكلّف أكثر بكثير من الوقت والمال. العلاقات العامة: عند انطلاق مشروعنا، أنفقنا الكثير من الوقت والجهد في بناء العلاقات مع الصحفيين، وقد كان ذلك مثمرًا حقًا. وكما هو الحال في العديد من الشركات، فإن ورود اسمنا في وسائل الإعلام رفيعة المستوى جذب إلينا زيارات أكثر وعددًا كبيرًا من الاشتراكات. ولكن بعد أن بدأنا بالنمو بدأ دور العلاقات العامة بالتضاؤل. فكانت الاشتراكات غالبًا بجودة أقل ونسبة فقدان المُستخدمين القادمين منها Churn rate أكبر من نفس النسبة الخاصّة بالمشتركين القادمين من المدونة أو من القنوات الأخرى. فقمنا بحسم الأمر في نهاية المطاف. أعتقد أنه من المهم ملاحظة أمر هنا، لأنني أستطيع تخيل تعليقات استشاريي وسائل التواصل الاجتماعي ومنظمي الفعاليات الغاضبين. ما سبق ليس عبارة عن قائمة "استراتيجيات النمو غير الفعالة". بل يكاد يكون العكس هو الصحيح في الحقيقة، فقد كانت هذه الأمور فعالة بالنسبة للبعض لدرجة أنها أدرجت بطريقة أو بأخرى في قائمة الأمور المقدّسة التي يجب على كل مشروع ناشئ القيام بها. ولقد قررنا ونحن بكامل وعينا وإدراكنا ألا نقوم بهذه الأمور، وقد نفعنا ذلك. وقد يكون ما يصلح لغيرنا مختلفًا. فائدة: لا تسمح لقوائم "ما يجب فعله" أن تُملي عليك كيفية استثمار وقتك. عوضًا عن ذلك، قم بإجراء الاختبارات واكتشف ما الذي يصلح لك فعلًا وركّز بقدر ما لديك من الموارد الخاصة بك على تلك الناجحة منها. التكتيكات الثلاثة التي نركز عليها اليومهناك عدد من الوسائل التي نركّز عليها قدر المستطاع وبقدر ما نركز على مواردنا المتوفرة حاليًا. وفي الواقع، سيقوم أحدهم في كثير من الأحيان بالتعليق على مقدار الوقت الذي نمضيه على المدونة. لكن مثلما أؤمن بالإيقاف الصارم عندما يتعلق الأمر بالوسائل غير الفعالة، أؤمن كذلك بتوفير الكثير من الوقت المتاح للقيام بالأمور المثمرة. ولحسن الحظ، ومع القدر الكافي من العمل على تحقيق الهدف الأول، يصبح تحقيق ذاك الأخير أكثر سهولة. وفي حين أنّ هناك الكثير من الأمور الأخرى التي نعمل عليها، إليكم ثلاثة تكتيكات مهمة نركّز عليها ونُخصّص لها جزءً كبيرًا من مواردنا. التدوين: قد يبدو أمرًا جنونيًا أن أقضي أكثر من 20% من وقتي على التّدوين، لكن عائدات الاستثمار في المدونة تتحدث عن نفسها. وهذا هو سبب تركيزنا على توفير المُحتوى. خدمة العملاء: لقد حصلنا على عوائد مرتفعة جدًا من التحدث مع زبائننا بصورة فردية، حتى أنني سأخصص مئات الساعات على مدى الأشهر القليلة القادمة من أجل محادثة الزبائن. مرة أخرى، قد يبدو مقدارًا كبيرًا من الوقت، ولكن سنخصص الوقت لأي أمرٍ هامٍ بما يكفي. المقاييس Metrics: نستخدم مقاييس دقيقة لنبني الطّريقة التي نُدير بها شركتنا النّاشئة. لم يكن ذلك ليحدث لولا أنني طلبت من أحد مهندسينا أن يُخصّص أسبوعًا كاملًا ليعمل على بناء نظام تتبّع وتحليل tracking system خاص بنا. فائدة: لا تخف من قضاء الكثير من الوقت للقيام بعمل ما، طالما أنه عمل مثمر. ليس هناك دليل وافٍ لمقدار الوقت الواجب قضاؤه مع هذه الوسيلة أو تلك، لأنه لا توجد أي شركة ناشئة أخرى بنفس مواصفات شركتك الحالية. كيف تطبق كل هذا على شركتك الناشئة؟ لقد ترددت قبل نشر قائمة الوسائل الفعليّة التي نستخدمها والتي لا نستخدمها، لأني أعتقد أن ذلك ليس بأهميّة الفكرة الأساسية لهذا المقال ومن المحتمل أنها تصرف الانتباه عنها. في النهاية، أبقيتها لأنني أعتقد أنها تفيد كأمثلة مساعدة، لكن آمل أن النّتيجة التي استخلصتها من قراءة هذا المقال هي أن وقتك أثمن بكثير من أن تهدر ولو ساعة واحدة بلا فائدة، وكذلك أنّ الفشل دائما قريب جدًا. إنّ القيام بأمور غير ذات نفع ليس أمرًا ضارًا بحد ذاته، إنما هو في الحقيقة الطريقة الوحيدة لنتطور ونجد ما الذي يفيدنا فعلاً. ولكن الاستمرار بالأمور التي لا تجدي نفعًا مرارًا وتكراراً لأنك وببساطة "يجب" عليك أن تقوم بها، هو تدمير فعلي لمشروعك. منذ وقت ليس ببعيد، كنت بحاجة إلى أن يُنبّهني أحدهم إلى هذا الأمر. لذا أرجو أن يكون تنبيهي هذا مفيد لك أيضًا. ترجمة -وبتصرّف- للمقال We Deleted Our Facebook Page. لصاحبه Alex Turnbull. حقوق الصورة البارزة: Designed by Freepik.
  4. في المقال الأول تكلمنا حول أساسيات صفحات الهبوط، وفي المقال الثاني صممنا صفحة هبوط في Photoshop باستخدام ما تعلمانه، الآن سنكمل ما بدأنا به ببناء صفحة الهبوط فعليا، سنمر على كل المراحل إنطلاقا من توزيع الملفات إلى صفحة جاهزة، هيا لننطلق. يمكنك تحميل الشِفرة المصدرية لهذا الدرس لمعاينة النتيجة النهائية. وهذا تذكير بواجهة الصفحة: الأساسياتفي البداية سنقوم بتوضيح ما سنقوم باستخدامه ولماذا سنستخدمه. أولا، لدينا الصور التي حصلنا عليها من ملف PSD الذي قمنا بتصميمه في درس التصميم، فلنستخدمها.لن نستخدم خط أيقونات لسبب وجيه وهو أنها ستكون مضيعة وقت وبدون فائدة فعلية فالصفحة مجرد صفحة واحدة لذا لا يوجد الكثير لنقلق بشأنه (بشأن عدد طلبات HTTP كمثال).سنستخدم هيكلة HTML5 Boilerplate وهو هيكل عمل مصغر لبناء صفحات HTML حيث يحتوي على تقسيم مجلدات ممتاز، ويوزدك ببعض الملفات المهمة مثل .htaccess و ملف index كامل يحتوي على كل شيء تحتاجه.سنستعمل بعض إضافات إطار عمل Bootstrap، وهم: Affix من أجل تثبيت قائمة التصفح عند النزول.إضافة Scrollspy من أجل تغيير لون الأيقونات كلما ممرنا على مرحلة.سنستخدم إضافة Owl carousel 2.0 من أجل جزء الشهادات، إذا كنت تملك إضافة أخرى فأنت حر باستخدامها.سنستعمل موقع TinyPNG من أجل ضغط الصور التي حصلنا عليها من ملف PSD.سنستخدم موقع Everything Font من أجل تحويل خط Cocon إلى نسخة الويب (woff) حتى نستخدمها.تقسييم الملفاتسيكون تقسيمنا للملفات على الشكل التالي: project/ ├── css/ │ ├── main.css │ ├── normalize.css │ └── owl.carousel.css ├── fonts/ │ └── CoconNextArabicLight.woff ├── js/ │ ├── main.js │ └── vendors/ │ ├── bootstrap.min.js │ ├── jquery-1.11.2.min.js │ └── owl.carousel.min.js ├── img/ ├── index.html └── favicon.icoعند تحميل إطار عمل H5BP فإنه يزودنا بالتقسييم بالتالي بشكل افتراضي، ما قمنا به نحن هو إضافة بعض الملفات في بعض الأماكن فحسب، مجلد img يحتوي على الصور التي حصلنا عليها من المرحلة السابقة عبر استخراجها من فوتوشوب، كما قمنا بإضافة bootstrap.js الذي يحتوي على كلٍ من affix وscrollspy. وقمنا بحذف بعض الملفات مثل modernizer وhtml5shiv لأننا لن ندعم المتصفحات القديمة. البدايةحسنا، نحتاج إلى أن نعد بعض الأمور قبل أن نبدأ، بعد تحميل كامل المكتبات المطلوبة نستطيع البدأ بإعداد بعض الأمور. نحن نملك خط Cocon بصيغة سطح المكتب (ttf). لا ضرر في هذه الصيغة إطلاقا، هي تعمل بشكل ممتاز في المتصفحات، ولكننا نستطيع تقليل الحجم إلى النصف عبر تحويل الخط إلى صيغة woff المخصصة للويب وذلك عبر موقع التحويل (ستجد الخط محولا في الشفرة المصدرية لهذا الدرس). نحتاج إلى ضغط الصور، هناك فائدة عظيمة نكسبها هنا، موقع TinyPNG سيقوم بتقليل حجم الصور إلى أكثر 70% مع الحفاظ على الجودة، وهذا حجم ممتاز لذلك سنقوم بذلك أيضا. الآن سنعد بعض الأمور الابتدائية في ملف CSS: @import url(owl.carousel.css); @font-face { font-family: Cocon; src: url(../fonts/CoconNextArabicLight.woff) format('woff'); } *, *:before, *:after { box-sizing: border-box; } body { font-family: cocon, sans-serif; background: #fff; position: relative; }سنقوم باستدعاء ملف owl.carousel من أجل تأثيرات الحركة في السكربت، سنقوم بإدراج خط Cocon للاستخدام، سنستعمل box-sizing من أجل احتواء العناصر بشكل أفضل. سنضيف بعض الأمور الافتراضية لوسم body. مكتبة scrollspy تحتاج إلى أن يكون وسم body بخاصية position:relative من أجل أن تعمل.هيكلة الصفحةفي سابق الأمر، كنُت قد خططت لبناء الصفحة عبر إطار عمل Bootstrap المعروف، وسبق وقلت هذا في المقال السابق، ولكني تراجعت عن الأمر لقلة الفوائد مقارنة بالسيئات، ووجدتها فرصة حسنة لاستخدام Flex module والتكلم عنه أكثر. أما بخصوص Bootstrap فلدي آرائي حوله، من بينها أنّه إطار مناسب تماما لإطلاق المشاريع بسرعة من أجل التجريب (لاحظ الاسم Bootstrap) كما أنّه إطار مناسب لبناء المشاريع الداخلية حيث لن يتم إطلاق المشروع لجمهور فعلي، إلا إذا كنت تنوي تخصيصه حتى النخاع فتغير مظهره، فذلك شأنك. الصفحة مكونة من 6 أجزاء أساسية: رأس الصفحة.روابط التصفح عبر الصفحة.مميزات التطبيق.الاقتباسات (أو الشهادات).الأرقام (أو التحليلات).التحميل والمشاركة.والهيكة الأساسية ستكون كالتالي: <header class="l-header"> <div class="l-app-preview"> </div> <div class="l-page-fold"> </div> </header><!-- .l-header --> <nav class="l-sticky-nav"> <div class="sticky-nav"> </div><!-- sticky-nav --> </nav><!-- l-sticky-nav --> <article id="features-section"> <section class="l-app-feature"> </section> </article><!-- #features-section --> <article id="testimonials-section"> </article><!-- #testimonials-section --> <article id="analysicts-section"> </article><!-- #analysicts-section --> <article id="download-section"> </article><!-- #download-section -->قمنا بتقسييم كل جزء من الصفحة إلى وسم article مستقل (ما عدى روابط التصفح ورأس الصفحة حيث يملكان وسوما افتراضية خاصة بهم من قبل). قمنا بتقسييم رأس الصفحة إلى جزئين، الأول سيحتوي بداخله صورة واجهة التطبيق، أما الثاني فسيحتوي على العنوان إلى جانب السطر الرئيسي وزر التحميل. روابط التصفح تملك جزئين، حاوي رئيسي وحاوي الروابط، وهناك سبب وجيه لهذا التكرار، بحيث عندما يتم تفعيل تثبيت الروابط على أعلى الشاشة، نرى أن يبقى هناك مكان فارغ (في المكان السابق الذي كانت الروابط موجودة فيه) حيث لا يحدث اختلال في الصفحة، الجزء المسؤول عن هذا سيكون l-sticky-nav، أيضا لاحظوا أنّ كل الروابط التي تحتوي على حرف L قبل اسمها (اختصارا لـ layout) ستكون مسؤولة عن الهيكلة بشكل خاص. رأس الصفحة<header class="l-header"> <div class="l-app-preview"> <img src="img/home-screen.png" alt=""> </div> <div class="l-page-fold"> <h1 class="display-title">اكتشف أشخاصا بنفس اهتماماتك</h1> <p class="display-content">تعرف على أشخاص يشاركونك الهوايات والاهتمامات شارك، اقرء، وتواصل مع الجميع عبر تطبيق اهتمامات</p> <a href="" class="display-badge"> <img src="img/badge.png" alt="حمل من متجر التطبيقات"> </a> </div> </header><!-- .l-header -->كان ذلك هو رأس الصفحة، بكل بساطة وكما أشدنا سابقا، الآن حان وقت إضافة بعض CSS له. .l-header { display: flex; justify-content: center; align-items: center; width: 100%; min-height: 100vh;/* used to make sure the header will cover the screen */ position: relative; padding: 48px 0; /* سيعطي هذا بعض المساحة للشاشات الصغيرة حيث المحتوى أكبر من ارتفاع الشاشة */ background: url(../img/background.png) center center no-repeat; background-attachment: fixed; background-size: cover; }الشفرة المصدرية مقسمة لثلاث أجزاء، كل جزء له مهمته المعينة. الجزء الأول مسؤول عن هيكلة رأس الصفحة، نحن نطلب منه أن يستخدم flex كنظام للهيكلة عبر display:flex وأن يقوم بوضع جميع العناصر في منتصف الصفحة أفقيا عبر justify-content:center والواقع أنها تقبل العديد من الخيارات الأخرى، منها flex-start التي تضع جميع العناصر في بداية الصفحة (اليمين في حالة العربية، أو اليسار في حالة اللاتينية، لكن الأمر لا علاقة له باتجاه الصفحة في واقع الأمر، بل باتجاه ترتيب العناصر عبر خاصية flex-direction التي تقبل 4 خيارات وهي ترتيب العناصر بشكل أفقي من بداية الصفحة لنهايتها عبر row ومن نهاية الصفحة إلى بدايتها عبر row-reverse أو من أعلى الصفحة إلى أسفلها عبر column أو العكس عبر column-reverse وسنتكلم عن هذا لاحقا) أو خيار flex-end الذي يقوم بالعكس، والخياران اللذان ستستخدمها كثيرا وهما space-around حيث يتم توزيع المساحة بين العناصر بالتساوي (وبالتالي في المنتصف ولكن مع مساحة بينهم وقبلهم وبعدهم) و space-between والتي تقوم بتوزيع المساحة بين العناصر بدون إضافة مساحة قبل العناصر وبعدهم (أيّ يتم تركيز كامل المساحة في المنتصف). الخيار الثالث يقول أننا نريد أن نضع العناصر في المنتصف عموديا وذلك عبر align-items:center والواقع أنّ الخاصية تملك أيضا خيارات كثيرة لا متسع لنا لشرحها كاملة الآن لأنها تحتاح لشرح بالصور في الغالب، ومنها flex-start التي تضع العناصر أعلى الصفحة (أو بالأحرى حسب الطريقة التي تم تحديد اتجاه المحور العمودي فيها عبر flex-direction كما بيّنا سابقا). الجزء الثاني، هو مسؤول عن جعل حجم رأس الصفحة بكامل أبعاد الشاشة، نستطيع جعله بكامل عرض الشاشة عبر width:100% أو بالمثل عبر width:100vw لا فرق بينهم لأنّ حاوي رأس الصفحة نفسه بكامل عرض الصفحة، تبقى المشكلة في الارتفاع، تحديد 100% لن ينفع وتحديد رقم معين لن ينفع إطلاقا مع كل الشاشات، الحل الوحيد هو استخدام وحدة القياس الجديدة vh والتي تقيم أبعاد الشاشة وليس العناصر، بحيث 100vh تعني كامل ارتفاع الشاشة. في الجزء الثالث سنقوم بإضافة خلفية، وضعها في المنتصف، نعطيها خاصية cover حتى تتمدد (مع المحافظة على الأبعاد ratio) على حسب الشاشة. .l-header:before { content: ""; position: absolute; top: 0; right: 0; height: 100%; width: 100%; background-color: rgba(0,0,0,0.64); }هذا الجزء مسؤول عن إضافة تأثير السواد فوق الصورة، البعض يقوم بإضافة عنصر (div) آخر داخل رأس الصفحة من أجل تحقيق هذا، ولكن هذا الحل أكثر نظافة، لاشيء فعلي لنشرحه هنا عدى أنّ عدم إدراج خاصية content (حتى ولو كانت فارغة) سيجعل الشفرة المصدرية السابقة غير فعالة، فأشباه الأصناف (pseudo-classes) لا تعمل بدونه. .l-app-preview, .l-page-fold { width: 50%; z-index: 10; position: relative; /* نحتاج إلى هذا الجزء لأن خاصية z-index لا تعمل مع static */ }هنا نقوم بإعطاء كل جزء منهم 50% من عرض الحاوي الخاص بهم، حتى يتم توزيع المحتوى بشكل عادل، خاصية z-index حتى نتأكد من أنّ المحتوى فوق تأثير السواد على الخلفية (لن يشكل هذا مشكلة في الأغلب لأننا استخدمنا شبه صنع before الذي سيضعه قبل العناصر أصلا). خاصية position:relative تم وضعها من أجل z-index لأنّه لا يعمل بدون تحديدها (في الواقع هو يعمل مع الجميع عدى static أيّ القيمة الافتراضية). مع إضافة بعض التأثيرات على العنوان، والقيام بتوسيط الصفحة، نخرج بهذه الشِفرة: .l-header { display: flex; justify-content: center; align-items: center; width: 100%; min-height: 100vh; position: relative; padding: 48px 0; background: url(../img/background.png) center center no-repeat; background-attachment: fixed; background-size: cover; } .l-header:before { content: ""; position: absolute; top: 0; right: 0; height: 100%; width: 100%; background-color: rgba(0,0,0,0.64); } .l-app-preview, .l-page-fold { width: 50%; z-index: 10; position: relative; } .l-app-preview img { display: block; margin: 0 auto; } .l-page-fold { padding-left: 24px; } .display-title { color: #fff; font-size: 55px; line-height: 1.2; margin-bottom: 36px; } .display-content { color: #fff; font-size: 28px; line-height: 1.7; margin-bottom: 128px; }تاليا سنعمل على روابط التصفح روابط التصفحالهيكلة كالتالي: <nav class="l-sticky-nav"> <div class="sticky-nav"> <div class="nav-element"> <a href="#features-section" class="nav-element--link active"> <img src="img/equalizer.png" alt="" class="nav-element--image"> </a> </div> <div class="nav-element"> <a href="#testimonials-section" class="nav-element--link"> <img src="img/id.png" alt="" class="nav-element--image"> </a> </div> <div class="nav-element"> <a href="#analysicts-section" class="nav-element--link"> <img src="img/globe.png" alt="" class="nav-element--image"> </a> </div> <div class="nav-element"> <a href="#download-section" class="nav-element--link"> <img src="img/download.png" alt="" class="nav-element--image"> </a> </div> </div><!-- sticky-nav --> </nav><!-- l-sticky-nav -->لاشيء لشرحه، هيا لنطلع على شِفرة CSS: .l-sticky-nav { margin-bottom: 128px; /* هذا الجزء منفصل عن روابط التحكم، بالأحرى عندما تلتصق الروابط في أعلى الشاشة سيبقى هذا في مكانه */ } .l-sticky-nav.fixed { padding: 50px; /* عندما يتم تثبيت التثبيت على روابط التصفح، سيبقى هذا في مكانه حتى لا تختل المساحة */ }سنعطي الحاوي الأول بعض المساحة في الأسفل، أيضا عندما يتم تثبيت الروابط سيصبح l-sticky-nav فارغا وبالتالي يكون ارتفاعه 0، مما يلغي فائدته، لذا في تلك الحالة سنجعل ارتفاعه 100px. الآن بالنسبة للحاوي الثاني: .sticky-nav { display: flex; justify-content: space-around; flex-wrap: wrap; padding: 24px; background-color: #fff; box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.1); }خاصية flex-wrap تحدد هل سيقوم الحاوي بوضع كامل العناصر في سطر واحد (عبر إعطائه no-wrap أيضا الخاصية الافتراضية) أو بوضع العناصر في سطر جديد إن لم يكن هناك متسع من المكان (عبر wrap)، عدى هذا كل شيء واضح، نقوم بتوسيط العناصر فحسب. .sticky-nav.affix { top: 0; right: 0; width: 100%; z-index: 10; position: fixed; }الآن عند تفعيل التثبيت سيتم (عبر Javascript) إضافة class إلى الحاوي الثاني، إنطلاقا منه سنقوم بتحديد ما نريده، وهو تثبيت العناصر في أعلى الشاشة، لكن في العلم أنّه عند إضافة خاصية fixed فالعنصر يخرج من نسق الصفحة، وشيء آخر وهو أنّ خاصية display:block لا تفيد بشيء حينها، لذا العنصر لن يأخذ كامل المساحة الأفقية التي يجدها (width:100%) بل يأخذ ما يحتاجه فحسب، لذا علينا تحديد الأمر بأنفسنا. .nav-element--image { filter: grayscale(100%); -webkit-filter: grayscale(100%); transition: all 200ms ease-out; } .nav-element--link.active .nav-element--image, .nav-element--link:hover .nav-element--image { filter: grayscale(0); -webkit-filter: grayscale(0); }نقوم بتحويل جميع الأيقونات إلى الرمادي عدى الأيقونات المفعلة (.active) أو التي يكون المؤشر فوقها. وهكذا نكون انتهينا من جزء آخر، الدور على جزء مميزات التطبيق. مميزات التطبيقالهيكلة كالتالي: <article id="features-section"> <section class="l-app-feature"> <div class="app-feature-preview"> <img src="img/feature-1.png" alt="" class="app-feature-image"> </div> <div class="app-feature-content"> <h2 class="app-feature-title">أضف، تابع، وتواصل مع من تشاركه الاهتمام</h2> <p class="app-feature-text">أضف إلى قائمة أصدقائك من تجدهم يشاركونك نفس الاهتمام، صنف أصدقائك على حسب اهتماماتك، وتواصل مباشرة معهم</p> </div> </section> <section class="l-app-feature"> <div class="app-feature-preview"> <img src="img/feature-2.png" alt="" class="app-feature-image"> </div> <div class="app-feature-content"> <h2 class="app-feature-title">شارك ما تجده مميزا، وعبر عن رأيك</h2> <p class="app-feature-text">أكتب المقالات لتشاركها مع دائرة أصدقائك، وأقرء مقالات الجديدة أو اكتشف اهتمامات جديدة</p> </div> </section> <section class="l-app-feature"> <div class="app-feature-preview"> <img src="img/feature-3.png" alt="" class="app-feature-image"> </div> <div class="app-feature-content"> <h2 class="app-feature-title">ابني حسابك الشخصي، وأحصل على متابعين</h2> <p class="app-feature-text">ابني حسابك الشخصي الخاص، شارك صورك وسيرتك، ودع الناس يقومون بمتابعتك</p> </div> </section> </article><!-- #features-section -->تم تقسييم كل جزء إلى section خاص به يحتوي بدوره على قسمين، واحد للصورة وواحد للعنوان والشرح، الأمر شبيه تماما برأس الصفحة، في الواقع سيعمل بنفس مفهوم رأس الصفحة. .l-app-feature { display: flex; justify-content: center; align-items: center; padding: 128px 0; } .l-app-feature:nth-child(even) { flex-direction: row-reverse; background: #13191C; } .l-app-feature:nth-child(even) .app-feature-title, .l-app-feature:nth-child(even) .app-feature-text { color: white; }الشيء الوحيد الجديد هنا هو (nth-child(even نحن هنا نقوم بتحديد كل العناصر التي تكون رتبتها رقما زوجيا (الثاني والرابع والسادس، يمكن أيضا القيام بالأمر عبر تمرير 2n+2 بدل evenمن أجل نفس النتيجة، في الواقع تستطيع تمرير أي معادلة من الشكلة an+b من أجل استهداف العناصر التي تريدها) قمنا بتمرير flex-direction:row-reverse من أجل عكس اتجاه المحور الأفقي حتى تبدأ العنصر من الاتجاه المعاكس، هذا سيجعل الصورة على اليسار والمحتوى على اليمين. وهذه كامل الشِفرة .l-app-feature { display: flex; justify-content: center; align-items: center; padding: 128px 0; } .l-app-feature:nth-child(even) { flex-direction: row-reverse; background: #13191C; } .l-app-feature:nth-child(even) .app-feature-title, .l-app-feature:nth-child(even) .app-feature-text { color: white; } .app-feature-preview, .app-feature-content { width: 50%; max-width: 600px; } .app-feature-preview img { display: block; margin: 0 auto; } .app-feature-title { font-size: 36px; color: #f85940; margin-bottom: 36px; } .app-feature-text { font-size: 28px; color: rgba(30,30,30,.9); line-height: 1.7; }جزء الشهاداتفي هذا الجزء قمنا باستخدام carousel من أجل عرض الشهادات والهيكلة كانت كالتالي: <article id="testimonials-section"> <h1 class="section-title">فلنسمع رأي البقية</h1> <section class="testimonials-carousel"> <div class="testimonial-item"> <div class="testimonial-text">أتمنى لو كان هذا التطبيق موجودا قبل سنة</div> <div class="testimonial-avatar"><img src="img/face-1-128.png" alt="" class="testimonial-image"></div> </div> </section> </article><!-- #testimonials-section -->أضفنا عنوانا، إلى جانب وضع الشهادات في حاوي خاص بهم من أجل تحديده عبر Javascript، ثم وضعنا لكل شهادة حاوي خاص بها testimonial-text يحتوي على محتوى الشهادة بالإضافة إلى صورة. .testimonial-item { display: flex; flex-direction: column; align-items: center; padding: 24px 0; margin-bottom: 48px; }هيكلة كل عنصر يتكون بسيطة، استخدما flex-direction:column لترتيب العناصر عموديا، كما استخدما align-items:center لتوسيط العناصر أفقيا (لاحظ أننا استخدمناها سابقا لتوسيط العناصر عموديا، ولكن لأن محور الترتيب اختلف الآن فهي ترتب العناصر أفقيا إلى الوسط) .testimonial-text:before, .testimonial-text:after { font-size: 48px; display: inline-block; padding: 0 16px; } .testimonial-text:before { content: "”"; } .testimonial-text:after { content: "“"; }قمنا هنا بإضافة علامتي تنصيص قبل وبعد الشهادة، قمنا بتكبير حجمهما ووضع بعض الفراغ بينهما وبين الشهادة. OwlCarousel (السكربت المستخدم من أجل عرض الشهادات) يعطينا أزرار التصفح بين الشهادات (على شكل نقاط) ولكنها بدون أيّ تأثير لذا سنقوم بذلك يدويا .owl-dots { text-align: center; } .owl-dot { height: 16px; width: 16px; border: 2px solid #E4523B; border-radius: 50%; display: inline-block; margin: 0 4px; } .owl-dot.active { background: #E4523B; }تحليلات الأرقاميحين وقت أرقام التحليلات، من أجل إطفاء التغيير وإضافة التركيز قمنا بإضافة خلفية لهم، هيكلة الجزء كانت كالتالي: <article id="analysicts-section"> <h1 class="section-title section-title__white">بعض الأرقام</h1> <div class="l-analysicts"> <div class="analysicts-item"> <div class="item-image"> <img src="img/articles.png" alt=""> </div> <h1 class="item-number">320</h1> <h2 class="item-title">مقالة نشرت</h2> </div> <div class="analysicts-item"> <div class="item-image"> <img src="img/groups.png" alt=""> </div> <h1 class="item-number">57</h1> <h2 class="item-title">مجموعة أنشئت</h2> </div> <div class="analysicts-item"> <div class="item-image"> <img src="img/users.png" alt=""> </div> <h1 class="item-number">+8000</h1> <h2 class="item-title">عضو مُسجل</h2> </div> <div class="analysicts-item"> <div class="item-image"> <img src="img/upload.png" alt=""> </div> <h1 class="item-number">450</h1> <h2 class="item-title">ملف رفع</h2> </div> </div> </article><!-- #analysicts-section -->منطق الهيكلة شبيهة بهيكلة مميزات التطبيق والشِفرة والتقسييم كانا بسيطان إلى أقصى حد: #analysicts-section { position: relative; padding: 48px 0; margin: 48px 0; background: url(../img/numbers-background.png) center center no-repeat; background-attachment: fixed; background-size: cover; } .l-analysicts { display: flex; justify-content: space-around; flex-wrap: wrap; } .analysicts-item { text-align: center; color: white; }جزء التحميل والمشاركةهذا الجزء بسيط إلى أقصى حد، عنوان بسيط مع زر للتحميل و 4 أزرار للدلالة على شبكات التطبيق الاجتماعية <article id="download-section"> <h1 class="section-title">إذا، هل قررت الانضمام؟</h1> <div class="cta-button"><img src="img/badge.png" alt=""></div> <div class="l-social-links"> <a href="" class="social-link"> <img src="img/facebook.png" alt="شارك في Facebook"> </a> <a href="" class="social-link"> <img src="img/twitter.png" alt="شارك في Twitter"> </a> <a href="" class="social-link"> <img src="img/pinterest.png" alt="شارك في Pinterest"> </a> <a href="" class="social-link"> <img src="img/google.png" alt="شارك في Google+"> </a> </div> </article> وبنفس البساطة أيضا .cta-button { margin: 36px 0; text-align: center; display: block; } .l-social-links { display: flex; justify-content: space-around; padding: 48px 0 64px; }Javascriptحان الوقت لإضافة Javascript إلى الصفحة، سنبدأ بإضافة Affix لروابط التصفح من أجل تثبيتهم. تنويه: في عالم مثالي كنا لنستخدم position:sticky لتقوم بالمهمة لنا، للأسف المتصفح الوحيد الذي يدعمها هو فيرفوكس، متصفح chrome كان يدعمها من قبل ولكنهم أزالوا الدعم في الوقت الحالي، لذا affix يعتبر أشبه بـِ polyfill. لدينا الشِفرة التالية التي سيتقوم بكل شيء لنا: $('.sticky-nav').affix({ offset: { top: $('.l-header').outerHeight() } }); $('.sticky-nav').on('affix.bs.affix', function () { $('.l-sticky-nav').addClass('fixed'); }); $('.sticky-nav').on('affixed-top.bs.affix', function () { $('.l-sticky-nav').removeClass('fixed'); });نقوم بتفعيل السكربت عبر إضافته إلى sticky-nav ثم نقوم بتحديد offset والذي يعني متى يتم تفعيل السكربت، نحن نريده أن يتفعل حالما يتم المرور عليه، نريد حساب كامل المسافة التي فوقه، وتلك المسافة ستكون حجم رأس الصفحة، لذا نضيفها عبر ()outerHeight التي تحسب الارتفاع الخارجي (من ضمنه padding). ثانيا نقوم بالاستماع إلى بعض الأحداث (events) والسكربت يوفر لنا 4 أحداث، سنستخدم اثنين فحسب، أول حدث ينطلق عندما يتم تفعيل السكربت مباشرة، وفي تلك اللحظة نضيف fixed إلى الحاوي من أجل أن يستغل المكان، تاليا نستمع للحدث الثاني والذي ينطلق حالما يتم إزالة السكربت (عند الرجوع للحالة العادية) في تلك اللحظة سنزيل fixed عن الحاوي ليعود إلى طبيعته. الآن سنتجه إلى scrollspy وهي تملك شروطا أكثر ازعاجا، مثل أنّها تعمل مع عناصر bootstrap فحسب لذا سنقوم ببعض التعديل في HTML و CSS أولا. <nav class="l-sticky-nav"> <ul class="nav sticky-nav"> <li class="nav-element"> <a href="#features-section" class="nav-element--link active"> <img src="img/equalizer.png" alt="" class="nav-element--image"> </a> </li> <li class="nav-element"> <a href="#testimonials-section" class="nav-element--link"> <img src="img/id.png" alt="" class="nav-element--image"> </a> </li> <li class="nav-element"> <a href="#analysicts-section" class="nav-element--link"> <img src="img/globe.png" alt="" class="nav-element--image"> </a> </li> <li class="nav-element"> <a href="#download-section" class="nav-element--link"> <img src="img/download.png" alt="" class="nav-element--image"> </a> </li> </ul><!-- sticky-nav --> </nav><!-- l-sticky-nav -->ما قمنا به هنا هو إضافة nav إلى الحاوي الثاني sticky-nav وقمنا بتغييره من div إلى ul ثم قمنا بتغيير العناصر nav-element من div إلى li. نقوم الآن بتعديل بعض CSS: .nav-element.active .nav-element--image, .nav-element:hover .nav-element--image { filter: grayscale(0); -webkit-filter: grayscale(0); }كل ما فعلناه هو أننا غيرنا nav-element–link إلى nav-element فحسب. الآن نستطيع استخدام الإضافة بشكل عادي تماما. $('body').scrollspy({ target: '.l-sticky-nav' });سوف نقوم بإضافتها إلى body هذا لأن عناصرنا (أقسام الصفحة) تقع مباشرة داخل وسم body وحددنا الهدف l-sticky-nav حيث يكون هو من يتم تعديل القيم فيه. تاليا سنقوم بإضافة carousel إلى الشهادات: if($('.testimonials-carousel').children().length > 1) { $('.testimonials-carousel').owlCarousel({ loop: true, nav: false, dots: true, rtl: true, items: 1 }) } ما نقوم به هو أننا نتفقد إن كان هنالك أكثر من شهادة، لأن OwlCarousel لا يعمل إذا كان هناك عنصر واحد في الصفحة (مشكلة على الأرجح سيتم إزالتها في النسخة الرسمية) بعد ذلك نقوم بتفعيله، وإعطائه بعض الخيارات، منها أننا لا نريد روابط للتقليب إلى اليمين واليسار، وأننا نريد نقاط التصفح فحسب، وأننا نريده أن يعمل من اليمين إلى اليسار (هذا السبب الوحيد الذي يدفعنا إلى استخدام النسخة 2.0 على النسخة الرسمية 1.3 وهو بسبب دعم اليمين إلى اليسار) وأننا نريد عنصرا واحدا كل مرة. هذا هو كامل شِفرة Javascript، لقد كانت بسيطة حقا: $(document).ready(function(){ $('.sticky-nav').affix({ offset: { top: $('.l-header').outerHeight() } }); $('.sticky-nav').on('affix.bs.affix', function () { $('.l-sticky-nav').addClass('fixed'); }); $('.sticky-nav').on('affixed-top.bs.affix', function () { $('.l-sticky-nav').removeClass('fixed'); }); $('body').scrollspy({ target: '.l-sticky-nav' }); if($('.testimonials-carousel').children().length > 1) { $('.testimonials-carousel').owlCarousel({ loop: true, nav: false, dots: true, rtl: true, items: 1 }) } })الخاتمةكانت هذه رحلة طويلة، انطلقنا من تعلم أساسيات ومكونات صفحات الهبوط إلى بناء واحدة لتطبيق وهمي، أول مقال ليس مخصصا للمطوريين أو المصممين بشكل خاص، أيّ مسوق أو مدير مشروع يستطيع أن يبني صفحة هبوط منتجه انطلاقا من ذلك الدليل على ورقة وإرساله لمطور ما، المقالان الآخيران كان أكثر تعمقا حيث في الواقع تطبيقا لما تعلمناه، الآن لكم المقدرة على إطلاق صفحات لمشاريعك، وجلب عملاء أكثر ومشتريين أكثر
×
×
  • أضف...