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

Mustafa Suleiman

الأعضاء
  • المساهمات

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

  • تاريخ آخر زيارة

  • عدد الأيام التي تصدر بها

    365

كل منشورات العضو Mustafa Suleiman

  1. كلام صحيح، وذلك هو الغرض من دورة خاصة بتعلم أساسيات علوم الحاسب ومخصصة لمن لا يمتلك أي دراية بالبرمجة أو علوم الحاسب، لذلك لا يتم التعمق بشكل كبير في كتابة الكود بل التدريب على التفكير المنطقي والتعرف على علوم الحاسب ومجالات البرمجة وآلية عمل الويب والسيرفرات وقواعد البيانات وخلافه. الأمر الذي يؤهلك لإختيار مجال البرمجة الذي تريده على دراية ووعي، أيضًا يجنبك الإحباط عند التعمق ودراسة لغة البرمجة الأولى لك، مثل دورة بايثون أو دورة جافاسكريبت. وتستطيع الاستزادة وتعلم ما تريد من خلال المسار الأول في دورة تطوير واجهات المستخدم في مسار أساسيات تطوير الويب، وأيضًا المسار الأول دورة تطوير التطبيقات باستخدام JavaScript وهو أساسيات لغة JavaScript، وكل المسارات الأولى من الدورات الأخرى متاحة لك بشكل مجاني. وبإمكانك أيضًا البحث على يوتيوب عن مشاريع جافاسكريبت أو بايثون للمبتدئين وستجد الكثير من أجل التطبيق على ما تعلمته، وأيضًا تستطيع البحث عما تريد فهمه، ويوجد شرح كامل لجافاسكريبت وبايثون في أكاديمية حسوب وموسوعة حسوب: https://wiki.hsoub.com/الصفحة_الرئيسية https://academy.hsoub.com/programming/javascript/ https://academy.hsoub.com/programming/python/
  2. يوجد عدة أخطاء في الكود وهي كالتالي: تم استيراد React مرتين واستخدام useReact مرتين أيضًا، وعليك باستيراد React مرة واحدة فقط واستخدام useState مرة واحدة. هناك خطأ في كتابة "useState"، اعتمد على useState وليس usestate. هناك خطأ في كتابة "useNavigate"، نستخدم useNavigate وليس usenavigate. الكود يحتوي على ترقيم غير صحيح في الكود الخاص بـ yup.object. يجب أن يكون yup.object() بدلاً من yup object(). في جزء cpassword, يوجد غلق قوس مفقود بعد [yup.ref('password')]. يوجد أخطاء في كتابة الدوال داخل الكود، استخدم useFormik و useState بدلاً من useformik و usestate على التوالي، ويجب أن يكون onSubmit بدلاً من onsubmit. في دالة register, هناك غلق قوس مفقود بعد if data.message == "succuess". هناك خطأ في كتابة Console.log، والصحيح هو console.log. وإليك الكود بعد تصحيح ما سبق. import React, { useState } from 'react'; import axios from 'axios'; import { useFormik } from 'formik'; import { useNavigate } from 'react-router-dom'; import * as yup from 'yup'; const Register = () => { const [errors, setErrors] = useState([]); const navigate = useNavigate(); const [statusErrors, setStatusErrors] = useState(''); const schema = yup.object({ name: yup.string().required('name is required').min(3, 'min is 3 char').max(10, 'max is 10 char'), email: yup.string().required('email is required').email('not valid email'), password: yup.string().required('password is required').matches(/^[A-Z][a-z0-9]{4,8}$/, 'not valid password'), cpassword: yup.string().required('confirm password is required').oneOf([yup.ref('password')], 'passwords do not match'), }); const formik = useFormik({ initialValues: { email: '', name: '', password: '', cpassword: '', }, validationSchema: schema, onSubmit: register, }); async function register(values) { try { const { data } = await axios.post('https://lazy-blue-sockeye-gear.cyclic.app/api/v1/auth/signup', values); console.log(data); if (data.message === "success") { console.log("registered"); } } catch (error) { console.log(error); } } return ( <div className="container mt-5 pt-5"> <form className="w-50 m-auto text-center" onSubmit={formik.handleSubmit}> <div className="mb-3"> <label htmlFor="exampleInputEmail1" className="form-label">Email address</label> <input type="email" className="form-control" id="exampleInputEmail1" value={formik.values.email} onChange={formik.handleChange} name="email" aria-describedby="emailhelp" /> </div> <div className="mb-3"> <label htmlFor="exampleInputName" className="form-label">Name</label> <input type="text" className="form-control" id="exampleInputName" value={formik.values.name} onChange={formik.handleChange} name="name" /> </div> <div className="mb-3"> <label htmlFor="exampleInputPassword1" className="form-label">Password</label> <input type="password" className="form-control" id="exampleInputPassword1" value={formik.values.password} onChange={formik.handleChange} name="password" /> </div> <div className="mb-3"> <label htmlFor="exampleInputPassword2" className="form-label">Confirm Password</label> <input type="password" className="form-control" id="exampleInputPassword2" value={formik.values.cpassword} onChange={formik.handleChange} name="cpassword" /> </div> <button type="submit" className="btn btn-primary">Submit</button> </form> </div> ); }; export default Register;
  3. تلك مشكلة أخرى في صيغة استعلام SQL الذي يتم تكوينه، وتكمن في طريقة تكوين الجملة WHERE في الاستعلام. جرب تعديل السطر التالي: cur.execute("SELECT * FROM employee WHERE " + self.se_by.get() + " like '%" + self.se_var.get() + "%'") إلى: cur.execute("SELECT * FROM employee WHERE {} LIKE '%{}%'".format(self.se_by.get(), self.se_var.get())) وذلك لاستخدام التنسيق النصي {} لتضمين قيم المتغيرات في الاستعلام مما يساعد في تجنب أخطاء صيغة SQL ويجعل التعبير أكثر وضوحًا، وتأكد أيضًا من أن أسماء الأعمدة والجداول مكتوبة بشكل صحيح وتطابق قاعدة البيانات لديك.
  4. المشكلة هي استخدام دالة str() للتحويل إلى سلسلة نصية في الجزء التالي: str(self.se_by.get())+" like'% "+str(self.se_var.get())+"%'" ويفترض أن self.se_by.get() و self.se_var.get() تعيدان قيمة عددية أو سلسلة نصية، وإذا كانت تلك القيم تعود بالفعل كسلاسل نصية، فلن تحتاج إلى استخدام str() مرة أخرى. لذا، عليك بتعديل السطر التالي: cur.execute("SELECT * FROM employee WHERE " + str(self.se_by.get()) + " like '% " + str(self.se_var.get()) + "%'") إلى: cur.execute("SELECT * FROM employee WHERE " + self.se_by.get() + " like '%" + self.se_var.get() + "%'") وبالتالي لن يتم تحويل القيم إلى سلاسل نصية مرتين، ويتم تكوين استعلام SQL بشكل صحيح.
  5. كل من WebRTC و Amazon Kinesis Video Streams هي خيارات جيدة، ولكن تقنية WebRTC هي تقنية مجانية ومفتوحة المصدر تسمح بالاتصال في الوقت الحقيقي بين جهازين أو أكثر، وقابلة للتوسع بشكل كبير، لكن يمكن أن تكون معقدة في إعدادها وصيانتها. بالمقابل، Amazon Kinesis Video Streams هي خدمة تديرها Amazon تجعل من السهل بث وتخزين بيانات الفيديو، أيضًا قابلة للتوسع، لكنها قد تكون أكثر تكلفة من WebRTC تبعًا لطريقة الإعداد والاستخدام. تعتمد تكلفة Amazon Kinesis Video Streams على كمية البيانات التي ستسخدمها، وكما ذكرت أنت التكلفة لـ 1000 طالب، تترواح ما بين 100 إلى 200 دولار في الشهر، وقد تزيد التكلفة إذا تم تدفق المزيد من البيانات أو إذا كنت بحاجة إلى تخزين البيانات لفترات أطول. وفيما يلي بعض العوامل التي يجب مراعاتها عند اختيار بين WebRTC و Amazon Kinesis Video Streams: التوسع كلا من WebRTC و Amazon Kinesis Video Streams قابلة للتوسع، لكن WebRTC يمكن أن تكون أكثر صعوبة في التوسع لعدد كبير من المستخدمين. التكلفة Amazon Kinesis Video Streams أكثر تكلفة من WebRTC، لكنها أيضًا أسهل في الإعداد والصيانة. الميزات WebRTC يوفر مجموعة أوسع من الميزات من Amazon Kinesis Video Streams، مثل إمكانية مشاركة الشاشة واستخدام اتصالات ند لند. وفي حال كنت قلقًا بشأن قابلية التوسع والتكلفة، فإن Amazon Kinesis Video Streams خيار جيد، وبالرغم من ذلك، إذا كنت بحاجة إلى مجموعة أوسع من الميزات، فعليك بالنظر إلى استخدام WebRTC. وإليك بعضالحلول البديلة الأخرى التي قد ترغب بأخذها في الإعتبار: Zoom Google Meet Microsoft Teams
  6. أولاً عليك بنشاء ملف تحكم (Controller) أو ملف خدمة (Service) في مجلد pages/api بمشروع Next.js واسمه يمكن أن يكون likes.ts. ثم كتابة دالتين للطلبات POST واحدة لإضافة الـ "like" والأخرى لإزالته، وإليك المثال التالي لملف likes.ts: import { NextApiRequest, NextApiResponse } from 'next'; export default function handler(req: NextApiRequest, res: NextApiResponse) { if (req.method === 'POST') { const { like } = req.body; if (like) { // إضافة "like" بناءً على قيمة `like` // انفذ الكود الخاص بإضافة "like" هنا res.status(200).json({ message: 'تمت إضافة الـ "like" بنجاح' }); } else { // إزالة "like" بناءً على قيمة `like` // انفذ الكود الخاص بإزالة "like" هنا res.status(200).json({ message: 'تمت إزالة الـ "like" بنجاح' }); } } else { res.status(405).json({ message: 'الطلب غير مدعوم' }); } } وفي صفحتك التي تحتوي على زر الـ "like"، قم بإضافة حالة لتتبع حالة الـ "like" وإجراء طلب POST بناءً على الحالة. مثال: import { useState } from 'react'; export default function LikeButton() { const [liked, setLiked] = useState(false); const handleLike = () => { fetch('/api/likes', { method: 'POST', body: JSON.stringify({ like: !liked }), headers: { 'Content-Type': 'application/json', }, }) .then((response) => response.json()) .then((data) => { console.log(data.message); setLiked(!liked); }) .catch((error) => { console.error('حدث خطأ:', error); }); }; return ( <button onClick={handleLike}> {liked ? 'إزالة الـ "like"' : 'إضافة الـ "like"'} </button> ); } ثم تحديث ملفات الطرق (routes) في مشروع Next.js (مثل pages/index.tsx) لتضمين الزر الخاص بالـ "like" في الصفحة: import LikeButton from '../components/LikeButton'; export default function HomePage() { return ( <div> <h1>صفحة الموقع</h1> <LikeButton /> </div> ); }
  7. بإمكانك الإعتماد على الدوال المتوفرة في لغة PHP للاتصال بقاعدة البيانات واستعلامها وإليك مثال بسيط يستخدم لغة PHP وMySQL: <?php // اتصال بقاعدة البيانات $servername = "اسم_خادم_قاعدة_البيانات"; $username = "اسم_مستخدم_قاعدة_البيانات"; $password = "كلمة_مرور_قاعدة_البيانات"; $dbname = "اسم_قاعدة_البيانات"; $conn = new mysqli($servername, $username, $password, $dbname); // التحقق من اتصال قاعدة البيانات if ($conn->connect_error) { die("فشل الاتصال بقاعدة البيانات: " . $conn->connect_error); } // إدراج السجل في قاعدة البيانات $sql = "INSERT INTO اسم_الجدول (حقل1, حقل2, حقل3) VALUES ('قيمة1', 'قيمة2', 'قيمة3')"; if ($conn->query($sql) === TRUE) { // الاستعلام الناجح // استعراض آخر معرف ID تم إدراجه $last_inserted_id = $conn->insert_id; echo "تم إدراج السجل بنجاح. العنصر الأخير المُدرَج له ID: " . $last_inserted_id; } else { echo "خطأ في الإدراج: " . $conn->error; } // إغلاق اتصال قاعدة البيانات $conn->close(); ?> قمت بإنشاء اتصال بقاعدة البيانات، ثم يتم إجراء استعلام INSERT لإدراج السجل في الجدول، وإذا تم الإدراج بنجاح، واستخدام الدالة $conn->insert_id لاستعراض آخر معرف ID تم إدراجه، ومن ثم عرضه في الصفحة. استبدلي "اسم_خادم_قاعدة_البيانات" و"اسم_مستخدم_قاعدة_البيانات" و"كلمة_مرور_قاعدة_البيانات" و"اسم_قاعدة_البيانات" بالقيم الصحيحة لخادم قاعدة البيانات الذي تستخدمه ومعلومات اعتماد الوصول لديك، وأيضًا استبدال "اسم_الجدول" و "حقل1" و "حقل2" و "حقل3" بالأسماء الصحيحة للجدول والحقول المراد إدراج البيانات فيها.
  8. سببه أنك تحاولين إضافة أو تحديث صف مرتبط بقيد أب (foreign key) ولكن القيد الأب غير موجود في الجدول المرجع (referenced table) أو عندما يتعارض العمل بتحديث القيد الأب مع قيد الابن (child key) المرتبط به ورسالة الخطأ تعني إلى أنه لا يمكنك إضافة أو تحديث صف في جدول doctor لأنه يتضمن قيد أب مرتبط بجدول employes والقيد الأب (user_id) المحدد غير موجود في جدول employes. وربما تكون قيمة user_id التي تحاولين إضافتها غير موجودة في جدول employes، أو تحاولين تحديث قيمة user_id التي تشير إلى قيد غير موجود في جدول employes. لذلك تحققي من وجود قيمة user_id في جدول employes المشار إليه في الخطأ، وتأكدي من أن القيد الأب المحدد موجود بالفعل في الجدول المرجع. وفي حال كانت القيمة موجودة في جدول employes، تحققي من نوع البيانات لحقل user_id في جدول doctor ومن أنه يتوافق مع نوع البيانات في حقل U_id في جدول employes، حيث يجب أن يكون نوع البيانات والطول والتنسيق متطابقين. أيضًا التأكد من أن لديك الصلاحيات الكافية لإضافة أو تحديث الصفوف في جدول doctor وجدول employes. وربما السبب هو أنه هناك تعارض في العلاقة بين الجدولين، فتحققي من القيود (constraints) الموجودة على العلاقة بين الجدولين وتأكد من أنها معرفة بشكل صحيح وتتوافق مع البيانات الموجودة.
  9. من الأفضل قراءة المستند الرسمي وتطبيق الشرح على مشروعك: https://vuejs.org/guide/reusability/custom-directives.html وأيضًا هناك دليل عن كيفية الإنتقال من vue 2 إلى vue 3 : https://v3-migration.vuejs.org
  10. هناك مشكلة تحدث عند إزالة العنصر من DOM، جرب تعديل الكود في ملف directives.js واستخدام الخاصية beforeUnmount بدلاً من unmounted في كود الـ custom directive. أي في ملف directives.js، قم بتعديل الكود ليصبح كالتالي: // directives.js import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) // global Custom Directive app.directive('globalexternal', { beforeUnmount: function (el) { el.placeholder = '' }, mounted: function (el) { el.placeholder = 'Global Custom Directive from external file' } }) console.log('Global Custom Directive from external file') export default app
  11. يجب تحويل قيمة الـ prompt إلى رقم حيث أن القيمة العائدة منه هي نص، وهناك أكثر من طريقة لفعل ذلك، الأولى هي بوضع علامة + بجانب prompt أي كالتالي: let x = +prompt('أدخل رقم من المصفوفة') وسيتم تحويل القيمة المدخلة إلى رقم. والطريقة الثانية هي باستخدام دالة parseInt كالتالي: let x = parseInt(prompt('أدخل رقم من المصفوفة')); والطريقة الثالثة هي باستخدام دالة Number وانتبه إلى أن حرف الـ N كبير لكونها constructor أي دالة بانية ولكننا نستخدمها كدالة هنا لتحويل النص إلى الرقم كالتالي: let x = Number(prompt('أدخل رقم من المصفوفة')); الكائن Number في JavaScript
  12. في Vue 3، هناك بعض التغييرات في استخدام custom directives مقارنةً بـ Vue 2، وتستطيع تحقيق ما تريده عن طريق التالي: في ملف directives.js، يجب تصدير الـ custom directive مباشرة بدون استخدام دالة glob()، وذلك لأنك ستقوم بتصدير الـ directive ذاتها، وليس دالة لتسجيل الـ directive: // directives.js import { createApp } from 'vue' import App from './App.vue' const app = createApp(App) // global Custom Directive app.directive('globalexternal', { mounted: function (el) { el.placeholder = 'Global Custom Directive from external file' } }) console.log('Global Custom Directive from external file') export default app وفي ملف main.js، قم بتصدير ما يتم استيراده من ملف directives.js ثم تشغيل التطبيق: // main.js import { createApp } from 'vue' import App from './App.vue' import directivesApp from './directives' const app = createApp(App) directivesApp.mount('#app') app.mount('#app') وفي ملف App.vue، قم بتطبيق الـ custom directive المستورد باستخدام v-globalexternal: <!-- App.vue --> <template> <input v-globalexternal style="width: 370px" /> </template> <script> export default { // ... } </script> ومن المفترض أن يعمل الـ custom directive بشكل صحيح في تطبيق Vue 3 لديك، وانتبه إلى أنه في Vue 3 لم يعد هناك حاجة لاستدعاء الـ custom directive في الملف main.js مثلما كان في Vue 2، بل تستطيع تسجيلها مباشرة في الملف directives.js. دروس ومقالات لإطار العمل Vue.js
  13. أولاً أنت لم تستخدم دالة isNaN بشكل صحيح وأيضًا لديك مشكلة أخرى هي عدم تحديث قيمة المتغير total بشكل صحيح. بالإضافة إلى أنك استخدمت علامة التنصيص العادية ' ' ونضع بداخلها نص فقط، أما إذا أردت استخدام متغير فأرجو منك استخدام Template literals أو قوالب النصوص وهي علامة التنصيص المائلة ` ` وتصل إليها من حرف ذ في الكيبورد لكن يجب أن تكون لوحة المفاتيح باللغة الإنجليزية وليس العربية، وإليك شرح لقوالب النصوص: قالب النص الحديث في JavaScript أرجو منك كتابة الكود كالتالي: let total = 0; while (true) { let value = +prompt('Enter a number'); if (value == 0) break; if (isNaN(value)) continue; total += value; } alert(`Your total number is: ${total}`); قمت بإصلاح استخدام دالة isNaN عن طريق إضافة قوسين بعد اسم الدالة وإضافة قيمة value. ثم تحديث المتغير total عندما يتم إدخال رقم صالح عن طريق إضافة القيمة value إليه. استخدام قالب النص بدلاً من علامة التنصيص العادية وسيتم سؤالك عن إدخال رقم بشكل لا نهائي لأننا وضعنا شرط true في while، وإذا ضغط على cancel أثناء إدخال الرقم سيتم عرض مجموع ما قمت بإدخاله سابقًا.
  14. بخصوص odoo ستجد ما تريده في المحتوى الأجنبي أرشح لك قناتي odoo mates و Odoo Discussions وأيضًا يوجد قائمة مفيدة باسم Odoo Website & E-Commerce في قناة Concept Solutions. أيضًا قناة odoo الرسمية بها شروحات مفيدة، ابحث مثلاً عن Build an ecommerce website with Odoo. أيضًا يوجد المستند الرسمي: https://www.odoo.com/documentation/16.0/developer/tutorials.html وتستطيع البحث في جوجل عن المزيد.
  15. هل تواجه مشكلة أو صعوبة في أمرًا ما، تستطيع طرح المشكلة ليتم مساعدتك. وبخصوص الأمور المالية أو تغيير الدورة أو الاسترجاع، فعليك بالتحديث إلى مركز المساعدة الخاص بأكاديمية حسوب من خلال الرابط التالي: https://support.academy.hsoub.com/conversations ثم أدخل البريد الخاص بحسابك الذي اشتركت من خلاله بالدورة، وسيصلك كود تفعيل على البريد أرجو منك إدخاله وستظهر لك نافذة المحادثة، اشرح بها ما تريد وسيتم الرد عليك خلال 24 إلى 48 ساعة حيث أنه في بعض الأحيان يوجد ضغط، ولا تقلق بشأن الرد.
  16. أولاً، يجب أن تقوم بتنصيب حزمة إعلانات المكافأة المناسبة من خلال ملف "pubspec.yaml" الخاص بتطبيقك بإضافة حزمة مثل firebase_admob أو admob_flutter وتثبيتها باستخدام أمر flutter pub get. ثانيًا، بعد تنصيب الحزمة، عليك أن تنشئ وتكوّن وحدة الإعلانات المكافأة في حسابك على منصة AdMob، حيث ستحتاج إلى استخدام معرف الوحدة الإعلانية الخاصة بالإعلانات المكافأة في تطبيقك. ثالثًا، قم بإنشاء عنصر واجهة المستخدم في تطبيقك حيث ترغب في عرض الإعلان المكافأة باستخدام واجهة المستخدم المخصصة لحزمة الإعلانات التي قمت بتنصيبها لإظهار الإعلان، وفي الغالب يكون هناك زر أو تفاعل مستخدم يمكنه استدعاء الإعلان المكافأة. أخيرًا، يجب أن تنشيء الإعلان المكافأة في تطبيقك بالإعتماد على وحدة الإعلانات المكافأة لتحديد الإعدادات المرتبطة بالإعلان، مثل الجوائز المحتملة ومدة الفيديو المطلوبة وما إلى ذلك. وتأكد من قراءة وثائق الحزمة التي استخدمتها والتعليمات المقدمة بواجهة برمجة التطبيقات (API) الخاصة بمزود الإعلانات الذي تستخدمه، وستحتاج أيضًا إلى اختبار التطبيق للتأكد من عرض الإعلانات بشكل صحيح والتأكد من أن كل شيء يعمل بشكل صحيح.
  17. في البداية يجب إنشاء اتصال بقاعدة البيانات باستخدام مكتبة PDO وتوفير معلومات الاتصال بقاعدة البيانات مثل اسم المستخدم وكلمة المرور واسم قاعدة البيانات ومضيف قاعدة البيانات. $servername = "اسم_الخادم"; $username = "اسم_المستخدم"; $password = "كلمة_المرور"; $dbname = "اسم_قاعدة_البيانات"; try { $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password); $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); echo "تم الاتصال بنجاح"; } catch(PDOException $e) { echo "فشل الاتصال: " . $e->getMessage(); } ثم تحديد الجداول التي تحتاج إلى إجراء الإضافة إليها، ولنفترض وجود جدولين: "users" و "doctors". ثم استعادة البيانات التي ترغبين في إضافتها إلى جداول المستخدمين والأطباء باستخدام المتغيرات لتخزين القيم المستلمة من الصفحة الخاصة بالمشرف كالتالي: $username = $_POST['اسم_المستخدم']; $password = $_POST['كلمة_المرور']; $role = $_POST['الدور']; الآن لنجري عملية الإدخال في كل جدول بالإعتماد على الاستعلامات المعدة مسبقًا (Prepared Statements) لتأمين قاعدة البيانات من هجمات SQL Injection وتسهيل عملية الإدخال. try { // إضافة إلى جدول المستخدمين $stmt = $conn->prepare("INSERT INTO users (username, password) VALUES (:username, :password)"); $stmt->bindParam(':username', $username); $stmt->bindParam(':password', $password); $stmt->execute(); // إضافة إلى جدول الأطباء إذا كان الدور طبيبًا if ($role == 'طبيب') { $stmt = $conn->prepare("INSERT INTO doctors (username) VALUES (:username)"); $stmt->bindParam(':username', $username); $stmt->execute(); } echo "تمت الإضافة بنجاح"; } catch(PDOException $e) { echo "حدث خطأ أثناء الإضافة: " . $e->getMessage(); } ولا تنسي إغلاق الإتصال بقاعدة البيانات بعد الانتهاء من العمليات. $conn = null; // إغلاق الاتصال بقاعدة البيانات
  18. إذا أردت نصيحتي، فعليك بدورة تطوير التطبيقات باستخدام جافاسكريبت، حيث يتم فيها التركيز على تعلم لغة جافاسكريبت بشكل كبير وأيضًا ستتعلم الإطارات والمكتبات الخاصة باللغة وإمكانية تعلم تطوير المواقع وتطبيقات الهاتف المحمول وبرامج سطح المكتب. وذلك لن يتوفر لك في دورة تطوير واجهات المستخدم، والتي بالمناسبة تستطيع دراسة المسار الأول منها والذي يشرح أساسيات HTML, CSS,JS وjQuery ثم التطبيق وبناء موقع شخصي، وبذلك تكون قد جمعت بين الأمرين، وتستطيع الاستزادة أيضًا من مصادر أخرى على جوجل ويوتيوب.
  19. السؤال من المفترض أن يكون عن الفرق بين px و remو em وسأشرح لك الفرق بينهم والاستخدام المناسب لكل منهم. px (بكسل) px هي وحدة قياس ثابتة تعتمد على دقة الشاشة. تحدد قيمة بكسل حجم العنصر بنسبة مباشرة لعدد البكسلات المستخدمة. استخدام px مناسب في حالة رغبتك في تحديد حجم محدد وثابت للعنصر بشكل دقيق، مثل تحديد عرض صورة محدد بعرض محدد. rem (جذر النسبة المئوية) rem هي وحدة قياس تعتمد على حجم الجسم (root)، أي حجم الخط المعرف على العنصر الجذري (html) في الصفحة. تسمح وحدة rem بتعيين حجم العناصر بنسبة مئوية من الحجم الجذري أي حجم الخط في الجذر root وهو عنصر <html> الحاوي لكل الصفحة وحجم الخط الإفتراضي للصفحة هو 16px. واستخدام rem مناسب عندما ترغب في تطبيق تغييرات الحجم بنسبة مئوية واحدة على جميع العناصر داخل الصفحة، مما يتيح تحقيق تكيف جيد للشاشات المختلفة. ومن الأفضل استخدام rem من أجل تحقيق تجاوب للصفحة على الشاشات المختلفة وتجنب استخدام px إلا في حالات محددة. em em هي وحدة قياس تعتمد على حجم العنصر الذي يحتوي عليه النص. تحدد وحدة em حجم العنصر بنسبة مئوية من حجم النص الحالي للعنصر الأب وليس الجذر. استخدام em مناسب عندما ترغب في تعيين حجم العناصر بنسبة مئوية من حجم النص المحيط به، مما يسمح بتكيف أحجام العناصر بناءًا على حجم النص المستخدم فيها. وستجد هنا المزيد من الشرح: وحدات الأحجام للخطوط في تصميم الويب (PX مقابل EM و REM) شرح rem وem من موسوعة حسوب https://wiki.hsoub.com/CSS/length
  20. الأمر بسيط عليك بفصل النص عن الصورة بتضمين النص داخل عنصر مثل span ثم تنسيقه على أنه block من أجل أن يأتي على سطر منفصل وليس بجانب الصورة وقمت بتحسين أيضًا بتحسين الكود وإضافة أيقونات من خلال مكتبة font-awesome وإليك الكود النهائي بعد التعديل: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Books selling</title> <link rel="stylesheet" href="Book store.css"> <link rel="stylesheet" href="css/all.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer" /> </head> <body> <div class="parent"> <div class="header"> <p><i class="fa-solid fa-phone"></i> call us</p> <p><i class="fa-solid fa-house"></i> home</p> <p><i class="fa-solid fa-magnifying-glass"></i> search</p> </div> <div class="main-content"> <P><img src="https://placehold.co/200x200" alt="" class="img-box"><br><span>العلوم</span></P> <P><img src="https://placehold.co/200x200" alt="" class="img-box"><br><span>الدراسات</span></P> <P><img src="https://placehold.co/200x200" alt="" class="img-box"><br><span>اللغة العربية</span></P> </div> <div class="footer"> <p>thank you</p> </div> </div> </body> </html> CSS .parent { width: 100%; display: grid; grid-template-columns: repeat(3, 1fr); grid-template-rows: repeat(7, 150px); gap: 10px; background: yellow; grid-template-areas: "head head head" "content content content" "content content content" "content content content" "content content content" "content content content" "content content content" "content content content" "foot foot foot"; } .parent div { background: violet; } .header { grid-area: head; background: blue; display: flex; padding-left: 15px; gap: 15px; } .main-content { grid-area: content; background: red; padding-left: 15px; display: flex; flex-wrap: wrap; gap: 10px; } .main-content p { display: flex; flex-direction: column; align-items: center; } .main-content img { margin-bottom: 10px; } .footer { grid-area: foot; background: green; }
  21. ما المشكلة أو السؤال؟ أرجو توضيح المطلوب تنفيذه أو المشكلة التي تواجهيها.
  22. هل السؤال متعلق بأحد الدورات؟ أرجو منك التعليق أسفل فيديو الدورة من أجل مساعدتك بشكل أفضل. وطرح الأسئلة العامة هنا في قسم أسئلة البرمجة. وعامًة undefined تعني أن المتغير لم يتم تعيين قيمة له بعد، وعندما يتم إنشاء متغير دون تعيين قيمة له، فإن قيمته الافتراضية ستكون undefined. أيضًا عندما تستدعي دالة أو تقوم بإرجاع قيمة من دالة دون تعيين قيمة لها، فإن القيمة التي تعود بها الدالة ستكون undefined. وعند الوصول إلى خاصية غير موجودة في كائن، فإن القيمة التي ستحصل عليها ستكون undefined. مثال: let z; console.log(z); // النتيجة ستكون undefined وقد يختلط الأمر عليك بين undefined وnull. وnull تعني أن المتغير قد تم تعيينه بقيمة فارغة أو أنه لا يشير إلى أي شيء وتستخدم null في الغالب عندما نود إعطاء متغير قيمة فارغة أو إزالة القيمة الحالية الموجودة في المتغير. وفي حالة استدعاء دالة وتحتاج إلى تمرير وسيطة (argument) لا تحمل أي قيمة، تستطيع تعيين قيمة null لتلك الوسيطة. مثال: let y = null; console.log(y); // النتيجة ستكون null أي أن الفرق بينهما يكمن في الاستخدام الدلالي.، حيث أن الـ undefined hستخدم عندما لا تتوفر قيمة معينة، بينما الـ null يُستخدم عندما تكون هناك حاجة لتعيين قيمة فارغة أو إزالة القيمة الحالية لمتغير معين.
  23. أرجو منك وضع الأسئلة الخاصة بالدورات أسفل الفيديو الخاص بالسؤال ليتم مساعدتك بشكل أفضل، ستجد تعليقات أسفل الفيديو، وطرح الأسئلة العامة هنا في قسم أسئلة البرمجة. والمشكلة لديك أنك استخدمت نسخة bootstrap-grid.rtl.min.css بدلاً من bootstrap.rtl.min.css. وفي حال استخدام النسخة الصحيحة من bootstrap ستعمل الأصناف لديك بدون مشكلة. حيث أن ملف bootstrap.rtl.min.css هو ملف الأساس لإطار عمل Bootstrap ويحتوي على مجموعة شاملة من التنسيقات والأنماط للعناصر المختلفة في صفحة الويب، ويتضمن نظام الشبكة الأساسي (grid system) الخاص بـ Bootstrap، الذي يستخدم نمط الشبكة الأساسي المبني على نظام العواميد (columns) والصفوف (rows) لتنظيم العناصر في صفحة الويب بشكل سهل ومرن. أما ملف bootstrap-grid.rtl.min.css، فهو ملف اختياري يتضمن فقط نظام الشبكة في Bootstrap دون التنسيقات الأخرى، وإذا كنت تريد استخدام نظام الشبكة فقط من Bootstrap دون إضافة أي تنسيقات أخرى، فاستخدام هذا الملف.
  24. حاول تحديث ملف روابط التنصل الخاص بك، ثم إنتظار فترة تتراوح ما بين أسبوع إلى شهر، ولكن لا مشكلة إذا لم يتم إزالة تلك الروابط، فجوجل لن تقوم بأخذ تلك الروابط في الحسبان عند تقييم موقعك. وستجد أن كل فترة هناك ورابط عديمة القيمة تأتي إلى موقعك، فعليك بالتنصل منها وإبقاء المفيد منها فقط، وأيضًا عليك بمحاربة ذلك ببناء محتوى طويل ومفيد للزائرين وليس محتوى ضعيف وقصير، خاصًة في حال عدم وجود روابط قوية لموقعك، وأيضًا الإشارة في المقالات لديك لمواقع خارجية ذات سلطة وتقييم عالي حيث أن المواقع المشبوهة لا تشير إلى تلك الموقع، وبالتالي ستتحسن نظرة جوجل لموقعك، وأيضًا لكي يتم ربط نشاط موقعك بنشاط تلك الموقع القوية والمؤثرة في مجال موقعك مثل مجال التقنية مثلاً. أي يجب توفير رابط واحد يشير إلى موقع خارجي مثل Microsoft أو أي رابط قوي آخر تستشهد به في مقالك. ومجال موقعك هو مجال خدمي، أي ستجد منافسة كبيرة به لذلك يجب تعيين شخص متخصص لتحسين الـ SEO لموقعك وبناء روابط.
  25. لا تشتت نفسك الآن، اعرف فقط ما عليك تعلمه أي ضع مسار تعليمي لك والتزم به لفترة 6 أشهر على الأقل، والطبع ستحتاج إلى تعلم إطار او مكتبة للواجهة الأمامية من أجل تصبح مطور واجهات أمامية محترف وتجد فرصة وظيفة في سوق العمل. لكن قبل تعلم React أو Angular عليك بإلقاء نظرة على الوظائف في بلدك، هل يوجد فرص لمطوري React بمستوى Entry Level أو Junior فإذا لم تجد ابحث عن وظائف Angular وفي الغالب ستجد أنه يوجد فرص لـ Angular أكثر من React بالنسبة للمبتدئين لكون React تتطلب خبرة أكثر من Angular حيث أن Angular بها قيود وقواعد عن كيفية تنفيذ المشاريع لكونه إطار عمل، بينما React هي مكتبة وتسطيع تنفيذ المشاريع بأكثر من طريقة ويجب تعلم كيفية الربط واستخدام المكتبات الأخرى بجانب React. ولكي تجد فرص كمطور React، عليك ببناء مشاريع كاملة متوسطة الحجم، أي أكثر من مشروع وليس فقط الإكتفاء بالمشاريع التي يتم توفيرها في الدورات مثل دورة تطوير التطبيقات باستخدام لغة JavaScript في أكاديمية حسوب، والتي يوجد بها أكثر من مشروع لوضعه في معرض أعمالك، لكن يجب تنفيذ المزيد وبأفكار مختلفة وبذلك تصبح بمستوى Junior وليس Entry Level. حيث أن Entry Level تعني شخص يعلم الأساسيات ويستطيع كتابة الكود لكن ليس لديه خبرة بكيفية تنفيذ المشاريع، أي لديه عند إنتهائك من مسار تعليمي أنت بذلك تصبح Entry Level. بينما بعد فترة 6 أشهر أخرى مثلاً ونفذت خلالها مشاريع أنت الآن في مستوى Junior لكن بشرط الإجتهاد خلال تلك الفترة فمن المفترض أن Junior تعني خبرة سنة لكن تستطيع الإجتهاد والحصول على خبرة خلال 6 أشهر سواء بتنفيذ المشاريع بمفردك أو العمل الحر، وهناك أمر هام وهو أن فترة دراستك لمسار تعليمي وهي 6 أشهر لا تعتبر خبرة فالبعض يخطيء في ذلك، بل ما بعدها هي مرحلة اكتساب الخبرة من خلال تنفيذ المشاريع والتعلم من الأخطاء وتعلم تقنيات جديدة والتعمق في اللغات والتقنيات التي تستخدمها من خلال المشاريع.
×
×
  • أضف...